From c9939dac9fe185049b52d3092a195f7c4c6cf759 Mon Sep 17 00:00:00 2001 From: Efemena Arah Date: Wed, 29 Jul 2026 13:22:34 +0100 Subject: [PATCH] Initial commit of migrated source code --- .editorconfig | 13 + .eslintrc.json | 44 + .github/actions/secret-scanner/action.yml | 67 + .../gitleaks-custom-rules-template.toml | 35 + .github/workflows/secret-scanning.yml | 24 + .gitignore | 49 + .prettierrc | 9 + .scripts/version.js | 46 + README.md | 28 +- angular.json | 155 + azure-pipelines.yaml | 53 +- jest.config.js | 17 + package-lock.json | 25102 ++++++++++++++++ package.json | 97 + projects/core/.eslintrc.json | 35 + projects/core/ng-package.json | 7 + projects/core/package.json | 14 + .../__tests__/capabilities.spec.ts | 318 + projects/core/src/capabilities/directives.ts | 43 + projects/core/src/capabilities/guards.ts | 19 + projects/core/src/capabilities/providers.ts | 11 + projects/core/src/capabilities/service.ts | 81 + .../__snapshots__/cookies.spec.ts.snap | 13 + .../src/cookies/__tests__/cookies.spec.ts | 125 + projects/core/src/cookies/cookies.service.ts | 117 + .../core/src/cookies/dynatrace/dtrum.mock.ts | 18 + .../cookies/dynatrace/dynatrace.interfaces.ts | 23 + .../cookies/dynatrace/dynatrace.service.ts | 75 + projects/core/src/cookies/providers.ts | 20 + projects/core/src/fake-session/interceptor.ts | 37 + projects/core/src/fake-session/providers.ts | 46 + projects/core/src/fake-session/service.ts | 44 + projects/core/src/http/__tests__/http.spec.ts | 535 + projects/core/src/http/dispatcher.ts | 90 + projects/core/src/http/http-backend.ts | 76 + projects/core/src/http/http-service.ts | 116 + projects/core/src/http/providers.ts | 83 + projects/core/src/http/util.ts | 43 + projects/core/src/index.ts | 1 + projects/core/src/public_api.ts | 19 + .../src/rxjs/__tests__/repeatUntil.spec.ts | 81 + projects/core/src/rxjs/repeatUntil.ts | 29 + projects/core/src/utils.ts | 19 + projects/core/tsconfig.lib.json | 27 + projects/core/tsconfig.lib.prod.json | 9 + projects/core/tsconfig.spec.json | 9 + projects/reference-data/.eslintrc.json | 37 + projects/reference-data/ng-package.json | 7 + projects/reference-data/package.json | 19 + projects/reference-data/src/actions/index.ts | 3 + .../src/actions/reference-data.actions.ts | 304 + ...n-type-standalone.autosuggest.spec.ts.snap | 41 + .../application-type.autosuggest.spec.ts.snap | 45 + .../assign-priority.select.spec.ts.snap | 22 + .../booking-type.select.spec.ts.snap | 22 + .../cluster.autosuggest.spec.ts.snap | 43 + .../cps-business-unit.select.spec.ts.snap | 73 + .../police-ranks.select.spec.ts.snap | 22 + .../witness-care-unit.select.spec.ts.snap | 69 + ...cation-type-standalone.autosuggest.spec.ts | 123 + .../application-type.autosuggest.spec.ts | 136 + .../__tests__/assign-priority.select.spec.ts | 117 + .../__tests__/booking-type.select.spec.ts | 118 + .../__tests__/cluster.autosuggest.spec.ts | 139 + .../cps-business-unit.select.spec.ts | 154 + .../__tests__/police-ranks.select.spec.ts | 116 + .../witness-care-unit.select.spec.ts | 146 + ...application-type-standalone.autosuggest.ts | 128 + .../application-type.autosuggest.ts | 194 + .../src/components/assign-priority.select.ts | 139 + .../src/components/booking-type.select.ts | 137 + .../src/components/cluster.autosuggest.ts | 156 + .../src/components/cps-area.select.ts | 138 + .../components/cps-business-unit.select.ts | 151 + .../src/components/cps-case-status.select.ts | 140 + .../src/components/fixed-list.autosuggest.ts | 171 + .../components/hearing-type.autosuggest.ts | 156 + .../src/components/hearing-type.select.ts | 138 + .../reference-data/src/components/index.ts | 63 + .../organisation-unit.autosuggest.ts | 180 + .../organisation-with-type.autosuggest.ts | 195 + .../components/police-force.autosuggest.ts | 156 + .../src/components/police-ranks.select.ts | 138 + .../src/components/prosecutor.autosuggest.ts | 173 + .../components/rota-business-types.select.ts | 161 + .../special-requirements.checkbox.ts | 142 + .../components/witness-care-unit.select.ts | 152 + .../__tests__/reference-data.effects.spec.ts | 1413 + .../src/effects/reference-data.effects.ts | 324 + .../__tests__/application-type.guard.spec.ts | 101 + .../__tests__/assign-priorities.guard.spec.ts | 101 + .../__tests__/booking-types.guard.spec.ts | 101 + .../guards/__tests__/clusters.guard.spec.ts | 101 + .../__tests__/court-centre-units.gard.spec.ts | 122 + .../__tests__/court-centres.guard.spec.ts | 102 + .../guards/__tests__/cps-areas.guard.spec.ts | 101 + .../cps-business-units.guard.spec.ts | 101 + .../__tests__/cps-case-status.guard.spec.ts | 101 + .../__tests__/hearing-type.guard.spec.ts | 101 + .../__tests__/judiciary-group-types.spec.ts | 103 + .../local-justice-areas.guard.spec.ts | 101 + .../organisation-with-type.guard.spec.ts | 124 + .../guards/__tests__/plea-types.guard.spec.ts | 101 + .../__tests__/police-force.guard.spec.ts | 101 + .../__tests__/police-ranks.guard.spec.ts | 99 + .../__tests__/prosecutors.guard.spec.ts | 101 + .../__tests__/public-holidays.guard.spec.ts | 102 + .../rota-business-types.guard.spec.ts | 101 + .../special-requirements.guard.spec.ts | 103 + .../__tests__/trial-types.guard.spec.ts | 101 + .../__tests__/witness-care-unit.guard.spec.ts | 101 + .../src/guards/application-type.guard.ts | 51 + .../src/guards/assingn-priorities.guard.ts | 51 + .../src/guards/booking-types.guard.ts | 51 + .../src/guards/clusters.guard.ts | 51 + .../src/guards/court-centre-units.gard.ts | 52 + .../src/guards/court-centres.guard.ts | 56 + .../src/guards/cps-areas.guard.ts | 51 + .../src/guards/cps-business-units.guard.ts | 51 + .../src/guards/cps-case-status.guard.ts | 51 + .../src/guards/fixed-lists.guard.ts | 51 + .../src/guards/hearing-type.guard.ts | 51 + .../src/guards/judiciary-group-types.guard.ts | 53 + .../src/guards/local-justice-areas.guard.ts | 53 + .../guards/organisation-with-type.guard.ts | 62 + .../src/guards/plea-types.guard.ts | 51 + .../src/guards/police-force.guard.ts | 51 + .../src/guards/police-ranks.guard.ts | 51 + .../src/guards/prosecutors.guard.ts | 51 + .../src/guards/public-holidays.guard.ts | 51 + .../src/guards/rota-business-types.guard.ts | 53 + .../src/guards/special-requirement.guard.ts | 53 + .../src/guards/trial-types.guard.ts | 51 + .../src/guards/witness-care-unit.guard.ts | 51 + .../src/helpers/judiciary-type.helper.ts | 193 + projects/reference-data/src/index.ts | 1 + .../src/mocks/application-type.mocks.ts | 53 + .../src/mocks/hearing-type.mocks.ts | 34 + .../src/mocks/organisation-unit.mocks.ts | 13 + .../src/mocks/prosecutor.mocks.ts | 19 + projects/reference-data/src/providers.ts | 62 + projects/reference-data/src/public_api.ts | 40 + .../__snapshots__/index.reducer.spec.ts.snap | 590 + .../reducers/__tests__/index.reducer.spec.ts | 1176 + projects/reference-data/src/reducers/index.ts | 144 + .../src/reducers/reference-data.reducer.ts | 514 + .../src/reference-data.interfaces.ts | 573 + .../src/reference-data.module.ts | 128 + .../__tests__/reference-data.service.spec.ts | 406 + .../src/services/reference-data.service.ts | 336 + .../judicial-member-name.pipe.spec.ts | 53 + .../src/utils/__tests__/mapper.spec.ts | 98 + .../sort-select-options-Alphabetical.spec.ts | 27 + .../src/utils/judicial-member-name.pipe.ts | 45 + projects/reference-data/src/utils/mapper.ts | 68 + .../utils/sort-select-options-Alphabetical.ts | 20 + projects/reference-data/tsconfig.lib.json | 32 + .../reference-data/tsconfig.lib.prod.json | 9 + projects/reference-data/tsconfig.spec.json | 10 + projects/scheduling/.eslintrc.json | 23 + projects/scheduling/ng-package.json | 7 + projects/scheduling/package.json | 16 + projects/scheduling/src/actions/index.ts | 4 + .../src/actions/listing-notes.actions.ts | 45 + .../src/actions/listing-notes.spec.ts | 102 + .../src/actions/scheduling.actions.spec.ts | 39 + .../src/actions/scheduling.actions.ts | 13 + .../estimate-input/estimate-input.html | 79 + .../estimate-input/estimate-input.scss | 12 + .../estimate-input/estimate-input.spec.ts | 552 + .../estimate-input/estimate-input.ts | 344 + .../hearing-slots-row.component.spec.ts.snap | 101 + .../hearing-slots-row.component.html | 144 + .../hearing-slots-row.component.scss | 32 + .../hearing-slots-row.component.spec.ts | 88 + .../hearing-slots-row.component.ts | 65 + ...hearing-slots-table.component.spec.ts.snap | 356 + .../hearing-slots-table.component.html | 32 + .../hearing-slots-table.component.spec.ts | 64 + .../hearing-slots-table.component.ts | 29 + ...g-note-confirmation.component.spec.ts.snap | 49 + .../listing-note.component.spec.ts.snap | 250 + .../listing-note.container.spec.ts.snap | 232 + ...isting-note-confirmation.component.spec.ts | 44 + .../__tests__/listing-note.component.spec.ts | 99 + .../__tests__/listing-note.container.spec.ts | 186 + ...ete-listing-note-confirmation.component.ts | 57 + .../listing-notes/listing-note.component.html | 100 + .../listing-notes/listing-note.component.scss | 47 + .../listing-notes/listing-note.component.ts | 94 + .../listing-notes/listing-note.container.ts | 144 + .../scheduling-filters.component.spec.ts.snap | 831 + .../scheduling-filters.component.html | 230 + .../scheduling-filters.component.scss | 24 + .../scheduling-filters.component.spec.ts | 183 + .../scheduling-filters.component.ts | 203 + .../scheduling-slots.component.spec.ts.snap | 25 + .../scheduling-slots.component.html | 97 + .../scheduling-slots.component.spec.ts | 292 + .../scheduling-slots.component.ts | 203 + projects/scheduling/src/index.ts | 1 + .../businessTypeDescription.pipe.spec.ts | 30 + .../src/pipes/__tests__/duration.pipe.spec.ts | 37 + .../src/pipes/businessTypeDescription.pipe.ts | 13 + .../scheduling/src/pipes/duration.pipe.ts | 24 + projects/scheduling/src/providers.ts | 18 + projects/scheduling/src/public-api.ts | 34 + .../__snapshots__/scheduling.spec.ts.snap | 15 + projects/scheduling/src/reducers/index.ts | 10 + .../src/reducers/listing-notes.spec.ts | 71 + .../src/reducers/scheduling.spec.ts | 119 + .../scheduling/src/reducers/scheduling.ts | 89 + projects/scheduling/src/scheduling.module.ts | 51 + projects/scheduling/src/selectors/index.ts | 4 + .../src/selectors/listing-notes.spec.ts | 121 + .../scheduling/src/selectors/listing-notes.ts | 31 + .../src/selectors/scheduling.spec.ts | 124 + .../scheduling/src/selectors/scheduling.ts | 20 + .../services/listing-notes.service.spec.ts | 85 + .../src/services/listing-notes.service.ts | 50 + .../src/services/scheduling.service.spec.ts | 68 + .../src/services/scheduling.service.ts | 62 + projects/scheduling/src/types/allocation.ts | 13 + projects/scheduling/src/types/filters.ts | 17 + projects/scheduling/src/types/hearingSlot.ts | 84 + projects/scheduling/src/types/index.ts | 4 + projects/scheduling/src/types/listingNotes.ts | 11 + .../src/utils/__tests__/courtroom.spec.ts | 27 + .../utils/__tests__/hearingSlotTime.spec.ts | 172 + .../utils/__tests__/operationalUnit.spec.ts | 27 + .../utils/__tests__/rotaBusinessType.spec.ts | 33 + projects/scheduling/src/utils/allocations.ts | 18 + projects/scheduling/src/utils/courtrooms.ts | 14 + .../scheduling/src/utils/hearingSlotTime.ts | 90 + projects/scheduling/src/utils/index.ts | 6 + .../scheduling/src/utils/operationalUnit.ts | 21 + .../scheduling/src/utils/rotaBusinessType.ts | 22 + .../scheduling/src/utils/sessionTimings.ts | 19 + projects/scheduling/tsconfig.lib.json | 25 + projects/scheduling/tsconfig.lib.prod.json | 10 + projects/scheduling/tsconfig.spec.json | 10 + projects/testing/package.json | 11 + projects/testing/src/index.ts | 1 + projects/testing/src/public_api.ts | 4 + projects/testing/src/resources/index.ts | 2 + .../src/resources/organisationUnits.ts | 43 + projects/testing/src/resources/users.ts | 244 + projects/testing/src/util/log.ts | 39 + projects/testing/src/util/pollUntil.ts | 34 + projects/testing/src/util/request.ts | 56 + projects/testing/src/util/urn.ts | 14 + projects/testing/tsconfig.json | 17 + projects/users-groups/.eslintrc.json | 38 + projects/users-groups/ng-package.json | 7 + projects/users-groups/package.json | 15 + projects/users-groups/src/actions/index.ts | 3 + .../src/actions/users-groups.actions.ts | 61 + .../__tests__/user-groups.effects.spec.ts | 104 + .../src/effects/user-groups.effects.ts | 37 + ...has-feature-enabled.directive.spec.ts.snap | 30 + ...user-has-feature-enabled.directive.spec.ts | 94 + .../cpp-user-has-feature-enabled.directive.ts | 86 + .../__tests__/user-details.guard.spec.ts | 135 + .../user-feature-exists.guard.spec.ts | 77 + .../__tests__/user-features.guard.spec.ts | 120 + ...ser-groups-with-organisation.guard.spec.ts | 115 + .../__tests__/user-groups.guard.spec.ts | 146 + .../user-organisations.guard.spec.ts | 104 + .../user-permissions-exist.guard.spec.ts | 78 + .../__tests__/user-permissions.guard.spec.ts | 220 + .../user-service-exists.guard.spec.ts | 83 + .../__tests__/user-services.guard.spec.ts | 119 + .../user-permissions-exist.guard.ts | 33 + .../permissions/user-permissions.guard.ts | 110 + .../src/guards/user-details.guard.ts | 65 + .../src/guards/user-feature-exist.guard.ts | 30 + .../src/guards/user-features.guard.ts | 63 + .../user-groups-with-organisation.guard.ts | 52 + .../src/guards/user-groups.guard.ts | 69 + .../src/guards/user-organisations.guard.ts | 48 + .../src/guards/user-roles.guard.ts | 65 + .../src/guards/user-service-exists.guard.ts | 30 + .../src/guards/user-services.guard.ts | 64 + projects/users-groups/src/index.ts | 1 + ...user-has-permission.directive.spec.ts.snap | 108 + .../cpp-user-has-permission.directive.spec.ts | 230 + .../cpp-user-has-permission.directive.ts | 109 + projects/users-groups/src/providers.ts | 36 + projects/users-groups/src/public_api.ts | 24 + .../__snapshots__/index.spec.ts.snap | 204 + .../src/reducers/__tests__/index.spec.ts | 360 + projects/users-groups/src/reducers/index.ts | 85 + .../src/reducers/users-groups.reducer.ts | 62 + .../system-announcements.service.spec.ts | 94 + .../__tests__/users-groups.service.spec.ts | 344 + .../services/system-announcements.service.ts | 23 + .../src/services/users-groups.service.ts | 173 + .../src/users-groups.interfaces.ts | 167 + .../users-groups/src/users-groups.module.ts | 64 + .../utils/__tests__/features-exist.spec.ts | 38 + .../utils/__tests__/permissions-exist.spec.ts | 144 + .../role-permissions-aggregator.spec.ts | 85 + .../users-groups/src/utils/features-exist.ts | 32 + projects/users-groups/src/utils/index.ts | 3 + .../src/utils/permissions-exist.ts | 49 + .../src/utils/role-permissions-aggregator.ts | 52 + projects/users-groups/tsconfig.lib.json | 30 + projects/users-groups/tsconfig.lib.prod.json | 9 + projects/users-groups/tsconfig.spec.json | 8 + sonar-project.properties | 24 + tsconfig.json | 26 + 311 files changed, 55105 insertions(+), 17 deletions(-) create mode 100644 .editorconfig create mode 100644 .eslintrc.json create mode 100644 .github/actions/secret-scanner/action.yml create mode 100644 .github/actions/secret-scanner/gitleaks-custom-rules-template.toml create mode 100644 .github/workflows/secret-scanning.yml create mode 100644 .gitignore create mode 100644 .prettierrc create mode 100644 .scripts/version.js create mode 100644 angular.json create mode 100644 jest.config.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 projects/core/.eslintrc.json create mode 100644 projects/core/ng-package.json create mode 100644 projects/core/package.json create mode 100644 projects/core/src/capabilities/__tests__/capabilities.spec.ts create mode 100644 projects/core/src/capabilities/directives.ts create mode 100644 projects/core/src/capabilities/guards.ts create mode 100644 projects/core/src/capabilities/providers.ts create mode 100644 projects/core/src/capabilities/service.ts create mode 100644 projects/core/src/cookies/__tests__/__snapshots__/cookies.spec.ts.snap create mode 100644 projects/core/src/cookies/__tests__/cookies.spec.ts create mode 100644 projects/core/src/cookies/cookies.service.ts create mode 100644 projects/core/src/cookies/dynatrace/dtrum.mock.ts create mode 100644 projects/core/src/cookies/dynatrace/dynatrace.interfaces.ts create mode 100644 projects/core/src/cookies/dynatrace/dynatrace.service.ts create mode 100644 projects/core/src/cookies/providers.ts create mode 100644 projects/core/src/fake-session/interceptor.ts create mode 100644 projects/core/src/fake-session/providers.ts create mode 100644 projects/core/src/fake-session/service.ts create mode 100644 projects/core/src/http/__tests__/http.spec.ts create mode 100644 projects/core/src/http/dispatcher.ts create mode 100644 projects/core/src/http/http-backend.ts create mode 100644 projects/core/src/http/http-service.ts create mode 100644 projects/core/src/http/providers.ts create mode 100644 projects/core/src/http/util.ts create mode 100644 projects/core/src/index.ts create mode 100644 projects/core/src/public_api.ts create mode 100644 projects/core/src/rxjs/__tests__/repeatUntil.spec.ts create mode 100644 projects/core/src/rxjs/repeatUntil.ts create mode 100644 projects/core/src/utils.ts create mode 100644 projects/core/tsconfig.lib.json create mode 100644 projects/core/tsconfig.lib.prod.json create mode 100644 projects/core/tsconfig.spec.json create mode 100644 projects/reference-data/.eslintrc.json create mode 100644 projects/reference-data/ng-package.json create mode 100644 projects/reference-data/package.json create mode 100644 projects/reference-data/src/actions/index.ts create mode 100644 projects/reference-data/src/actions/reference-data.actions.ts create mode 100644 projects/reference-data/src/components/__tests__/__snapshots__/application-type-standalone.autosuggest.spec.ts.snap create mode 100644 projects/reference-data/src/components/__tests__/__snapshots__/application-type.autosuggest.spec.ts.snap create mode 100644 projects/reference-data/src/components/__tests__/__snapshots__/assign-priority.select.spec.ts.snap create mode 100644 projects/reference-data/src/components/__tests__/__snapshots__/booking-type.select.spec.ts.snap create mode 100644 projects/reference-data/src/components/__tests__/__snapshots__/cluster.autosuggest.spec.ts.snap create mode 100644 projects/reference-data/src/components/__tests__/__snapshots__/cps-business-unit.select.spec.ts.snap create mode 100644 projects/reference-data/src/components/__tests__/__snapshots__/police-ranks.select.spec.ts.snap create mode 100644 projects/reference-data/src/components/__tests__/__snapshots__/witness-care-unit.select.spec.ts.snap create mode 100644 projects/reference-data/src/components/__tests__/application-type-standalone.autosuggest.spec.ts create mode 100644 projects/reference-data/src/components/__tests__/application-type.autosuggest.spec.ts create mode 100644 projects/reference-data/src/components/__tests__/assign-priority.select.spec.ts create mode 100644 projects/reference-data/src/components/__tests__/booking-type.select.spec.ts create mode 100644 projects/reference-data/src/components/__tests__/cluster.autosuggest.spec.ts create mode 100644 projects/reference-data/src/components/__tests__/cps-business-unit.select.spec.ts create mode 100644 projects/reference-data/src/components/__tests__/police-ranks.select.spec.ts create mode 100644 projects/reference-data/src/components/__tests__/witness-care-unit.select.spec.ts create mode 100644 projects/reference-data/src/components/application-type-standalone.autosuggest.ts create mode 100644 projects/reference-data/src/components/application-type.autosuggest.ts create mode 100644 projects/reference-data/src/components/assign-priority.select.ts create mode 100644 projects/reference-data/src/components/booking-type.select.ts create mode 100644 projects/reference-data/src/components/cluster.autosuggest.ts create mode 100644 projects/reference-data/src/components/cps-area.select.ts create mode 100644 projects/reference-data/src/components/cps-business-unit.select.ts create mode 100644 projects/reference-data/src/components/cps-case-status.select.ts create mode 100644 projects/reference-data/src/components/fixed-list.autosuggest.ts create mode 100644 projects/reference-data/src/components/hearing-type.autosuggest.ts create mode 100644 projects/reference-data/src/components/hearing-type.select.ts create mode 100644 projects/reference-data/src/components/index.ts create mode 100644 projects/reference-data/src/components/organisation-unit.autosuggest.ts create mode 100644 projects/reference-data/src/components/organisation-with-type.autosuggest.ts create mode 100644 projects/reference-data/src/components/police-force.autosuggest.ts create mode 100644 projects/reference-data/src/components/police-ranks.select.ts create mode 100644 projects/reference-data/src/components/prosecutor.autosuggest.ts create mode 100644 projects/reference-data/src/components/rota-business-types.select.ts create mode 100644 projects/reference-data/src/components/special-requirements.checkbox.ts create mode 100644 projects/reference-data/src/components/witness-care-unit.select.ts create mode 100644 projects/reference-data/src/effects/__tests__/reference-data.effects.spec.ts create mode 100644 projects/reference-data/src/effects/reference-data.effects.ts create mode 100644 projects/reference-data/src/guards/__tests__/application-type.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/assign-priorities.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/booking-types.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/clusters.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/court-centre-units.gard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/court-centres.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/cps-areas.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/cps-business-units.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/cps-case-status.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/hearing-type.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/judiciary-group-types.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/local-justice-areas.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/organisation-with-type.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/plea-types.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/police-force.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/police-ranks.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/prosecutors.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/public-holidays.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/rota-business-types.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/special-requirements.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/trial-types.guard.spec.ts create mode 100644 projects/reference-data/src/guards/__tests__/witness-care-unit.guard.spec.ts create mode 100644 projects/reference-data/src/guards/application-type.guard.ts create mode 100644 projects/reference-data/src/guards/assingn-priorities.guard.ts create mode 100644 projects/reference-data/src/guards/booking-types.guard.ts create mode 100644 projects/reference-data/src/guards/clusters.guard.ts create mode 100644 projects/reference-data/src/guards/court-centre-units.gard.ts create mode 100644 projects/reference-data/src/guards/court-centres.guard.ts create mode 100644 projects/reference-data/src/guards/cps-areas.guard.ts create mode 100644 projects/reference-data/src/guards/cps-business-units.guard.ts create mode 100644 projects/reference-data/src/guards/cps-case-status.guard.ts create mode 100644 projects/reference-data/src/guards/fixed-lists.guard.ts create mode 100644 projects/reference-data/src/guards/hearing-type.guard.ts create mode 100644 projects/reference-data/src/guards/judiciary-group-types.guard.ts create mode 100644 projects/reference-data/src/guards/local-justice-areas.guard.ts create mode 100644 projects/reference-data/src/guards/organisation-with-type.guard.ts create mode 100644 projects/reference-data/src/guards/plea-types.guard.ts create mode 100644 projects/reference-data/src/guards/police-force.guard.ts create mode 100644 projects/reference-data/src/guards/police-ranks.guard.ts create mode 100644 projects/reference-data/src/guards/prosecutors.guard.ts create mode 100644 projects/reference-data/src/guards/public-holidays.guard.ts create mode 100644 projects/reference-data/src/guards/rota-business-types.guard.ts create mode 100644 projects/reference-data/src/guards/special-requirement.guard.ts create mode 100644 projects/reference-data/src/guards/trial-types.guard.ts create mode 100644 projects/reference-data/src/guards/witness-care-unit.guard.ts create mode 100644 projects/reference-data/src/helpers/judiciary-type.helper.ts create mode 100644 projects/reference-data/src/index.ts create mode 100644 projects/reference-data/src/mocks/application-type.mocks.ts create mode 100644 projects/reference-data/src/mocks/hearing-type.mocks.ts create mode 100644 projects/reference-data/src/mocks/organisation-unit.mocks.ts create mode 100644 projects/reference-data/src/mocks/prosecutor.mocks.ts create mode 100644 projects/reference-data/src/providers.ts create mode 100644 projects/reference-data/src/public_api.ts create mode 100644 projects/reference-data/src/reducers/__tests__/__snapshots__/index.reducer.spec.ts.snap create mode 100644 projects/reference-data/src/reducers/__tests__/index.reducer.spec.ts create mode 100644 projects/reference-data/src/reducers/index.ts create mode 100644 projects/reference-data/src/reducers/reference-data.reducer.ts create mode 100644 projects/reference-data/src/reference-data.interfaces.ts create mode 100644 projects/reference-data/src/reference-data.module.ts create mode 100644 projects/reference-data/src/services/__tests__/reference-data.service.spec.ts create mode 100644 projects/reference-data/src/services/reference-data.service.ts create mode 100644 projects/reference-data/src/utils/__tests__/judicial-member-name.pipe.spec.ts create mode 100644 projects/reference-data/src/utils/__tests__/mapper.spec.ts create mode 100644 projects/reference-data/src/utils/__tests__/sort-select-options-Alphabetical.spec.ts create mode 100644 projects/reference-data/src/utils/judicial-member-name.pipe.ts create mode 100644 projects/reference-data/src/utils/mapper.ts create mode 100644 projects/reference-data/src/utils/sort-select-options-Alphabetical.ts create mode 100644 projects/reference-data/tsconfig.lib.json create mode 100644 projects/reference-data/tsconfig.lib.prod.json create mode 100644 projects/reference-data/tsconfig.spec.json create mode 100644 projects/scheduling/.eslintrc.json create mode 100644 projects/scheduling/ng-package.json create mode 100644 projects/scheduling/package.json create mode 100644 projects/scheduling/src/actions/index.ts create mode 100644 projects/scheduling/src/actions/listing-notes.actions.ts create mode 100644 projects/scheduling/src/actions/listing-notes.spec.ts create mode 100644 projects/scheduling/src/actions/scheduling.actions.spec.ts create mode 100644 projects/scheduling/src/actions/scheduling.actions.ts create mode 100644 projects/scheduling/src/components/estimate-input/estimate-input.html create mode 100644 projects/scheduling/src/components/estimate-input/estimate-input.scss create mode 100644 projects/scheduling/src/components/estimate-input/estimate-input.spec.ts create mode 100644 projects/scheduling/src/components/estimate-input/estimate-input.ts create mode 100644 projects/scheduling/src/components/hearing-slots-row/__snapshots__/hearing-slots-row.component.spec.ts.snap create mode 100644 projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.html create mode 100644 projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.scss create mode 100644 projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.spec.ts create mode 100644 projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.ts create mode 100644 projects/scheduling/src/components/hearing-slots-table/__snapshots__/hearing-slots-table.component.spec.ts.snap create mode 100644 projects/scheduling/src/components/hearing-slots-table/hearing-slots-table.component.html create mode 100644 projects/scheduling/src/components/hearing-slots-table/hearing-slots-table.component.spec.ts create mode 100644 projects/scheduling/src/components/hearing-slots-table/hearing-slots-table.component.ts create mode 100644 projects/scheduling/src/components/listing-notes/__tests__/__snapshots__/delete-listing-note-confirmation.component.spec.ts.snap create mode 100644 projects/scheduling/src/components/listing-notes/__tests__/__snapshots__/listing-note.component.spec.ts.snap create mode 100644 projects/scheduling/src/components/listing-notes/__tests__/__snapshots__/listing-note.container.spec.ts.snap create mode 100644 projects/scheduling/src/components/listing-notes/__tests__/delete-listing-note-confirmation.component.spec.ts create mode 100644 projects/scheduling/src/components/listing-notes/__tests__/listing-note.component.spec.ts create mode 100644 projects/scheduling/src/components/listing-notes/__tests__/listing-note.container.spec.ts create mode 100644 projects/scheduling/src/components/listing-notes/delete-listing-note-confirmation.component.ts create mode 100644 projects/scheduling/src/components/listing-notes/listing-note.component.html create mode 100644 projects/scheduling/src/components/listing-notes/listing-note.component.scss create mode 100644 projects/scheduling/src/components/listing-notes/listing-note.component.ts create mode 100644 projects/scheduling/src/components/listing-notes/listing-note.container.ts create mode 100644 projects/scheduling/src/components/scheduling-filters/__snapshots__/scheduling-filters.component.spec.ts.snap create mode 100644 projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.html create mode 100644 projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.scss create mode 100644 projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.spec.ts create mode 100644 projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.ts create mode 100644 projects/scheduling/src/components/scheduling-slots/__snapshots__/scheduling-slots.component.spec.ts.snap create mode 100644 projects/scheduling/src/components/scheduling-slots/scheduling-slots.component.html create mode 100644 projects/scheduling/src/components/scheduling-slots/scheduling-slots.component.spec.ts create mode 100644 projects/scheduling/src/components/scheduling-slots/scheduling-slots.component.ts create mode 100644 projects/scheduling/src/index.ts create mode 100644 projects/scheduling/src/pipes/__tests__/businessTypeDescription.pipe.spec.ts create mode 100644 projects/scheduling/src/pipes/__tests__/duration.pipe.spec.ts create mode 100644 projects/scheduling/src/pipes/businessTypeDescription.pipe.ts create mode 100644 projects/scheduling/src/pipes/duration.pipe.ts create mode 100644 projects/scheduling/src/providers.ts create mode 100644 projects/scheduling/src/public-api.ts create mode 100644 projects/scheduling/src/reducers/__snapshots__/scheduling.spec.ts.snap create mode 100644 projects/scheduling/src/reducers/index.ts create mode 100644 projects/scheduling/src/reducers/listing-notes.spec.ts create mode 100644 projects/scheduling/src/reducers/scheduling.spec.ts create mode 100644 projects/scheduling/src/reducers/scheduling.ts create mode 100644 projects/scheduling/src/scheduling.module.ts create mode 100644 projects/scheduling/src/selectors/index.ts create mode 100644 projects/scheduling/src/selectors/listing-notes.spec.ts create mode 100644 projects/scheduling/src/selectors/listing-notes.ts create mode 100644 projects/scheduling/src/selectors/scheduling.spec.ts create mode 100644 projects/scheduling/src/selectors/scheduling.ts create mode 100644 projects/scheduling/src/services/listing-notes.service.spec.ts create mode 100644 projects/scheduling/src/services/listing-notes.service.ts create mode 100644 projects/scheduling/src/services/scheduling.service.spec.ts create mode 100644 projects/scheduling/src/services/scheduling.service.ts create mode 100644 projects/scheduling/src/types/allocation.ts create mode 100644 projects/scheduling/src/types/filters.ts create mode 100644 projects/scheduling/src/types/hearingSlot.ts create mode 100644 projects/scheduling/src/types/index.ts create mode 100644 projects/scheduling/src/types/listingNotes.ts create mode 100644 projects/scheduling/src/utils/__tests__/courtroom.spec.ts create mode 100644 projects/scheduling/src/utils/__tests__/hearingSlotTime.spec.ts create mode 100644 projects/scheduling/src/utils/__tests__/operationalUnit.spec.ts create mode 100644 projects/scheduling/src/utils/__tests__/rotaBusinessType.spec.ts create mode 100644 projects/scheduling/src/utils/allocations.ts create mode 100644 projects/scheduling/src/utils/courtrooms.ts create mode 100644 projects/scheduling/src/utils/hearingSlotTime.ts create mode 100644 projects/scheduling/src/utils/index.ts create mode 100644 projects/scheduling/src/utils/operationalUnit.ts create mode 100644 projects/scheduling/src/utils/rotaBusinessType.ts create mode 100644 projects/scheduling/src/utils/sessionTimings.ts create mode 100644 projects/scheduling/tsconfig.lib.json create mode 100644 projects/scheduling/tsconfig.lib.prod.json create mode 100644 projects/scheduling/tsconfig.spec.json create mode 100644 projects/testing/package.json create mode 100644 projects/testing/src/index.ts create mode 100644 projects/testing/src/public_api.ts create mode 100644 projects/testing/src/resources/index.ts create mode 100644 projects/testing/src/resources/organisationUnits.ts create mode 100644 projects/testing/src/resources/users.ts create mode 100644 projects/testing/src/util/log.ts create mode 100644 projects/testing/src/util/pollUntil.ts create mode 100644 projects/testing/src/util/request.ts create mode 100644 projects/testing/src/util/urn.ts create mode 100644 projects/testing/tsconfig.json create mode 100644 projects/users-groups/.eslintrc.json create mode 100644 projects/users-groups/ng-package.json create mode 100644 projects/users-groups/package.json create mode 100644 projects/users-groups/src/actions/index.ts create mode 100644 projects/users-groups/src/actions/users-groups.actions.ts create mode 100644 projects/users-groups/src/effects/__tests__/user-groups.effects.spec.ts create mode 100644 projects/users-groups/src/effects/user-groups.effects.ts create mode 100644 projects/users-groups/src/features/directives/__tests__/__snapshots__/cpp-user-has-feature-enabled.directive.spec.ts.snap create mode 100644 projects/users-groups/src/features/directives/__tests__/cpp-user-has-feature-enabled.directive.spec.ts create mode 100644 projects/users-groups/src/features/directives/cpp-user-has-feature-enabled.directive.ts create mode 100644 projects/users-groups/src/guards/__tests__/user-details.guard.spec.ts create mode 100644 projects/users-groups/src/guards/__tests__/user-feature-exists.guard.spec.ts create mode 100644 projects/users-groups/src/guards/__tests__/user-features.guard.spec.ts create mode 100644 projects/users-groups/src/guards/__tests__/user-groups-with-organisation.guard.spec.ts create mode 100644 projects/users-groups/src/guards/__tests__/user-groups.guard.spec.ts create mode 100644 projects/users-groups/src/guards/__tests__/user-organisations.guard.spec.ts create mode 100644 projects/users-groups/src/guards/__tests__/user-permissions-exist.guard.spec.ts create mode 100644 projects/users-groups/src/guards/__tests__/user-permissions.guard.spec.ts create mode 100644 projects/users-groups/src/guards/__tests__/user-service-exists.guard.spec.ts create mode 100644 projects/users-groups/src/guards/__tests__/user-services.guard.spec.ts create mode 100644 projects/users-groups/src/guards/permissions/user-permissions-exist.guard.ts create mode 100644 projects/users-groups/src/guards/permissions/user-permissions.guard.ts create mode 100644 projects/users-groups/src/guards/user-details.guard.ts create mode 100644 projects/users-groups/src/guards/user-feature-exist.guard.ts create mode 100644 projects/users-groups/src/guards/user-features.guard.ts create mode 100644 projects/users-groups/src/guards/user-groups-with-organisation.guard.ts create mode 100644 projects/users-groups/src/guards/user-groups.guard.ts create mode 100644 projects/users-groups/src/guards/user-organisations.guard.ts create mode 100644 projects/users-groups/src/guards/user-roles.guard.ts create mode 100644 projects/users-groups/src/guards/user-service-exists.guard.ts create mode 100644 projects/users-groups/src/guards/user-services.guard.ts create mode 100644 projects/users-groups/src/index.ts create mode 100644 projects/users-groups/src/permissions/directives/__tests__/__snapshots__/cpp-user-has-permission.directive.spec.ts.snap create mode 100644 projects/users-groups/src/permissions/directives/__tests__/cpp-user-has-permission.directive.spec.ts create mode 100644 projects/users-groups/src/permissions/directives/cpp-user-has-permission.directive.ts create mode 100644 projects/users-groups/src/providers.ts create mode 100644 projects/users-groups/src/public_api.ts create mode 100644 projects/users-groups/src/reducers/__tests__/__snapshots__/index.spec.ts.snap create mode 100644 projects/users-groups/src/reducers/__tests__/index.spec.ts create mode 100644 projects/users-groups/src/reducers/index.ts create mode 100644 projects/users-groups/src/reducers/users-groups.reducer.ts create mode 100644 projects/users-groups/src/services/__tests__/system-announcements.service.spec.ts create mode 100644 projects/users-groups/src/services/__tests__/users-groups.service.spec.ts create mode 100644 projects/users-groups/src/services/system-announcements.service.ts create mode 100644 projects/users-groups/src/services/users-groups.service.ts create mode 100644 projects/users-groups/src/users-groups.interfaces.ts create mode 100644 projects/users-groups/src/users-groups.module.ts create mode 100644 projects/users-groups/src/utils/__tests__/features-exist.spec.ts create mode 100644 projects/users-groups/src/utils/__tests__/permissions-exist.spec.ts create mode 100644 projects/users-groups/src/utils/__tests__/role-permissions-aggregator.spec.ts create mode 100644 projects/users-groups/src/utils/features-exist.ts create mode 100644 projects/users-groups/src/utils/index.ts create mode 100644 projects/users-groups/src/utils/permissions-exist.ts create mode 100644 projects/users-groups/src/utils/role-permissions-aggregator.ts create mode 100644 projects/users-groups/tsconfig.lib.json create mode 100644 projects/users-groups/tsconfig.lib.prod.json create mode 100644 projects/users-groups/tsconfig.spec.json create mode 100644 sonar-project.properties create mode 100644 tsconfig.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e89330a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..2ef9aca --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,44 @@ +{ + "root": true, + "ignorePatterns": ["projects/**/*"], + "plugins": ["@angular-eslint"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["tsconfig.json", "e2e/tsconfig.json"], + "createDefaultProgram": true + }, + "extends": ["plugin:@angular-eslint/template/process-inline-templates", "prettier"], + "rules": { + "@angular-eslint/component-selector": "off", + "@angular-eslint/directive-selector": "off", + "prefer-arrow/prefer-arrow-functions": "off", + "@typescript-eslint/naming-convention": "off", + "@typescript-eslint/member-ordering": "off", + "jsdoc/newline-after-description": "off", + "@angular-eslint/no-output-native": "off", + "@angular-eslint/component-class-suffix": "off", + "@typescript-eslint/consistent-type-definitions": "off", + "@typescript-eslint/dot-notation": "off", + "@angular-eslint/no-input-rename": "off", + "@typescript-eslint/explicit-member-accessibility": [ + "off", + { + "accessibility": "explicit" + } + ], + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/unified-signatures": "off", + "id-blacklist": "off", + "id-match": "off", + "no-underscore-dangle": "off" + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@angular-eslint/template/recommended"], + "rules": {} + } + ] +} diff --git a/.github/actions/secret-scanner/action.yml b/.github/actions/secret-scanner/action.yml new file mode 100644 index 0000000..0948dba --- /dev/null +++ b/.github/actions/secret-scanner/action.yml @@ -0,0 +1,67 @@ +name: Secret Scanner + +description: Scans the code base to detect for the presence of secrets. + +inputs: + github_token: + required: true + description: GitHub token for authentication, required for accessing the repository and posting comments. + + gitleaks_license: + required: true + description: Gitleaks license key to use the licensed version. + + gitleaks_regex_internal_url: + required: true + description: Regex to identify internal urls + + gitleaks_regex_banned_ids: + required: true + description: Regex to identify banned IDs + +runs: + using: "composite" + steps: + - name: Prepare Gitleaks config + shell: bash + run: | + echo "Executing step: Prepare Gitleaks config" + set -euo pipefail + + # Validate that regex parameters are not empty or null + # Note: Missing secrets evaluate to empty strings in GitHub Actions + GITLEAKS_REGEX_INTERNAL_URL_VALUE="${{ inputs.gitleaks_regex_internal_url }}" + GITLEAKS_REGEX_BANNED_IDS_VALUE="${{ inputs.gitleaks_regex_banned_ids }}" + + if [ -z "$GITLEAKS_REGEX_INTERNAL_URL_VALUE" ] || [ "$GITLEAKS_REGEX_INTERNAL_URL_VALUE" = "null" ]; then + echo "::error::gitleaks_regex_internal_url is required and cannot be empty or null. Please ensure the secret is defined and has a value." + exit 1 + fi + + if [ -z "$GITLEAKS_REGEX_BANNED_IDS_VALUE" ] || [ "$GITLEAKS_REGEX_BANNED_IDS_VALUE" = "null" ]; then + echo "::error::gitleaks_regex_banned_ids is required and cannot be empty or null. Please ensure the secret is defined and has a value." + exit 1 + fi + + export GITLEAKS_REGEX_INTERNAL_URL="$GITLEAKS_REGEX_INTERNAL_URL_VALUE" + export GITLEAKS_REGEX_BANNED_IDS="$GITLEAKS_REGEX_BANNED_IDS_VALUE" + CUSTOM_CONFIG_FILE="$RUNNER_TEMP/gitleaks-custom-rules.toml" + envsubst < "${{ github.action_path }}/gitleaks-custom-rules-template.toml" > "$CUSTOM_CONFIG_FILE" + + # Set GITLEAKS_CONFIG env variable and make it available to subsequent steps + echo "GITLEAKS_CONFIG=$CUSTOM_CONFIG_FILE" >> "$GITHUB_ENV" + echo "------------ Scan will run with builtin + custom rules ------------" + + - name: Gitleaks scanning + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ inputs.github_token }} + GITLEAKS_LICENSE: ${{ inputs.gitleaks_license }} + GITLEAKS_ENABLE_COMMENTS: "false" # suppress PR comments + GITLEAKS_ENABLE_SUMMARY: "false" # suppress Job Summary + + - name: TruffleHog 🐽 scanning + uses: trufflesecurity/trufflehog@main + with: + extra_args: --results=verified + diff --git a/.github/actions/secret-scanner/gitleaks-custom-rules-template.toml b/.github/actions/secret-scanner/gitleaks-custom-rules-template.toml new file mode 100644 index 0000000..2286071 --- /dev/null +++ b/.github/actions/secret-scanner/gitleaks-custom-rules-template.toml @@ -0,0 +1,35 @@ +title = "Custom rules" + +[extend] +useDefault = true + +[[rules]] +id = "internal-urls" +description = "Identify internal urls" +regex = '''${GITLEAKS_REGEX_INTERNAL_URL}''' +tags = ["internal-urls"] + +[[rules]] +id = "banned-ids" +description = "Identify banned IDs" +regex = '''${GITLEAKS_REGEX_BANNED_IDS}''' +tags = ["banned-ids"] + +# --------------------------------------------------------------------------- +# Reviewed and accepted values. Each entry is matched against a finding's +# secret, so only these exact values are excluded - the rules above still +# apply everywhere else. +# - "vnd..query.local" HTTP media types, which are content-type +# identifiers rather than hostnames (only the trailing ".local" matches) +# - user-id UUIDs used by the test fixtures under projects/testing +# --------------------------------------------------------------------------- +[allowlist] +description = "Accepted values" +regexes = [ + '''^vnd\.[A-Za-z0-9.-]+\.local$''', + '''^d7c91866-646a-462c-9203-46678e8cddef$''', + '''^48a948dc-7d96-45bd-baa5-5237432152d2$''', + '''^ad0920bd-521a-4f40-b942-f82d258ea3cc$''', + '''^0e61972a-0a26-4de1-a676-36119c535a60$''' +] + diff --git a/.github/workflows/secret-scanning.yml b/.github/workflows/secret-scanning.yml new file mode 100644 index 0000000..d312688 --- /dev/null +++ b/.github/workflows/secret-scanning.yml @@ -0,0 +1,24 @@ +name: Scanning +on: + pull_request: + branches: + - '**' + schedule: + - cron: '0 4 * * 4' # Every Thursday at 04:00 + workflow_dispatch: + +jobs: + scan: + name: Secrets Scanner + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: ./.github/actions/secret-scanner + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + gitleaks_license: ${{ secrets.GITLEAKS_LICENSE }} + gitleaks_regex_internal_url: ${{ secrets.HMCTS_CP_GITLEAKS_REGEX_INTERNAL_URL }} + gitleaks_regex_banned_ids: ${{ secrets.HMCTS_CP_GITLEAKS_REGEX_BANNED_IDS }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7ba183d --- /dev/null +++ b/.gitignore @@ -0,0 +1,49 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/build +/dist +/tmp +/release +/out-tsc + +# dependencies +/node_modules +.npmrc + +# profiling files +chrome-profiler-events.json +speed-measure-plugin.json + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# misc +/.angular/cache +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +.scannerwork/ +/typings + +# System Files +.DS_Store +Thumbs.db diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..be9f5c7 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "printWidth": 100, + "singleQuote": true, + "useTabs": false, + "tabWidth": 2, + "semi": true, + "bracketSpacing": true, + "trailingComma": "none" +} diff --git a/.scripts/version.js b/.scripts/version.js new file mode 100644 index 0000000..f106597 --- /dev/null +++ b/.scripts/version.js @@ -0,0 +1,46 @@ +const path = require('path'); +const fs = require('fs'); +const buildDir = path.join(__dirname, '../dist'); +const caretRangeRegex = /^\^0\.0\.0-PLACEHOLDER$/; + +if (!process.env.npm_package_version) { + throw new Error( + '[Build] Failed to determine package version. ' + + 'Did you forget to supply an `npm_package_version` environment variable?' + ); +} + +function updateCppPeerDependencies(packageJson, newVersion) { + if (!packageJson.peerDependencies) { + return; + } + for (const [depName, currentRange] of Object.entries(packageJson.peerDependencies)) { + if (currentRange.match(caretRangeRegex)) { + packageJson.peerDependencies[depName] = `^${newVersion}`; + console.log( + `[Build] Bumped ${depName} peer dependency: ${currentRange} to ${packageJson.peerDependencies[depName]}` + ); + } + } +} + +try { + const newVersion = process.env.npm_package_version.trim(); + const directoryNames = fs.readdirSync(buildDir).filter((item) => { + const itemPath = path.join(buildDir, item); + return fs.statSync(itemPath).isDirectory(); + }); + + directoryNames.forEach((packageName) => { + const pathToPackage = path.join(buildDir, packageName, 'package.json'); + const packageJson = { + ...require(pathToPackage), + version: newVersion + }; + updateCppPeerDependencies(packageJson, newVersion); + fs.writeFileSync(pathToPackage, JSON.stringify(packageJson, null, 2)); + console.log(`[Build] Bumped ${packageJson.name} to ${packageJson.version}.`); + }); +} catch (e) { + console.log(`[Build] Versioning failed: ${e.toString()}`); +} diff --git a/README.md b/README.md index de7b47a..5c42cb2 100644 --- a/README.md +++ b/README.md @@ -1 +1,27 @@ -# cpp-ui-core \ No newline at end of file +# CppCore + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.2.1. + +## Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/angular.json b/angular.json new file mode 100644 index 0000000..211d016 --- /dev/null +++ b/angular.json @@ -0,0 +1,155 @@ +{ + "version": 1, + "newProjectRoot": "projects", + "projects": { + "core": { + "root": "projects/core", + "sourceRoot": "projects/core/src", + "projectType": "library", + "architect": { + "build": { + "builder": "@angular/build:ng-packagr", + "options": { + "tsConfig": "projects/core/tsconfig.lib.json", + "project": "projects/core/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/core/tsconfig.lib.prod.json" + } + } + }, + "test": { + "builder": "@angular-builders/jest:run", + "options": { + "configPath": "./jest.config.js" + } + }, + "lint": { + "builder": "@angular-eslint/builder:lint", + "options": { + "lintFilePatterns": ["projects/core/**/*.ts", "projects/core/**/*.html"] + } + } + } + }, + "reference-data": { + "root": "projects/reference-data", + "sourceRoot": "projects/reference-data/src", + "projectType": "library", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular/build:ng-packagr", + "options": { + "tsConfig": "projects/reference-data/tsconfig.lib.json", + "project": "projects/reference-data/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/reference-data/tsconfig.lib.prod.json" + } + } + }, + "test": { + "builder": "@angular-builders/jest:run", + "options": { + "configPath": "./jest.config.js" + } + }, + "lint": { + "builder": "@angular-eslint/builder:lint", + "options": { + "lintFilePatterns": [ + "projects/reference-data/**/*.ts", + "projects/reference-data/**/*.html" + ] + } + } + } + }, + "testing": { + "root": "projects/testing", + "sourceRoot": "projects/testing/src", + "projectType": "library", + "prefix": "lib", + "architect": {} + }, + "users-groups": { + "root": "projects/users-groups", + "sourceRoot": "projects/users-groups/src", + "projectType": "library", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular/build:ng-packagr", + "options": { + "tsConfig": "projects/users-groups/tsconfig.lib.json", + "project": "projects/users-groups/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/users-groups/tsconfig.lib.prod.json" + } + } + }, + "test": { + "builder": "@angular-builders/jest:run", + "options": { + "configPath": "./jest.config.js" + } + }, + "lint": { + "builder": "@angular-eslint/builder:lint", + "options": { + "lintFilePatterns": ["projects/users-groups/**/*.ts", "projects/users-groups/**/*.html"] + } + } + } + }, + "scheduling": { + "projectType": "library", + "root": "projects/scheduling", + "sourceRoot": "projects/scheduling/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular/build:ng-packagr", + "options": { + "tsConfig": "projects/scheduling/tsconfig.lib.json", + "project": "projects/scheduling/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/scheduling/tsconfig.lib.prod.json" + } + } + }, + "test": { + "builder": "@angular-builders/jest:run", + "options": { + "configPath": "./jest.config.js" + } + }, + "lint": { + "builder": "@angular-eslint/builder:lint", + "options": { + "lintFilePatterns": ["projects/scheduling/**/*.ts", "projects/scheduling/**/*.html"] + } + } + } + } + }, + "cli": { + "analytics": "ad4e11a1-4cab-4779-9fdd-c62e01b6b2d7", + "schematicCollections": ["@angular-eslint/schematics"] + }, + "schematics": { + "@angular-eslint/schematics:application": { + "setParserOptionsProject": true + }, + "@angular-eslint/schematics:library": { + "setParserOptionsProject": true + } + } +} diff --git a/azure-pipelines.yaml b/azure-pipelines.yaml index 5bb9d8b..015aa5d 100644 --- a/azure-pipelines.yaml +++ b/azure-pipelines.yaml @@ -1,15 +1,26 @@ -name: CPP Context Verify & Validation +name: UI Verify & Validation -# Need to update this for actual migration trigger: none pr: - - '*' + - main + - 'team/*' parameters: - - name: RUN_RELEASE - type: boolean - default: false + - name: SEMVER_VERSION_INCREMENT + default: 'manual' + values: + - patch + - minor + - major + - prepatch + - preminor + - premajor + - prerelease + - from-git + - manual + - name: SEMVER_VERSION_MANUAL + default: null resources: repositories: @@ -17,23 +28,33 @@ resources: type: github name: hmcts/cpp-azure-devops-templates endpoint: 'hmcts' - ref: 'main' + ref: 'ui-test-upd' pool: - name: "MDV-ADO-AGENT-AKS-01" - demands: - - identifier -equals centos8-j17 + name: 'MDV-ADO-AGENTS-01' variables: - sonarqubeProject: "uk.gov.moj.cpp.common:common-bom" + - name: NODE_VERSION + value: '18.20.x' + - name: NPM_VERSION + value: '10.7.0' + - name: sonarqubeProject + value: 'uk.gov.justice.cpp.ui:ui-core' stages: - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - - template: pipelines/platform-verify.yaml@cppAzureDevOpsTemplates + - template: pipelines/ui-library-verify.yaml@cppAzureDevOpsTemplates + parameters: + repo: '$(Build.Repository.Name)' + NODE_VERSION: '${{ variables.NODE_VERSION }}' + NPM_VERSION: '${{ variables.NPM_VERSION }}' + sonarqube_project: ${{ variables['sonarqubeProject'] }} - ${{ if eq(variables['Build.Reason'], 'Manual') }}: - - template: pipelines/library-validation.yaml@cppAzureDevOpsTemplates + - template: pipelines/ui-library-validation.yaml@cppAzureDevOpsTemplates parameters: - serviceName: 'commonbom' - RUN_RELEASE: ${{ parameters.RUN_RELEASE }} - JOB_TYPE: 'library' + repo: '$(Build.Repository.Name)' + SEMVER_VERSION_INCREMENT: '${{ parameters.SEMVER_VERSION_INCREMENT }}' + SEMVER_VERSION_MANUAL: '${{ parameters.SEMVER_VERSION_MANUAL }}' + NODE_VERSION: '${{ variables.NODE_VERSION }}' + NPM_VERSION: '${{ variables.NPM_VERSION }}' diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..27e4dcf --- /dev/null +++ b/jest.config.js @@ -0,0 +1,17 @@ +const { paths, baseUrl } = require('./tsconfig.json').compilerOptions; +const { pathsToModuleNameMapper } = require('ts-jest'); + +module.exports = { + modulePathIgnorePatterns: ['dist'], + modulePaths: [baseUrl], + moduleNameMapper: { + ...pathsToModuleNameMapper(paths, { prefix: '' }), + '^lodash-es$': 'lodash' + }, + transformIgnorePatterns: ['node_modules/(?!@cpp|@angular|@ngrx|.*\\.mjs)'], + snapshotSerializers: [ + '/node_modules/jest-preset-angular/build/serializers/no-ng-attributes', + '/node_modules/jest-preset-angular/build/serializers/ng-snapshot', + '/node_modules/jest-preset-angular/build/serializers/html-comment' + ] +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..669a18e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,25102 @@ +{ + "name": "cpp.ui.core", + "version": "19.0.5", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cpp.ui.core", + "version": "19.0.5", + "license": "UNLICENSED", + "dependencies": { + "@ngrx/operators": "^19.2.1", + "tslib": "^2.0.0" + }, + "devDependencies": { + "@angular-builders/jest": "^19.0.1", + "@angular-devkit/core": "^19.2.15", + "@angular-eslint/builder": "19.8.1", + "@angular-eslint/eslint-plugin": "19.8.1", + "@angular-eslint/eslint-plugin-template": "19.8.1", + "@angular-eslint/schematics": "19.8.1", + "@angular-eslint/template-parser": "19.8.1", + "@angular/animations": "^19.2.14", + "@angular/build": "^19.2.15", + "@angular/cdk": "^19.2.19", + "@angular/cli": "^19.2.15", + "@angular/common": "^19.2.14", + "@angular/compiler": "^19.2.14", + "@angular/compiler-cli": "^19.2.14", + "@angular/core": "^19.2.14", + "@angular/forms": "^19.2.14", + "@angular/language-service": "^19.2.14", + "@angular/platform-browser": "^19.2.14", + "@angular/platform-browser-dynamic": "^19.2.14", + "@angular/router": "^19.2.14", + "@cpp/pdk": "^19.0.2", + "@kolkov/angular-editor": "^2.1.0", + "@ngrx/effects": "^19.2.1", + "@ngrx/store": "^19.2.1", + "@types/jest": "^30.0.0", + "@types/lodash-es": "^4.17.7", + "@types/node": "^18.19.122", + "@types/request": "^2.48.4", + "@types/uuid": "^3.4.4", + "@types/ws": "^8.5.4", + "@typescript-eslint/eslint-plugin": "^8.38.0", + "@typescript-eslint/parser": "^8.38.0", + "chalk": "^3.0.0", + "core-js": "^2.5.4", + "eslint": "^8.57.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-import": "latest", + "eslint-plugin-jsdoc": "^52.0.1", + "eslint-plugin-prefer-arrow": "latest", + "husky": "^4.2.5", + "jasmine-marbles": "^0.9.2", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.5.0", + "jest-jasmine2": "^29.5.0", + "jest-preset-angular": "^14.5.4", + "lodash-es": "^4.17.21", + "mkdirp": "^3.0.1", + "ng-packagr": "^19.2.2", + "npm-run-all": "^4.1.5", + "prettier": "^2.8.4", + "pretty-quick": "^3.1.3", + "request": "^2.88.0", + "rxjs": "^7.8.2", + "rxjs-marbles": "^7.0.1", + "ts-jest": "^29.4.1", + "ts-node": "~9.0.0", + "typescript": "^5.8.3", + "zone.js": "^0.15.1" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha1-7UQbb6YAByUgzhi0PSyMyMrsx/Q=", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-builders/common": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-builders/common/-/common-3.0.1.tgz", + "integrity": "sha1-apz6Rm5QEZNMi9SUzU35MnMHLeo=", + "dev": true, + "dependencies": { + "@angular-devkit/core": "^19.0.0", + "ts-node": "^10.0.0", + "tsconfig-paths": "^4.1.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + } + }, + "node_modules/@angular-builders/common/node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha1-cPAhyeGFvM3Kgg4m3EE4BcEBxx8=", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/@angular-builders/jest": { + "version": "19.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-builders/jest/-/jest-19.0.1.tgz", + "integrity": "sha1-yzllmPq8NL0kGEkLKYxk7a4qbb0=", + "dev": true, + "dependencies": { + "@angular-builders/common": "3.0.1", + "@angular-devkit/architect": ">=0.1900.0 < 0.2000.0", + "@angular-devkit/core": "^19.0.0", + "jest-preset-angular": "14.5.4", + "lodash": "^4.17.15" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular-devkit/build-angular": "^19.0.0", + "@angular/compiler-cli": "^19.0.0", + "@angular/core": "^19.0.0", + "@angular/platform-browser-dynamic": "^19.0.0", + "jest": ">=29" + } + }, + "node_modules/@angular-builders/jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@angular-builders/jest/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/@angular-builders/jest/node_modules/jest-preset-angular": { + "version": "14.5.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-preset-angular/-/jest-preset-angular-14.5.4.tgz", + "integrity": "sha1-iNtYCkG27xqY+XT3rUfRFOx56bM=", + "dev": true, + "dependencies": { + "bs-logger": "^0.2.6", + "esbuild-wasm": ">=0.15.13", + "jest-environment-jsdom": "^29.7.0", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0", + "ts-jest": "^29.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "optionalDependencies": { + "esbuild": ">=0.15.13" + }, + "peerDependencies": { + "@angular/compiler-cli": ">=15.0.0 <20.0.0", + "@angular/core": ">=15.0.0 <20.0.0", + "@angular/platform-browser-dynamic": ">=15.0.0 <20.0.0", + "jest": "^29.0.0", + "jsdom": ">=20.0.0", + "typescript": ">=4.8" + }, + "peerDependenciesMeta": { + "jsdom": { + "optional": true + } + } + }, + "node_modules/@angular-builders/jest/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@angular-builders/jest/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@angular-builders/jest/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@angular-builders/jest/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.1902.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-devkit/architect/-/architect-0.1902.18.tgz", + "integrity": "sha1-dZt0DXVQVvoTOnI+khPd6Q8Mupk=", + "dev": true, + "dependencies": { + "@angular-devkit/core": "19.2.18", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/architect/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha1-b289meqARCke/ZLnx/z1YsQFdUM=", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/build-angular": { + "version": "19.2.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-devkit/build-angular/-/build-angular-19.2.18.tgz", + "integrity": "sha1-UdnZ/Scs12xglRrTtQezNEXylOw=", + "dev": true, + "peer": true, + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.1902.18", + "@angular-devkit/build-webpack": "0.1902.18", + "@angular-devkit/core": "19.2.18", + "@angular/build": "19.2.18", + "@babel/core": "7.26.10", + "@babel/generator": "7.26.10", + "@babel/helper-annotate-as-pure": "7.25.9", + "@babel/helper-split-export-declaration": "7.24.7", + "@babel/plugin-transform-async-generator-functions": "7.26.8", + "@babel/plugin-transform-async-to-generator": "7.25.9", + "@babel/plugin-transform-runtime": "7.26.10", + "@babel/preset-env": "7.26.9", + "@babel/runtime": "7.26.10", + "@discoveryjs/json-ext": "0.6.3", + "@ngtools/webpack": "19.2.18", + "@vitejs/plugin-basic-ssl": "1.2.0", + "ansi-colors": "4.1.3", + "autoprefixer": "10.4.20", + "babel-loader": "9.2.1", + "browserslist": "^4.21.5", + "copy-webpack-plugin": "12.0.2", + "css-loader": "7.1.2", + "esbuild-wasm": "0.25.4", + "fast-glob": "3.3.3", + "http-proxy-middleware": "3.0.5", + "istanbul-lib-instrument": "6.0.3", + "jsonc-parser": "3.3.1", + "karma-source-map-support": "1.4.0", + "less": "4.2.2", + "less-loader": "12.2.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.3.1", + "mini-css-extract-plugin": "2.9.2", + "open": "10.1.0", + "ora": "5.4.1", + "picomatch": "4.0.2", + "piscina": "4.8.0", + "postcss": "8.5.2", + "postcss-loader": "8.1.1", + "resolve-url-loader": "5.0.0", + "rxjs": "7.8.1", + "sass": "1.85.0", + "sass-loader": "16.0.5", + "semver": "7.7.1", + "source-map-loader": "5.0.0", + "source-map-support": "0.5.21", + "terser": "5.39.0", + "tree-kill": "1.2.2", + "tslib": "2.8.1", + "webpack": "5.98.0", + "webpack-dev-middleware": "7.4.2", + "webpack-dev-server": "5.2.2", + "webpack-merge": "6.0.1", + "webpack-subresource-integrity": "5.1.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "esbuild": "0.25.4" + }, + "peerDependencies": { + "@angular/compiler-cli": "^19.0.0 || ^19.2.0-next.0", + "@angular/localize": "^19.0.0 || ^19.2.0-next.0", + "@angular/platform-server": "^19.0.0 || ^19.2.0-next.0", + "@angular/service-worker": "^19.0.0 || ^19.2.0-next.0", + "@angular/ssr": "^19.2.18", + "@web/test-runner": "^0.20.0", + "browser-sync": "^3.0.2", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", + "karma": "^6.3.0", + "ng-packagr": "^19.0.0 || ^19.2.0-next.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "typescript": ">=5.5 <5.9" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@angular/ssr": { + "optional": true + }, + "@web/test-runner": { + "optional": true + }, + "browser-sync": { + "optional": true + }, + "jest": { + "optional": true + }, + "jest-environment-jsdom": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha1-b289meqARCke/ZLnx/z1YsQFdUM=", + "dev": true, + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1902.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-devkit/build-webpack/-/build-webpack-0.1902.18.tgz", + "integrity": "sha1-3kLhWBKDBt64csMbYTuhyC5OIjQ=", + "dev": true, + "peer": true, + "dependencies": { + "@angular-devkit/architect": "0.1902.18", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^5.0.2" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha1-b289meqARCke/ZLnx/z1YsQFdUM=", + "dev": true, + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "19.2.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-devkit/core/-/core-19.2.18.tgz", + "integrity": "sha1-lzN7OX8/AEGtjZsbV/74Z15keuQ=", + "dev": true, + "dependencies": { + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/core/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha1-b289meqARCke/ZLnx/z1YsQFdUM=", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "19.2.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-devkit/schematics/-/schematics-19.2.18.tgz", + "integrity": "sha1-8wfh2jzozcPBpfImeBcXYtkvhU0=", + "dev": true, + "dependencies": { + "@angular-devkit/core": "19.2.18", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.17", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha1-b289meqARCke/ZLnx/z1YsQFdUM=", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-eslint/builder": { + "version": "19.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-eslint/builder/-/builder-19.8.1.tgz", + "integrity": "sha1-lbnNobrfXY6paPVHf2UwO68j8QE=", + "dev": true, + "dependencies": { + "@angular-devkit/architect": ">= 0.1900.0 < 0.2000.0", + "@angular-devkit/core": ">= 19.0.0 < 20.0.0" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/bundled-angular-compiler": { + "version": "19.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-19.8.1.tgz", + "integrity": "sha1-wWfwsybGvJlAgi+zsN+2GyfkK0o=", + "dev": true + }, + "node_modules/@angular-eslint/eslint-plugin": { + "version": "19.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-eslint/eslint-plugin/-/eslint-plugin-19.8.1.tgz", + "integrity": "sha1-ZkEHzW29UBHQy52tqUhoWpdJ9OQ=", + "dev": true, + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "19.8.1", + "@angular-eslint/utils": "19.8.1" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/eslint-plugin-template": { + "version": "19.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-19.8.1.tgz", + "integrity": "sha1-oJbpSvQCmMPqXsx2rxaI4AUeHr8=", + "dev": true, + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "19.8.1", + "@angular-eslint/utils": "19.8.1", + "aria-query": "5.3.2", + "axobject-query": "4.1.0" + }, + "peerDependencies": { + "@angular-eslint/template-parser": "19.8.1", + "@typescript-eslint/types": "^7.11.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/schematics": { + "version": "19.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-eslint/schematics/-/schematics-19.8.1.tgz", + "integrity": "sha1-FpnywfbiEJZkU6wSIxmSr/4NTg8=", + "dev": true, + "dependencies": { + "@angular-devkit/core": ">= 19.0.0 < 20.0.0", + "@angular-devkit/schematics": ">= 19.0.0 < 20.0.0", + "@angular-eslint/eslint-plugin": "19.8.1", + "@angular-eslint/eslint-plugin-template": "19.8.1", + "ignore": "7.0.5", + "semver": "7.7.2", + "strip-json-comments": "3.1.1" + } + }, + "node_modules/@angular-eslint/schematics/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-7.7.2.tgz", + "integrity": "sha1-Z9mf3NNc7CHm+Lh6f9UVoz+YK1g=", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-eslint/template-parser": { + "version": "19.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-eslint/template-parser/-/template-parser-19.8.1.tgz", + "integrity": "sha1-yNuCckXOgQ4aLKo9qp5/w7J5Nbg=", + "dev": true, + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "19.8.1", + "eslint-scope": "^8.0.2" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/utils": { + "version": "19.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular-eslint/utils/-/utils-19.8.1.tgz", + "integrity": "sha1-tr4996TmL/CsINxXbe+P+ZhNNCY=", + "dev": true, + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "19.8.1" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular/animations": { + "version": "19.2.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/animations/-/animations-19.2.15.tgz", + "integrity": "sha1-alZ84K9ELDsQHA4TPWf41aIQjPQ=", + "dev": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/common": "19.2.15", + "@angular/core": "19.2.15" + } + }, + "node_modules/@angular/build": { + "version": "19.2.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/build/-/build-19.2.18.tgz", + "integrity": "sha1-PUl0TxisuK9+DQJNAqMuznPM0Ik=", + "dev": true, + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.1902.18", + "@babel/core": "7.26.10", + "@babel/helper-annotate-as-pure": "7.25.9", + "@babel/helper-split-export-declaration": "7.24.7", + "@babel/plugin-syntax-import-attributes": "7.26.0", + "@inquirer/confirm": "5.1.6", + "@vitejs/plugin-basic-ssl": "1.2.0", + "beasties": "0.3.2", + "browserslist": "^4.23.0", + "esbuild": "0.25.4", + "fast-glob": "3.3.3", + "https-proxy-agent": "7.0.6", + "istanbul-lib-instrument": "6.0.3", + "listr2": "8.2.5", + "magic-string": "0.30.17", + "mrmime": "2.0.1", + "parse5-html-rewriting-stream": "7.0.0", + "picomatch": "4.0.2", + "piscina": "4.8.0", + "rollup": "4.34.8", + "sass": "1.85.0", + "semver": "7.7.1", + "source-map-support": "0.5.21", + "vite": "6.3.6", + "watchpack": "2.4.2" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "lmdb": "3.2.6" + }, + "peerDependencies": { + "@angular/compiler": "^19.0.0 || ^19.2.0-next.0", + "@angular/compiler-cli": "^19.0.0 || ^19.2.0-next.0", + "@angular/localize": "^19.0.0 || ^19.2.0-next.0", + "@angular/platform-server": "^19.0.0 || ^19.2.0-next.0", + "@angular/service-worker": "^19.0.0 || ^19.2.0-next.0", + "@angular/ssr": "^19.2.18", + "karma": "^6.4.0", + "less": "^4.2.0", + "ng-packagr": "^19.0.0 || ^19.2.0-next.0", + "postcss": "^8.4.0", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "typescript": ">=5.5 <5.9" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@angular/ssr": { + "optional": true + }, + "karma": { + "optional": true + }, + "less": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", + "integrity": "sha1-D0Si+GaO2HsEC2/mWTWKySOdpNs=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", + "integrity": "sha1-JbmgHe72UYqUhDFWTJh7yyBSdPU=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", + "integrity": "sha1-ihAoaciPN4DH1eZ3av0/GQhOzX8=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", + "integrity": "sha1-jlJkF81vVNrx0MBM82EWAhZYGVY=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", + "integrity": "sha1-DnAnBUST80CbHyGaPqxe/RKO+Jk=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", + "integrity": "sha1-crIEqSATnp7D0zG9nP2aDCSMyxA=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", + "integrity": "sha1-qxtSLr5bfgbJlQTMOPbNi4CLpBw=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", + "integrity": "sha1-+Mwwtjjx7n49GOrCSvR+op2b6wA=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", + "integrity": "sha1-evN6noXyXbWdyCFBcpB7fhRsEsw=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", + "integrity": "sha1-piPrDTYXwDt6c3FuuFxuN7d29+A=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", + "integrity": "sha1-h6sDPuvRqaHde2BQn2Mz7B+C2ZQ=", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", + "integrity": "sha1-97wQ++CWq0RpQjPcQqIpHtVFPUs=", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", + "integrity": "sha1-oVHLEjTMmyz16M/AKqkUNrj54ng=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", + "integrity": "sha1-eFnhllAcw7MGLUXSd2z7TS86k1A=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", + "integrity": "sha1-5iNX0ARY2xcne4itv2kLuFXKyTc=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", + "integrity": "sha1-/HzUD0SDSnA8Hxw/6LzCfOR2zVA=", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", + "integrity": "sha1-Flf1Yya74KyA7tyfnBj8Hd0k4Qc=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular/build/node_modules/vite": { + "version": "6.3.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/vite/-/vite-6.3.6.tgz", + "integrity": "sha1-aal2tkkwdQ1AIZ+8aMUgCHTTFcE=", + "dev": true, + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/@angular/build/node_modules/vite/node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha1-KCUAZhWmGbT2Kp50JswSCzSajzw=", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@angular/build/node_modules/vite/node_modules/rollup": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rollup/-/rollup-4.52.5.tgz", + "integrity": "sha1-lpgs3K7c3VGxI1mYHyQPlDBOwjU=", + "dev": true, + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.5", + "@rollup/rollup-android-arm64": "4.52.5", + "@rollup/rollup-darwin-arm64": "4.52.5", + "@rollup/rollup-darwin-x64": "4.52.5", + "@rollup/rollup-freebsd-arm64": "4.52.5", + "@rollup/rollup-freebsd-x64": "4.52.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", + "@rollup/rollup-linux-arm-musleabihf": "4.52.5", + "@rollup/rollup-linux-arm64-gnu": "4.52.5", + "@rollup/rollup-linux-arm64-musl": "4.52.5", + "@rollup/rollup-linux-loong64-gnu": "4.52.5", + "@rollup/rollup-linux-ppc64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-musl": "4.52.5", + "@rollup/rollup-linux-s390x-gnu": "4.52.5", + "@rollup/rollup-linux-x64-gnu": "4.52.5", + "@rollup/rollup-linux-x64-musl": "4.52.5", + "@rollup/rollup-openharmony-arm64": "4.52.5", + "@rollup/rollup-win32-arm64-msvc": "4.52.5", + "@rollup/rollup-win32-ia32-msvc": "4.52.5", + "@rollup/rollup-win32-x64-gnu": "4.52.5", + "@rollup/rollup-win32-x64-msvc": "4.52.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/@angular/cdk": { + "version": "19.2.19", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/cdk/-/cdk-19.2.19.tgz", + "integrity": "sha1-Jbo7j1Zea82c1ZFZwNmkJEzzx+4=", + "dev": true, + "dependencies": { + "parse5": "^7.1.2", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^19.0.0 || ^20.0.0", + "@angular/core": "^19.0.0 || ^20.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/cli": { + "version": "19.2.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/cli/-/cli-19.2.18.tgz", + "integrity": "sha1-Wd/kK1gc99OFv1C+HEHIgiBDq/Y=", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1902.18", + "@angular-devkit/core": "19.2.18", + "@angular-devkit/schematics": "19.2.18", + "@inquirer/prompts": "7.3.2", + "@listr2/prompt-adapter-inquirer": "2.0.18", + "@schematics/angular": "19.2.18", + "@yarnpkg/lockfile": "1.1.0", + "ini": "5.0.0", + "jsonc-parser": "3.3.1", + "listr2": "8.2.5", + "npm-package-arg": "12.0.2", + "npm-pick-manifest": "10.0.0", + "pacote": "20.0.0", + "resolve": "1.22.10", + "semver": "7.7.1", + "symbol-observable": "4.0.0", + "yargs": "17.7.2" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/common": { + "version": "19.2.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/common/-/common-19.2.15.tgz", + "integrity": "sha1-k01+rVyKPEZgqxMboSn85glt7x0=", + "dev": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/core": "19.2.15", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "19.2.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/compiler/-/compiler-19.2.15.tgz", + "integrity": "sha1-IPsh531sas6aDEJ6PKm8tEFbYzY=", + "dev": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + } + }, + "node_modules/@angular/compiler-cli": { + "version": "19.2.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/compiler-cli/-/compiler-cli-19.2.15.tgz", + "integrity": "sha1-aNFBguHiOo87ExlPzLVp7s/Yn8M=", + "dev": true, + "dependencies": { + "@babel/core": "7.26.9", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^4.0.0", + "convert-source-map": "^1.5.1", + "reflect-metadata": "^0.2.0", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js", + "ngcc": "bundles/ngcc/index.js" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/compiler": "19.2.15", + "typescript": ">=5.5 <5.9" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core": { + "version": "7.26.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/core/-/core-7.26.9.tgz", + "integrity": "sha1-cYOFQqSx5J3+01PXrLxuuJ9KdvI=", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.9", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.9", + "@babel/types": "^7.26.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha1-S1YPZJ/E6RjdCrdc9JYei8iC2Co=", + "dev": true + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha1-VW0u+GiRRuRtzqS/3QlfNDTf/LQ=", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular/core": { + "version": "19.2.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/core/-/core-19.2.15.tgz", + "integrity": "sha1-A5W2Co75xxWpffeln+SXPuPTWlE=", + "dev": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.15.0" + } + }, + "node_modules/@angular/forms": { + "version": "19.2.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/forms/-/forms-19.2.15.tgz", + "integrity": "sha1-f5+BvIt+y9rhuZS3pNvst/wufr8=", + "dev": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/common": "19.2.15", + "@angular/core": "19.2.15", + "@angular/platform-browser": "19.2.15", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/language-service": { + "version": "19.2.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/language-service/-/language-service-19.2.15.tgz", + "integrity": "sha1-ZSPwm9HWMpFA06LUZcNLtHi1Z3c=", + "dev": true, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + } + }, + "node_modules/@angular/platform-browser": { + "version": "19.2.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/platform-browser/-/platform-browser-19.2.15.tgz", + "integrity": "sha1-78gU79mPbiuVjyoliN6GLc6jZKA=", + "dev": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/animations": "19.2.15", + "@angular/common": "19.2.15", + "@angular/core": "19.2.15" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "19.2.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/platform-browser-dynamic/-/platform-browser-dynamic-19.2.15.tgz", + "integrity": "sha1-P8xhPnPQpO2Op2i+zmuvcUK4hKM=", + "dev": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/common": "19.2.15", + "@angular/compiler": "19.2.15", + "@angular/core": "19.2.15", + "@angular/platform-browser": "19.2.15" + } + }, + "node_modules/@angular/router": { + "version": "19.2.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@angular/router/-/router-19.2.15.tgz", + "integrity": "sha1-HSdIqRaKUk1eyEkISd8nlr2gq1M=", + "dev": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/common": "19.2.15", + "@angular/core": "19.2.15", + "@angular/platform-browser": "19.2.15", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha1-IA9xXmbVKiOyIalDVTSpHME61b4=", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha1-qKSWLhVnEhrAs7SH9SEHRDtFXH8=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.10", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/core/-/core-7.26.10.tgz", + "integrity": "sha1-XIdvg8jE3LIz7ktnDAYG8qwwAPk=", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.10", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.10", + "@babel/parser": "^7.26.10", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.10", + "@babel/types": "^7.26.10", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha1-S1YPZJ/E6RjdCrdc9JYei8iC2Co=", + "dev": true + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha1-VW0u+GiRRuRtzqS/3QlfNDTf/LQ=", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.10", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/generator/-/generator-7.26.10.tgz", + "integrity": "sha1-pg2d5JysoWdE5jQMNljf72E4w/c=", + "dev": true, + "dependencies": { + "@babel/parser": "^7.26.10", + "@babel/types": "^7.26.10", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha1-2OrE0twNe24R+m5TUzLg0xhPBrQ=", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha1-RqD276uAjVHSnOloWN0Qzocycz0=", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha1-VW0u+GiRRuRtzqS/3QlfNDTf/LQ=", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", + "integrity": "sha1-Ry0MKAKIUJaJea2J8XNZSmmV2kY=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha1-8x/Ya5FfxNrx86xpdsWb5whO2cU=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha1-VW0u+GiRRuRtzqS/3QlfNDTf/LQ=", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha1-fB3dZLIGXH94A0sltDNGp+Ge2Zc=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha1-8x/Ya5FfxNrx86xpdsWb5whO2cU=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha1-VW0u+GiRRuRtzqS/3QlfNDTf/LQ=", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha1-dCzPHLADwHtIhZ/J+iwbvkDl91M=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.10" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha1-uUMN8qpOF7woZl6t6uiqHZheZnQ=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha1-8+B6EL437XpjRhxj5pKVdZRaYVA=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha1-fvdpoyPiZV4SZnO7bS1pE7vq0gQ=", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha1-orN9PaOyNE/ghdqyNEJvK5ovpfY=", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha1-xlIhthpkPz5icF5d0rXxFeNfkgA=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha1-3bL4dlNP+AE+bCspm/TTmzxR1Ew=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha1-RgHVx84usq6lgyjUNyVSP802LOY=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha1-8x/Ya5FfxNrx86xpdsWb5whO2cU=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha1-se0tY0zjvbcw5LUt4w+MzP1pK8A=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha1-YruRs6u6jH8f7AJS2dvqEbPuelY=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha1-g5SUNokOB/o9aHPGGpbju/aS2FY=", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha1-VNp5YJerGc5n7Z+ItHuy7Ek2doc=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha1-AQtpOPq3y333SqK7wGqlA7j+X7Q=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha1-+lL1sefbGrBJRFtCHERxMDiXcC8=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", + "integrity": "sha1-/khyCSvBQ4/9DOV55vaZYJ+dCno=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha1-/gcnR0LpW9988UQ1k+64kmq2OCc=", + "dev": true, + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha1-CwIl7pA2LwMO/WROgDTJlGiJOwg=", + "dev": true, + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha1-+95Xl0cHu/oDdtNNQl/0+mxzJCE=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha1-Q/cKbX79UjcO7731WuA9kbKThW0=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha1-vrYjvVc7i28wR70EwyUGrcPlinI=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha1-4TSlR56yupwCcU6MHr8eyQdhJP0=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.28.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", + "integrity": "sha1-Nz9uLeABb3PK+PJwBPYdFndDdCo=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha1-eET5KJVG76n+usLeTP41igUL1wM=", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha1-qYP7Gusuw/btBCohD2QOkOeG/g0=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha1-TJpvZp9dDN8bkKFnHpoUa+UwDOo=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha1-tcmHJ0xKOoK4lxR5aTGmtTVErhA=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha1-GV34mxRrS3izv4l/16JXyEZZ1AY=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha1-iIlK79KwO17mrRVip8jhWHSWrs0=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha1-OxQShHaZ7qc5tPJgLHTONvawsPc=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha1-7mATSMNw+jNNIge+FYd3SWUh/VE=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha1-AcohtmjNghjJ5kDLbdiMVBKyyWo=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha1-L5vrXv8w+lB8VTLRB9qse4iPo0w=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha1-ypHvRjA1MESLkGZSusLp/plB9pk=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha1-Fn7XA2iIYIH3S1w2xlqIwDtm0ak=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha1-ubBws+M1cM2f0Hun+pHA3Te5r5c=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha1-YOIl7cvZimQDMqLnLdPmbxr1WHE=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha1-YRGiZbz7Ag6579D9/X0mQCue1sE=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha1-T2nCq5UWfgGAzVM2YT+MV4j31Io=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha1-DcZnHsDqIrbpShEU+FeXDNOd4a0=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha1-wc/a3DWmRiQAAfBhOCR7dBw02Uw=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha1-UUfSkGank0UPIgxj+jqUMbfm3Rg=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha1-1Jo7PmtS5b5nQAIjF1gCNKakc1c=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha1-biBhBnujqwJm2DSp+UgRGW8qupo=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.26.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz", + "integrity": "sha1-XjmRE147nG6q9e/1bRrloR30X/g=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.26.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.25.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha1-yAAI2srlFIJ5PlqcCLOaW+fhLXE=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha1-VYqdbiTPcoAt07YqS1Hg1iwPV/k=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", + "integrity": "sha1-4NOvY72MgN4uVn5pClToTYXrFvY=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha1-3UCmo3Df1J0yNiriBt2vK7CCqSU=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", + "integrity": "sha1-0bjmm1TJmTvFWCA+H0m/yXm/2FI=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha1-ddZhdUhniMVnKKc0JNZ8vHRzSVw=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha1-8x/Ya5FfxNrx86xpdsWb5whO2cU=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha1-gWYueL9ec0qXmCwrfwp5MojvPKo=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha1-uEAnZN+WF5ogcLt7UBoVhs+K16c=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha1-qmgh3oZMUosf7PKG8KF0446Cb00=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha1-8fv2KOzhjhLnsysXWUDmg1j1RtE=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha1-UEOFTKYgqUFJNy5pAw/4y2qesOw=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha1-THjzVVKsDgaqH248Vz1naV6K9aQ=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", + "integrity": "sha1-fMkKgXDoNTJnbPpQUnjhRwVulP4=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha1-ccpp00ce3W2qcRz038NABBXfnCM=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha1-vCT3CA6f9yG2OnCseyVkyhW2xAo=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha1-TQvzB3IOTc5tfDD8sf1sp3ves6c=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha1-ouDObvJWN2vVJ/KQ2gI5g1J6T0w=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha1-uq76TRCh1CBvnc3aUNfVgnu3CyQ=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", + "integrity": "sha1-0Cj9bbjAgd7kq+vIEsIyXiSoWw4=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha1-N7iLpZTYUkGOmVNvVhL3lfI66vk=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha1-pBRfnYfCKR/i0F+ZS2XbpOPnGW8=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha1-jkTtN8J4fswjvcNn9Jl3R2YU6DI=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", + "integrity": "sha1-dDnlkqktdnDfy5XQy8BL0+ZIAdI=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha1-Y/LPT23BXevBL2lORHFIY9NM0zQ=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha1-8yuPeBjY/AzEbuIKjvdfBxr5duE=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha1-JZxDk5coytFwasFzUbfmp76hq+s=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha1-T50xU79ngtc91CeFqdItAxl7yR0=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha1-YU4LFcyADlmX2t2b1upSTtbIGcY=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha1-nuHOyoCz5sS6ySR7IUnjaVj3+Y0=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha1-HJMs0nvzh0xDpcrE9D6/lwyYcbU=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha1-hMc0Hr3jXM02sTfp5FhmglByoww=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", + "integrity": "sha1-gjjHhfnVwcUVqQvxlu+1DQdaSyY=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha1-H9L+u3x059Ic87BfeuvJB5QK9To=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha1-/ay6scXtgexw39u4shPWXaFItq8=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha1-TbvvKDtbLwGiHoHimfduNfkA+xE=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha1-8x/Ya5FfxNrx86xpdsWb5whO2cU=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha1-B+r9YYgAWR6IBzoK8blA2aQsZCQ=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.28.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha1-nT+jvrtI3dAJHOVykTnNmcZ86lE=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha1-35ulV3yXTj8USYiLcLdhaZmKbQk=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha1-QPukh4zL0cVmBaRHmjqJGsAnS7Q=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.26.10", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.10.tgz", + "integrity": "sha1-a0UEIz3oI459ZmwVzeaB3GKt/4c=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha1-VW0u+GiRRuRtzqS/3QlfNDTf/LQ=", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha1-Uyq9rN7Ie/7h4O+OL83uVD/jK5A=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha1-GiZNX8EnUJGPUOP+PiTkNxeKuwg=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha1-GJhJNdnSKWhDpJHXigFJOffc0oA=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha1-Gg6zXYuz5u/AbJ/UDrC871SDKLg=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha1-cOlmu0kuA1Cc836vptzDBR+EQ2k=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha1-PjFD+EOK74Qt4ogW7OWHgBkM+AY=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha1-vf4tMXDHjFaRo8O+k0yMAIdSWVY=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha1-JZSPXDldsV9gkCjjcGZ+2Lrpr5c=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha1-arcG0Q+AG1xy2ouyVIVh+gQZPNE=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.26.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/preset-env/-/preset-env-7.26.9.tgz", + "integrity": "sha1-LsZOkD0O/nQ2mfd6EL33lVwhI8M=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.26.8", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.26.8", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.26.5", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.26.3", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.26.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.26.3", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.26.8", + "@babel/plugin-transform-typeof-symbol": "^7.26.7", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.40.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha1-VW0u+GiRRuRtzqS/3QlfNDTf/LQ=", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha1-zLiKLEnIFyNoYf7ngmCAVzuKkjo=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.10", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/runtime/-/runtime-7.26.10.tgz", + "integrity": "sha1-oHtNj6J68TGmM9ezUk24A+tHZMI=", + "dev": true, + "peer": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha1-+njO7TxOe2Pr9ss55YUvykX2gJ0=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha1-RQyrkTXSGnosqdLTWqBcIOaMNgs=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha1-cSci1eUPRNB7x6yf6EQ4dC3WEpg=", + "dev": true, + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha1-EPxAX2CJfDXwfoVJPJMse1ygWSs=", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha1-daLotRy3WKdVPWgEpZMteqznXDk=", + "dev": true + }, + "node_modules/@cpp/pdk": { + "version": "19.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@cpp/pdk/-/@cpp/pdk-19.0.2.tgz", + "integrity": "sha1-jlGKxc7dPnSyZrFDItjTxu6gwI0=", + "dev": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/cdk": "^19.0.0", + "@angular/common": "^19.0.0", + "@angular/core": "^19.0.0", + "@angular/forms": "^19.0.0", + "@angular/router": "^19.0.0", + "@kolkov/angular-editor": "^2.1.0", + "@ng-select/ng-select": "^14.9.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha1-AGKcNaaI4FqIsc2mhPudXnPwAKE=", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha1-ZTT9WTOlO6fL86F2FeJzoNEnP/k=", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", + "integrity": "sha1-8Tx8IFkV65GuVMVX9ekr3di+DoM=", + "dev": true, + "peer": true, + "engines": { + "node": ">=14.17.0" + } + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.52.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@es-joy/jsdoccomment/-/jsdoccomment-0.52.0.tgz", + "integrity": "sha1-EGlFttGr7YlZeqEEuA/4+ftwOKY=", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.8", + "@typescript-eslint/types": "^8.34.1", + "comment-parser": "1.4.1", + "esquery": "^1.6.0", + "jsdoc-type-pratt-parser": "~4.1.0" + }, + "engines": { + "node": ">=20.11.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", + "integrity": "sha1-gw1kdsu8oMAFE2rwcwNka0GfEWI=", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/android-arm/-/android-arm-0.25.4.tgz", + "integrity": "sha1-VmC9JQgFU90qKEOPKkAaKZWb2bE=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", + "integrity": "sha1-0R1PwpkiTnKeIZDKytvMAOep/Wc=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/android-x64/-/android-x64-0.25.4.tgz", + "integrity": "sha1-GN3ecFv5hOjNnv7FThmawYvHvuE=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", + "integrity": "sha1-sLf7VduPxvXeWgIHrphuucR2bmc=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", + "integrity": "sha1-5oE/3roLujVss1CkuAVD++Zr8m8=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", + "integrity": "sha1-3BGnPTzNwwhWe5CLQ8ZpjoUHWb4=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", + "integrity": "sha1-kdoI24vRv/XzGSTFeoHasm6ToUM=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", + "integrity": "sha1-m5PD5UrEmi7eb5BucF1dkG9tueg=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", + "integrity": "sha1-78FeRclFoIJwj5qfc7+o1NtJcoo=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", + "integrity": "sha1-vo7yw+HZn8otJcQWspfQA2BiNZY=", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", + "integrity": "sha1-sIQKJwfD/ALuwojT+d76OCfNeoc=", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", + "integrity": "sha1-KhmOWkWMnw51iBpOY9JroM+d858=", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", + "integrity": "sha1-ZPSuC5I9fdcvuGC5si7bQgB8+PU=", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", + "integrity": "sha1-+yhEsR/d3TninSkcfPgPmbDVFY0=", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", + "integrity": "sha1-FGaHbgqjVgx2c+Y/3ryCeHB7x1A=", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", + "integrity": "sha1-wQ/eiZRV23y6XxGzvM+g5Bv00M0=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", + "integrity": "sha1-AuSD+8vj8Y8LAmEqlBt3vnbBEaQ=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", + "integrity": "sha1-7EAfsLHtCsAdl4VkxfyGNO0dwu0=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", + "integrity": "sha1-8nLC9Bz+odkbk9SHpRtcXKeoyMQ=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", + "integrity": "sha1-LiWVC8EPqdseXIaOPVDET3wVD9c=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", + "integrity": "sha1-zVlvplpns7etxezVLZ9XM4MuGr0=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", + "integrity": "sha1-tNvLV7Ie6vgzHkJMOZm4nYlR3Ig=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", + "integrity": "sha1-QQhC5dZtTs4XV2NOKXqHY164L3o=", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", + "integrity": "sha1-CxfsinCyOFgn1SMUwSUxYKC5usw=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha1-cwjfFY4GTw3YuP21iqFPoqf5E7M=", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha1-vM32Fbz3tujbgw7AuNIcmiXeWXs=", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha1-OIomnw8lwbatwxe1osVXFIlMcK0=", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha1-q5tFRGblqMw6GHvqrVgEEqnFuEM=", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha1-PNQOcp82Q/2HywTlC/DrcivFlvU=", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha1-Gc0ZS/0+Qo8EmnCBfAONiatL41s=", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha1-3mM9s+wu9qPIni8ZA4Bj6KEi4sI=", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha1-+5B2JN8yVtBLmqLfUNeql+xkh0g=", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha1-q5tFRGblqMw6GHvqrVgEEqnFuEM=", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha1-Gc0ZS/0+Qo8EmnCBfAONiatL41s=", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha1-r1smkaIrRL6EewyoFkHF+2rQFyw=", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha1-Siho111taWPkI7z5C3/RvjQ0CdM=", + "deprecated": "Use @eslint/object-schema instead", + "dev": true + }, + "node_modules/@inquirer/ansi": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/ansi/-/ansi-1.0.1.tgz", + "integrity": "sha1-mU990WoAxUensRDgS/T07KGFeSk=", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "4.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/checkbox/-/checkbox-4.3.0.tgz", + "integrity": "sha1-dHqw7Js4Xdd9MhWlH8mr4l9Vaks=", + "dev": true, + "dependencies": { + "@inquirer/ansi": "^1.0.1", + "@inquirer/core": "^10.3.0", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/confirm/-/confirm-5.1.6.tgz", + "integrity": "sha1-5alZZ2cWhgwmVgszmXs4vWW/lq0=", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.7", + "@inquirer/type": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/core/-/core-10.3.0.tgz", + "integrity": "sha1-NC5P1iy9M+piCJNkJ0mV2+wfL/4=", + "dev": true, + "dependencies": { + "@inquirer/ansi": "^1.0.1", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.21", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/editor/-/editor-4.2.21.tgz", + "integrity": "sha1-n/5kF2ChofdyLDm+ABQwYFN63Mc=", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.3.0", + "@inquirer/external-editor": "^1.0.2", + "@inquirer/type": "^3.0.9" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.21", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/expand/-/expand-4.0.21.tgz", + "integrity": "sha1-OyLrPZlhvbrW7bKpVs/K3BW+kSg=", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/external-editor/-/external-editor-1.0.2.tgz", + "integrity": "sha1-3BbnBkxGxTvgmRjbY5/3gHGMBxo=", + "dev": true, + "dependencies": { + "chardet": "^2.1.0", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.14", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/figures/-/figures-1.0.14.tgz", + "integrity": "sha1-Eqe/00SoOubMXWAEs4ntEfbba+Q=", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.2.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/input/-/input-4.2.5.tgz", + "integrity": "sha1-QP4KS1hcNnCJtX70VdpJgPvFSA8=", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.21", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/number/-/number-3.0.21.tgz", + "integrity": "sha1-+4+sTIvQhHGxBo3In0LWH+OkPKk=", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.21", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/password/-/password-4.0.21.tgz", + "integrity": "sha1-s0IqGWISkPInD5su+O7e2M+F208=", + "dev": true, + "dependencies": { + "@inquirer/ansi": "^1.0.1", + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.3.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/prompts/-/prompts-7.3.2.tgz", + "integrity": "sha1-rQh56zvHg8GbeMQg5e6xign8m0c=", + "dev": true, + "dependencies": { + "@inquirer/checkbox": "^4.1.2", + "@inquirer/confirm": "^5.1.6", + "@inquirer/editor": "^4.2.7", + "@inquirer/expand": "^4.0.9", + "@inquirer/input": "^4.1.6", + "@inquirer/number": "^3.0.9", + "@inquirer/password": "^4.0.9", + "@inquirer/rawlist": "^4.0.9", + "@inquirer/search": "^3.0.9", + "@inquirer/select": "^4.0.9" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/rawlist/-/rawlist-4.1.9.tgz", + "integrity": "sha1-tGQctU4TAEmhO9G3YhrHZsbVMfI=", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/search/-/search-3.2.0.tgz", + "integrity": "sha1-/vN4llWS6fQHzU8feCykDfGz7V4=", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.3.0", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/select/-/select-4.4.0.tgz", + "integrity": "sha1-4Z0ND7/NXLSiDykuYsiKqBVcxtw=", + "dev": true, + "dependencies": { + "@inquirer/ansi": "^1.0.1", + "@inquirer/core": "^10.3.0", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/type/-/type-3.0.9.tgz", + "integrity": "sha1-9/lpbpJ25OGukzJ2evuRmZkuMdk=", + "dev": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha1-s3Znt7wYHBaHgiWbq0JHT79StVA=", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha1-YCFu6kZNhkWXzigyAAc4oFiWUME=", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha1-wETV3MUhoHZBNHJZehrLHxA8QEE=", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha1-hAyIA7DYBH9P8M+WMXazLU7z7XI=", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha1-FPja7G2B5yIdKjV+Zoyrc728p5Q=", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha1-Eyh1q95njH6o1pFTPy5+Irt0Tbo=", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha1-VtwiNo7lcPrOG0mBmXXZuaXq0hQ=", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha1-LVmuOrSzj7QnC/oj0w+OLobH/jI=", + "dev": true, + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha1-/T2x1Z7PfPEh6AZQu4ZxL5tV7O0=", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha1-2ugS/bOCX6MGYJqHFzg8UMNqBTc=", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha1-w1IlhD3493bfIcV1V7wIfp39/Gk=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha1-5F44TkuOwWvOL9kDr3hFD2v37Jg=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha1-zUgi29uEUpJlxaK9tSmjycyVD/w=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha1-i8OS4gTpXf51ZKu+cqQE4o5R9/M=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/console/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha1-tszMI58w/zZglljFpeIpF1fORI8=", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha1-i8OS4gTpXf51ZKu+cqQE4o5R9/M=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha1-Dt7erk0HH1yP/jZ40V86G+CRVr4=", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha1-JNYfVP8feG881Ac7S5RBY4O68qc=", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/environment/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/environment/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha1-ToNs9g6Zxvz6vp+Z0Bfz/dUKY0c=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha1-dqPtsMt1O3Dfv+Iyg1ENPUVDK/I=", + "dev": true, + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha1-T5VBPUdIRU/bF0BL8RQYJ9FeYBE=", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect/node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha1-Aj7+XSaopw8hZ30KGvwPCkTjocY=", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/expect/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/expect/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/expect/-/expect-29.7.0.tgz", + "integrity": "sha1-V4h0WQ3LMhRRQITAgRXYruYeEbw=", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha1-AXk0pm67fs9vIF6EaZvhCv1wRYo=", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha1-ro/sef8kn9WSzoDj7kdOg6bETxI=", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha1-i8OS4gTpXf51ZKu+cqQE4o5R9/M=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/expect/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/expect/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha1-/ZG/H/+xbX0NJKQmqxpHpJiBpWU=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/fake-timers/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/fake-timers/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha1-i8OS4gTpXf51ZKu+cqQE4o5R9/M=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha1-ToNs9g6Zxvz6vp+Z0Bfz/dUKY0c=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/fake-timers/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/fake-timers/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha1-T8tNwuvPCBG+HAT9HLecLbpDHLw=", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha1-jZKQ+exH/3cmB/qGTKHVou+uHU0=", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/globals/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/globals/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha1-ToNs9g6Zxvz6vp+Z0Bfz/dUKY0c=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha1-1TBBR/SaBSkAtLhT3tsRHQgOGZ8=", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern/node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha1-8Xwd45WLZ9/khTVPWhAJMpjypJs=", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha1-BLJi7LO4+qg7Cz0yFiOXI5Po9Mc=", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha1-i8OS4gTpXf51ZKu+cqQE4o5R9/M=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/reporters/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha1-Qwtc6KTgBEp+OBlmMwWnswkcjgM=", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha1-2Quncglc83o0peuUE/G1YqCFVMQ=", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha1-jbmoCqGgl7siYlcmhnNLrtmxZXw=", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha1-bO+XfOHTmDSjrqiHoXJmKKbwcs4=", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha1-3y3Zw0bH13aLigZjmZRkDGQuKEw=", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha1-S1YPZJ/E6RjdCrdc9JYei8iC2Co=", + "dev": true + }, + "node_modules/@jest/transform/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/transform/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha1-ETH4z2NOfoTF53urEvBSr1hfulk=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha1-Y0Khn0Q0dRjJPkOxrGnes8Rlah8=", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha1-eg7mAfYPmaIMfHxf8MgDiMEYm9Y=", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha1-shg1y9Nttla4V8KtAuvUE8wTqbo=", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha1-aRKwDSxjHA0Vzhp6tXzWV/Ko+Lo=", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha1-2xXWeByTHzolGj2sOVAcmKYIL9A=", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha1-z46p3LhJuByV8U/AqqFRxrVNJXg=", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha1-jZnH9n6vck00KN/ZgmxkVSZqXIM=", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/codegen": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", + "integrity": "sha1-XCP3lsR2dfFm0juUjNuIkYS5Mgc=", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.21.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz", + "integrity": "sha1-k/jdV/46OpITKzPR6xgtzZ52Kfo=", + "dev": true, + "peer": true, + "dependencies": { + "@jsonjoy.com/base64": "^1.1.2", + "@jsonjoy.com/buffers": "^1.2.0", + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/json-pointer": "^1.0.2", + "@jsonjoy.com/util": "^1.9.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pointer": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", + "integrity": "sha1-BJy1MKwk6Ey6CFkMXja0McSENAg=", + "dev": true, + "peer": true, + "dependencies": { + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/util": "^1.9.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jsonjoy.com/util/-/util-1.9.0.tgz", + "integrity": "sha1-fulVhq7Qp2a3Rs2Ng2PjNsPEfEY=", + "dev": true, + "peer": true, + "dependencies": { + "@jsonjoy.com/buffers": "^1.0.0", + "@jsonjoy.com/codegen": "^1.0.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@kolkov/angular-editor": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@kolkov/angular-editor/-/angular-editor-2.1.0.tgz", + "integrity": "sha1-At1bql7uWF2OCx1c06kf+m7146c=", + "dev": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">=14", + "@angular/core": ">=14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha1-T8VsFcWAua233DwzOhNOVAtEv7E=", + "dev": true, + "peer": true + }, + "node_modules/@listr2/prompt-adapter-inquirer": { + "version": "2.0.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.18.tgz", + "integrity": "sha1-8b/5DyASaZFAI7F8s4PI/r1ih/I=", + "dev": true, + "dependencies": { + "@inquirer/type": "^1.5.5" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@inquirer/prompts": ">= 3 < 8" + } + }, + "node_modules/@listr2/prompt-adapter-inquirer/node_modules/@inquirer/type": { + "version": "1.5.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@inquirer/type/-/type-1.5.5.tgz", + "integrity": "sha1-MD6gTOetLlhbkhtmKzvjbve08Js=", + "dev": true, + "dependencies": { + "mute-stream": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@listr2/prompt-adapter-inquirer/node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha1-4xvZ/mLwrtI1IKpDJOpmcVMeAT4=", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "3.2.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.2.6.tgz", + "integrity": "sha1-XeQZ6blbp6paAwWkUeICvkHddsA=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "3.2.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.2.6.tgz", + "integrity": "sha1-HioGb0m0VEEe13ilie5XpgUYUd8=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "3.2.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.2.6.tgz", + "integrity": "sha1-pKq8M237su/a1skeOalb7Olvp70=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.2.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.2.6.tgz", + "integrity": "sha1-QsTGfdZ9pihg+Pt91X6RcfQHwdI=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "3.2.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.2.6.tgz", + "integrity": "sha1-g/tmlgbr5idZFaBvLKLjTSzhZk4=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "3.2.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.2.6.tgz", + "integrity": "sha1-cp8gNd3vGXUnmzMpUy9cH4bJGRg=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha1-nt7GGyLDCCAYp59tHDAond89nRE=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha1-M2d6J1IEiYrYrL9ic0/E3AtqSFU=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha1-lPsFQ7ouKHZsP8Q5yrvgRArnAVk=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha1-Ge33zcLnBj7jKEA8HYlaht0o9Ls=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha1-SgYJq1/kTQfJxgoR5EhNPDi71uM=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha1-CqVQLVR7V6v8SsSS3mjiAG5BckI=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@napi-rs/nice": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice/-/nice-1.1.1.tgz", + "integrity": "sha1-warNYx7NTFAMlZ4+fP7dXHO//io=", + "dev": true, + "optional": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/nice-android-arm-eabi": "1.1.1", + "@napi-rs/nice-android-arm64": "1.1.1", + "@napi-rs/nice-darwin-arm64": "1.1.1", + "@napi-rs/nice-darwin-x64": "1.1.1", + "@napi-rs/nice-freebsd-x64": "1.1.1", + "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", + "@napi-rs/nice-linux-arm64-gnu": "1.1.1", + "@napi-rs/nice-linux-arm64-musl": "1.1.1", + "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", + "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", + "@napi-rs/nice-linux-s390x-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-musl": "1.1.1", + "@napi-rs/nice-openharmony-arm64": "1.1.1", + "@napi-rs/nice-win32-arm64-msvc": "1.1.1", + "@napi-rs/nice-win32-ia32-msvc": "1.1.1", + "@napi-rs/nice-win32-x64-msvc": "1.1.1" + } + }, + "node_modules/@napi-rs/nice-android-arm-eabi": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", + "integrity": "sha1-Tr2WaCHNbCzHzAIOtGjeOXu5tA8=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-android-arm64": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", + "integrity": "sha1-4YO6h0USvABYUtqri3jGPgpCiKg=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-arm64": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", + "integrity": "sha1-ZLFYWAl3TLuL+VzqPUyIJ8mJc5Q=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-x64": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", + "integrity": "sha1-mcDH9iyx4jynaIG7KcxgAK7MxvA=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-freebsd-x64": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", + "integrity": "sha1-mlyg487YYgeIfJilpWDejN5akJ4=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", + "integrity": "sha1-uKahvIjQ3j6ZrD/eppmA3G4gtQI=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-gnu": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", + "integrity": "sha1-Im8e8w/LgPpANw6EO3XMhuOeEYM=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-musl": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", + "integrity": "sha1-ATRcPbeSELpUBshyno23XtEcXxQ=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-ppc64-gnu": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", + "integrity": "sha1-znoQJSJ9qrSR3tQHhLVhOU1oj8s=", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-riscv64-gnu": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", + "integrity": "sha1-m+9dyJoEJdAxY4U7SWjbtobZj9U=", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-s390x-gnu": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", + "integrity": "sha1-JHyMfEWHaHe9szfP6ykP9P2C3mI=", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-gnu": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", + "integrity": "sha1-f9H14DfLRKtPX5WjsyJameMkjxI=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-musl": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", + "integrity": "sha1-1EfNcVeuXaXAsV/GGL9h8MNE/28=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-openharmony-arm64": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", + "integrity": "sha1-ESDkV9LMayvIbvCml/rv4uGU384=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-arm64-msvc": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", + "integrity": "sha1-keTP7PM5tD+nk08MixnQT0zdm8A=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-ia32-msvc": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", + "integrity": "sha1-7ZMAu6B00+OwoHfWsVfytP9wrw4=", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-x64-msvc": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", + "integrity": "sha1-gpK4L7RkWGGMz/W4Ew94l0NJVB4=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@ng-select/ng-select": { + "version": "14.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@ng-select/ng-select/-/ng-select-14.9.0.tgz", + "integrity": "sha1-j58J03vYVvF90K8G8cSFEIsYBlg=", + "dev": true, + "peer": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">= 18", + "npm": ">= 8" + }, + "peerDependencies": { + "@angular/common": "^19.0.0", + "@angular/core": "^19.0.0", + "@angular/forms": "^19.0.0" + } + }, + "node_modules/@ngrx/effects": { + "version": "19.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@ngrx/effects/-/effects-19.2.1.tgz", + "integrity": "sha1-6e5xTet/iWO31LIr8h4GssaAyuk=", + "dev": true, + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/core": "^19.0.0", + "@ngrx/store": "19.2.1", + "rxjs": "^6.5.3 || ^7.5.0" + } + }, + "node_modules/@ngrx/operators": { + "version": "19.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@ngrx/operators/-/operators-19.2.1.tgz", + "integrity": "sha1-aZVvnyNkiuLnMkBiMpejBkGNafM=", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@ngrx/store": { + "version": "19.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@ngrx/store/-/store-19.2.1.tgz", + "integrity": "sha1-hZnP3RZxWJUuetuoXieQd3oOUKY=", + "dev": true, + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/core": "^19.0.0", + "rxjs": "^6.5.3 || ^7.5.0" + } + }, + "node_modules/@ngtools/webpack": { + "version": "19.2.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@ngtools/webpack/-/webpack-19.2.18.tgz", + "integrity": "sha1-EqNwAKUwD6NlnJdUTi3n5DD9308=", + "dev": true, + "peer": true, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^19.0.0 || ^19.2.0-next.0", + "typescript": ">=5.5 <5.9", + "webpack": "^5.54.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha1-dhnC6yGyVIP20WdUi0z9WnSIw9U=", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha1-W9Jir5Tp0lvR5xsF3u1Eh2oiLos=", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha1-6Vc36LtnRt3t9pxVaVNJTxlv5po=", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/agent": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@npmcli/agent/-/agent-3.0.0.tgz", + "integrity": "sha1-FoWx+9Sht7tPkwy7aM6AHt/nqkQ=", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha1-mosfJGhmwChQlIZYX2K48sGMJw4=", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha1-QQ/IoXtw5ZgBPfJXwkRrfzOD8Rk=", + "dev": true + }, + "node_modules/@npmcli/fs": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@npmcli/fs/-/fs-4.0.0.tgz", + "integrity": "sha1-oesa7d79Kko0fsoPqzC8YsDhwPI=", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/git": { + "version": "6.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@npmcli/git/-/git-6.0.3.tgz", + "integrity": "sha1-lmy7IoUUNyh33lJE2yhbGZg286o=", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^8.0.0", + "ini": "^5.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^10.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha1-SkB+K9eN37FL6gwnxvcHLd53Xw0=", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha1-QQ/IoXtw5ZgBPfJXwkRrfzOD8Rk=", + "dev": true + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/which/-/which-5.0.0.tgz", + "integrity": "sha1-2T8tk/eYNNQ2PH0MI+ANB8RmyNY=", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@npmcli/installed-package-contents/-/installed-package-contents-3.0.0.tgz", + "integrity": "sha1-LBFw/09w9orxJeKELhhTqTIj5NE=", + "dev": true, + "dependencies": { + "npm-bundled": "^4.0.0", + "npm-normalize-package-bin": "^4.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@npmcli/node-gyp/-/node-gyp-4.0.0.tgz", + "integrity": "sha1-AfkAuuYvDyf5paEntA1EPd+51MY=", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "6.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@npmcli/package-json/-/package-json-6.2.0.tgz", + "integrity": "sha1-fH5h5Gbu/fcpy4ejTDrcFdduL5c=", + "dev": true, + "dependencies": { + "@npmcli/git": "^6.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^8.0.0", + "json-parse-even-better-errors": "^4.0.0", + "proc-log": "^5.0.0", + "semver": "^7.5.3", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/glob/-/glob-10.4.5.tgz", + "integrity": "sha1-9NnwuQ/9urCcnXf18ptCYlF7CVY=", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "8.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@npmcli/promise-spawn/-/promise-spawn-8.0.3.tgz", + "integrity": "sha1-CMXkwcq3/4SORC5LGbvw7mmdEz8=", + "dev": true, + "dependencies": { + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha1-SkB+K9eN37FL6gwnxvcHLd53Xw0=", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/which/-/which-5.0.0.tgz", + "integrity": "sha1-2T8tk/eYNNQ2PH0MI+ANB8RmyNY=", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/redact": { + "version": "3.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@npmcli/redact/-/redact-3.2.2.tgz", + "integrity": "sha1-SmdF4K4mkSCtIjeAzjdNbFmuNM0=", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "9.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@npmcli/run-script/-/run-script-9.1.0.tgz", + "integrity": "sha1-YWjCvkcD/l7TGssIohUctiDtMKQ=", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^4.0.0", + "@npmcli/package-json": "^6.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "node-gyp": "^11.0.0", + "proc-log": "^5.0.0", + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha1-SkB+K9eN37FL6gwnxvcHLd53Xw0=", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/which/-/which-5.0.0.tgz", + "integrity": "sha1-2T8tk/eYNNQ2PH0MI+ANB8RmyNY=", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha1-NCUHqc+q8XJHmogjCd7x6ZH7EgA=", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha1-UH+DbX4gQveYx9B60Zw1RvmEisE=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha1-PSbc443mWQ73nEfsLFV5PAatT2c=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha1-mfOvOGkGnM93Tk3fzPfmT9IxHvg=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha1-FNaFd0Gp9R3+UdWwi3yK/bxzrZs=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha1-Q8MkbWiSOB20c7tPZjIprSC2CaE=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha1-ZjdQ9wkLtieNIhDeZD64o/eA0I4=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha1-umDh9Wl39+R81+Ma1l0V/cvQfjA=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha1-9/vN/y8ExSb5bqwB+XQZpqmYVdI=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha1-TS6g9jPrGRfYPUgzks5hgbapLk4=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha1-J3s0awXbVPVWVzAd13vfmdY2Bu4=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha1-fp4ComeE1HUD3h0Q6Oq2zOtSQkM=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha1-LQ+U+lmoc83FhL9/ax3GKN35duY=", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha1-rlJpMllmS6byIo+mHX7kS2TqCUc=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true, + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/@parcel/watcher/node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha1-Grpmk7DyVSWKBJ1iEykykyKq1Vg=", + "dev": true, + "optional": true + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha1-p36nQvqyV3UUVDTrHSMoz1ATrDM=", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha1-++eE4paC6btt7ijqdaGoNwLnuAU=", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha1-V7obDL2o56PFl6SFPIB7FW4hp7Q=", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", + "integrity": "sha1-cx3yff23cYlUe875atp78Wa7svs=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", + "integrity": "sha1-S+ptt44faSdAXff+D68vUJXgE0M=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", + "integrity": "sha1-p6q3fUS+PESiD5RuEBYPhOVFDn8=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", + "integrity": "sha1-xXLAJLV+6N3RsIUXA6zp62zA3YI=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", + "integrity": "sha1-z3T4ETtagwmKXAJsFldCJ3y/uIs=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", + "integrity": "sha1-OVYfOi8gGkrWoBQlsf9ZKBVOzXw=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", + "integrity": "sha1-mA1gYeNzv9rrZ5JcRtL4+bPeU38=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", + "integrity": "sha1-+RqQ8w3ADVpkrC2bvtyCnNPPqng=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", + "integrity": "sha1-+scA+lw4vBOg1dNEYxMwk9pMkqA=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", + "integrity": "sha1-9Q7Mz4x4hB/23xcGvEeC1/Yr+cM=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", + "integrity": "sha1-duoDi1ScXGxfDQYpQmJ8QGZkLuI=", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", + "integrity": "sha1-WGncCygkLaZVPitSr0E3T0A4zW4=", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", + "integrity": "sha1-XN2fhRzhvqM9aESmn5V03jNfILE=", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", + "integrity": "sha1-2aTD8KNJK8ePb9/oExrGHHNZzNU=", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", + "integrity": "sha1-713Df0OI9SU/De9D4UQOwBKvIE0=", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", + "integrity": "sha1-vaPrZ+HJk8G6ErycL2lOdwOVjZ8=", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", + "integrity": "sha1-fbw8y8vPs+Zb50U437bo3RYXj94=", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", + "integrity": "sha1-V4P8CtyrfcBpaSBW6MqNg3CYVc4=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", + "integrity": "sha1-ALbCmymBl6OE48ZZkQtHlDADpng=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", + "integrity": "sha1-hdDfcjNzTfMeVHweZH0qUwCzvzA=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", + "integrity": "sha1-y/7gHx/nN5HDUZGgU5eDhSDKPN0=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", + "integrity": "sha1-lc29/0j+bJSKvPah1QCyvVzjP2I=", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", + "integrity": "sha1-GiKs/JPGSmSkjEJnLoV+5Rd00NM=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", + "integrity": "sha1-TNss+uac23saPMWHeOggQIB16Sg=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/wasm-node": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/wasm-node/-/wasm-node-4.52.5.tgz", + "integrity": "sha1-JUsWsLDMNMSSqCBwICO72aLB94Y=", + "dev": true, + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha1-kn3S+um8M2FAOsLHoAwy3c6a1+g=", + "dev": true + }, + "node_modules/@schematics/angular": { + "version": "19.2.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@schematics/angular/-/angular-19.2.18.tgz", + "integrity": "sha1-sUyZU8MRJyHSClHT9EG42P6VpoY=", + "dev": true, + "dependencies": { + "@angular-devkit/core": "19.2.18", + "@angular-devkit/schematics": "19.2.18", + "jsonc-parser": "3.3.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@sigstore/bundle": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sigstore/bundle/-/bundle-3.1.0.tgz", + "integrity": "sha1-dPjzeHFIQA3dNkvoqakhIXTGZkY=", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.4.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/core": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sigstore/core/-/core-2.0.0.tgz", + "integrity": "sha1-+Iio5Mj9qieEhRSigZILb9jsqVU=", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.4.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sigstore/protobuf-specs/-/protobuf-specs-0.4.3.tgz", + "integrity": "sha1-XZdOsWwKHUSj8K9uPnIZs1rFeVM=", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sigstore/sign/-/sign-3.1.0.tgz", + "integrity": "sha1-XQmNTStZonnprJtRx5QQTNoMZJ4=", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^3.1.0", + "@sigstore/core": "^2.0.0", + "@sigstore/protobuf-specs": "^0.4.0", + "make-fetch-happen": "^14.0.2", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "3.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sigstore/tuf/-/tuf-3.1.1.tgz", + "integrity": "sha1-sBsmEoj2RuDaV3N3gok+fSaVxS4=", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.4.1", + "tuf-js": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "2.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sigstore/verify/-/verify-2.1.1.tgz", + "integrity": "sha1-9ncwASzUdPWVBEw3F/MqwqHp0rw=", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^3.1.0", + "@sigstore/core": "^2.0.0", + "@sigstore/protobuf-specs": "^0.4.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha1-Zmf6wWxDa1Q0o4ejTe2wExmPbm4=", + "dev": true + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha1-cZ33+0F2a8FDNp6qDdVtjch8mVg=", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha1-ECk1fkTKkBphVYX20nc428iQhM0=", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha1-Vf3/Hsq581QBkSna9N8N1Nkj6mY=", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha1-9UShSNOrNYAcH2M6dEH9h8LkhL8=", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha1-buRkAGhfEw4ngSjHs4t+Ax/1svI=", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha1-7j3vHyfZ7WbaxuRqKVz/sBUuBY0=", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha1-5DhjFihPALmENb9A9y91oJ2r9sE=", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha1-C5LcwMwcgfbzBqOB8o4xsaVlNuk=", + "dev": true + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha1-pS9ho9c3SDP8qUWyVJvDCi3UDQo=", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@tufjs/models/-/models-3.0.1.tgz", + "integrity": "sha1-Wuu3guu54G8HGueDHB81tGKwMZw=", + "dev": true, + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha1-PfFfJ7qFMZyqB7oI0HIYibs5wBc=", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha1-tYGSlMUReZV6+uw0FEL5NB5BCKk=", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha1-VnJRNwHBshmbxtrWNqnXSRWGdm8=", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha1-B9cT1szg0mXJhJ2wy+YtP2Hzb3Q=", + "dev": true, + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha1-GFm+u4/X2smRikXVTBlxq4ta9HQ=", + "dev": true, + "peer": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha1-rfkM4aEF6B3R+cYf3Fr9ob+5KVY=", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/caseless": { + "version": "0.12.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/caseless/-/caseless-0.12.5.tgz", + "integrity": "sha1-25RoyxsbWpJbjzSCLxZp3wxUcvU=", + "dev": true + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha1-W6fzvE+73q/43e2VLl/yzFP42Fg=", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha1-fecWRaEDBWtIrDzgezUguBnB1bM=", + "dev": true, + "peer": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha1-1Xla1zLOgXFfJ/ddqRMASlZ1FYQ=", + "dev": true, + "peer": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha1-MQi9XxiwzbJ3yGez3UScntcHmsU=", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha1-lYuRyZGxhnztMYvt6g4hXuBQcm4=", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/express/-/express-4.17.25.tgz", + "integrity": "sha1-BwyMc6b+5pNtZcGV27+32lAmZJs=", + "dev": true, + "peer": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", + "integrity": "sha1-8dMG3MA7Gq+/trT+aEzOijHP/BA=", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha1-Kga8D2iiCrN7PjaqI4vmq99J6LQ=", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha1-W3SasrFroRNCP+saZKldzTA5hHI=", + "dev": true, + "peer": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.17", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha1-2eLEVx/jUHNDyyEM1BeQN15ZpTM=", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha1-dznCMqH+6bTTzomF8xTAxtM1Sdc=", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha1-UwR2FK5y4Z/AQB2HLeOuK0zjUL8=", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha1-DwPj0vZw+9rFhuNLQzeDBwzBb1Q=", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha1-XoWuVoAGcS5K1m8lQz6b2siAHx0=", + "dev": true, + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/jsdom": { + "version": "20.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/jsdom/-/jsdom-20.0.1.tgz", + "integrity": "sha1-B8FLwZvS+RjBkpVBzarK6JR0SAg=", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha1-WWoXRyM2lNUPatinhp/Lb1bPWEE=", + "dev": true, + "peer": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.17.20", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha1-HKdzYdc2NDLSn15VlQ2eweHG6pM=", + "dev": true + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha1-ZfbR5fgFOap8+/yWLeXe8M9PNBs=", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha1-HvMC4Bz30rWg+lJnkMkSO/HQZpA=", + "dev": true, + "peer": true + }, + "node_modules/@types/node": { + "version": "18.19.130", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/node/-/node-18.19.130.tgz", + "integrity": "sha1-2kxjJHk6ed77emLLo5R+xa3QDVk=", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.14", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/node-forge/-/node-forge-1.3.14.tgz", + "integrity": "sha1-AGwmFszWVVBWDCdX2EcuttPs6gs=", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha1-WVDlCWB5MFWEXpVsQn/CsNcMUjk=", + "dev": true + }, + "node_modules/@types/q": { + "version": "0.0.32", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha1-2LYM7PYvLbD7aOXgBgd7kXi4XeU=", + "dev": true, + "peer": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha1-UK5DU+qt3AQEQnmBL1LIxlhX28s=", + "dev": true, + "peer": true + }, + "node_modules/@types/request": { + "version": "2.48.13", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/request/-/request-2.48.13.tgz", + "integrity": "sha1-q99CVlJOgB6o/dpUMg8IPttaa4A=", + "dev": true, + "dependencies": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.5" + } + }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha1-7SeaZPpDi7afJIDtpEk3kSu3SAo=", + "dev": true, + "peer": true + }, + "node_modules/@types/selenium-webdriver": { + "version": "3.0.26", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", + "integrity": "sha1-/H2H1YCv+i5SaFsuiBvCAYGaWDY=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/send/-/send-1.2.1.tgz", + "integrity": "sha1-anhORVQ8GMd0wEm/9tPbrwRcnHQ=", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha1-5q4T1QU8sG7TY5IRC0+aSaxOyJg=", + "dev": true, + "peer": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha1-doFpFFp3j49d/LY2CurUFKOZT+4=", + "dev": true, + "peer": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/send/-/send-0.17.6.tgz", + "integrity": "sha1-rrU4W+Yv9YpSzVRZ2qUJrpFlHSU=", + "dev": true, + "peer": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha1-zjIs8HvMEZ1Mv3+IlU86O9D2dTU=", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha1-YgkyHrLBcSp+dGZCK4yx/A2d1dg=", + "dev": true + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha1-y24qaRtwyxd8bjrpwdLosuqM0wQ=", + "dev": true + }, + "node_modules/@types/uuid": { + "version": "3.4.13", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/uuid/-/uuid-3.4.13.tgz", + "integrity": "sha1-/okOUX+4QGIL4oTuIT6B1wKx92s=", + "dev": true + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha1-SEZOS/Ld/RfbE9hFRn9gcP/qSqk=", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.34", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/yargs/-/yargs-17.0.34.tgz", + "integrity": "sha1-HC+WNbcdVAGCc3OgHOLop2cOqDk=", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha1-gV4wt4bS6PDc2F/VvPXhoE0AjxU=", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.46.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz", + "integrity": "sha1-3Eq5PuPX5sjjiCCg1sfJPHGD4tw=", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/type-utils": "8.46.2", + "@typescript-eslint/utils": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.46.2", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.46.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@typescript-eslint/parser/-/parser-8.46.2.tgz", + "integrity": "sha1-3ZONRdWBrI/6nYpBilAoKzBvfr8=", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.46.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@typescript-eslint/project-service/-/project-service-8.46.2.tgz", + "integrity": "sha1-qy8CoN5NpqfuuIWvXgWb5XgZ1gg=", + "dev": true, + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.46.2", + "@typescript-eslint/types": "^8.46.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.46.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@typescript-eslint/scope-manager/-/scope-manager-8.46.2.tgz", + "integrity": "sha1-fTffJJPEBEUFiayztdDGnMBnCog=", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.46.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.2.tgz", + "integrity": "sha1-0RBFHLk7vRiYZSBuo372d8GWgow=", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.46.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@typescript-eslint/type-utils/-/type-utils-8.46.2.tgz", + "integrity": "sha1-gC0CeGTm+3UuZUJe0J8+CJ+004Q=", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/utils": "8.46.2", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.46.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@typescript-eslint/types/-/types-8.46.2.tgz", + "integrity": "sha1-K61zSFEbMebkJXmCDmK3MUVjV2M=", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.46.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.2.tgz", + "integrity": "sha1-q1R6J+QiK7ajKBy36YcFJy4sfQg=", + "dev": true, + "dependencies": { + "@typescript-eslint/project-service": "8.46.2", + "@typescript-eslint/tsconfig-utils": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.46.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@typescript-eslint/utils/-/utils-8.46.2.tgz", + "integrity": "sha1-sxPTPWf5kYWDryBb17zr8g8jFzI=", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.46.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.2.tgz", + "integrity": "sha1-gD+imJSMOaz4EK8hvc5vi6v6lzg=", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha1-TP6mD+fdCtjoFuHtAmwdUlG1EsE=", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha1-0Gu7OE689sUF/eHD0O1N3/4Kr/g=", + "dev": true + }, + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.2.0.tgz", + "integrity": "sha1-lJD+FbiDM1GYL74JY5h/afQPUBk=", + "dev": true, + "engines": { + "node": ">=14.21.3" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha1-qfagfysDyVyNOMRTah/ftSH/VbY=", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha1-/Moe7dscxOe27tT8eVbWgTshufs=", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha1-4KFhUiSLw42u523X4h8Vxe86sec=", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha1-giqbxgMWZTH31d+E5ntb+ZtyuWs=", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha1-29kyVI5xGfS4p4d/1ajSDmNJCy0=", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha1-5VYQh1j0SKroTIUOWTzhig6zHgs=", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha1-lindqcRDDqtUtZEFPW3G87oFA0g=", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha1-HF6qzh1gatosf9cEXqk1bFnuDbo=", + "dev": true, + "peer": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha1-V8XD3rAQXQLOJfo/109OvJ/Qu7A=", + "dev": true, + "peer": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha1-kXog6T9xrVYClmwtaFrgxsIfYPE=", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha1-rGaJ9QIhm1kZjd7ELc1JaxAE1Zc=", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha1-mR5/DAkMsLtiu6yIIHbj0hnalXA=", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha1-5vce18yuRngcIGAX08FMUO+oEGs=", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha1-s+E/GJNgXKeLUsaOVM9qhl+Qufs=", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha1-O7PpY4qK5f2vlhDnoGtNn5qm/gc=", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha1-7vAUoxRa5Hehy8AM0eVSM23Ot5A=", + "dev": true, + "peer": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha1-0pHGpOl5ibXGHZrPOWrk/hM6cY0=", + "dev": true, + "peer": true + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha1-53qX+9NFt22DJF7c0X05OxtB+zE=", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/abab/-/abab-2.0.6.tgz", + "integrity": "sha1-QbgPLIcdGWhiFrgjCSMc/Tyz0pE=", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true + }, + "node_modules/abbrev": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha1-isiztQJNMUZP4qX+7qn0U2v0QCU=", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha1-C/C+EltnAUrcsLCSHmLbe//hay4=", + "dev": true, + "peer": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha1-WOMjpy/twNb5zU0x/kn1FHlZDM0=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha1-o2CJi8QV7arEbIJB9jg5dbkwuBY=", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha1-Db8FxE+nyUMykUwCBm1b7/YsQMM=", + "dev": true, + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha1-ftW7VZCLOy8bxVxq8WU7rafweTc=", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha1-eU3RacOXft9LpOpHWDWHxYZiNrc=", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha1-/EoP0ID30QRx8wpzIPJVYK3ijJk=", + "dev": true, + "peer": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha1-i1yzi1w0qaAY7h/A5qBm0d/MUow=", + "dev": true, + "peer": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.16", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha1-C15Md58H3t6lgFzcyxFHBx2UqQk=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha1-48121MVI7oldPD/Y3B9sW5Ay56g=", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha1-N9mlx3ava8ktf0+VEOukwKYNEaY=", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha1-PV3HYryhdnnDwup+kK1rdTIwlXg=", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha1-adTThaRzPNvqtElkoRcKiPh/DhY=", + "dev": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha1-N2ETQOsiQ+cMxgTK011jJw1IeBs=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha1-ayKR0dt9mLZSHV8e+kLQ86n+tl4=", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha1-0mCiSwGYQ24TP6JqUkptZfo7Ljc=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha1-afvE1sy+OD+XNpNK40w/gpDxv0E=", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "peer": true, + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha1-CCyyyJyf6GWaMRpTvWpNxTAdswQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha1-eQxYsZuhcgqEIFtXxhjVrYUklz4=", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha1-OH8Ok/XUUoA3PTh6WdNMltsyGWM=", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/arg/-/arg-4.1.3.tgz", + "integrity": "sha1-Jp/HrVuOQstjyJbVZmAXJhwUQIk=", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha1-JG9Q88p4oyQPbJl+ipvR6sSeSzg=", + "dev": true + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha1-k/gaQ0gOM6M48ZFjo9EKUMAdzVk=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha1-OE0So3KVrsN2mrAirTI6GKUcz4s=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true, + "peer": true + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha1-HwzKoI6Qzbw+tDMhD5A60PF8Pzo=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha1-z6EGXIHctk40VXybgdAS9qQhxWQ=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha1-U0qvnm6N15+2uamRf4Oe8exjr+U=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha1-cSzHkq5wNwrkBYYmRinjOqtd04s=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha1-nXYNhNvdBtDL+SyISWFaGnqzGDw=", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha1-DTp7tuZOAqkMAwOzHykoaOoJoI0=", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha1-UJyfymDq+FA0xoKYOBiOTkyP+ys=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha1-XK7BTUOXbvQuMty0vWKHjpa+Wzs=", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha1-pcw3XWoDwu/IelU/PgsVIt7xSEY=", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha1-CqFnIWllrJR0zPqDiSz7az4eUu8=", + "dev": true + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha1-KHaMdtDjz/IbxiqeLQtqwwBCoe4=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha1-9DaZGSJbaExWCFmYrGPb0FvgINU=", + "dev": true, + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-loader": { + "version": "9.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha1-BMeDXbFsJG3Rm6CRRBjzk3eXWHs=", + "dev": true, + "peer": true, + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha1-+ojsWSMv2bTjbbvFQKjsmptH2nM=", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha1-0QyIhcISVXThwjHKyt+VVnXhzj0=", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha1-VW0u+GiRRuRtzqS/3QlfNDTf/LQ=", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha1-qtvpQ0ZBgqiSLDySfDBn/0DSRiY=", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.14", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha1-gQG4K3acVog1YRVCSI1GM5XC748=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha1-VW0u+GiRRuRtzqS/3QlfNDTf/LQ=", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.11.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", + "integrity": "sha1-Tk4YLxuzfHumLir4HY3QnfMTRPY=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.3", + "core-js-compat": "^3.40.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha1-MnUuOKtvZ2e5JlA0e/JqMbFq6MU=", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha1-IHMNbNx92l2JQByrEKxqMgZ6zeY=", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha1-+gX6UQ59STiW17DdIDNgHIQPFxw=", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4=", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha1-GxtEAWClv3rUC2UPCVljSBkDkwo=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.20", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/baseline-browser-mapping/-/baseline-browser-mapping-2.8.20.tgz", + "integrity": "sha1-Z2bPJw82aNILZxK5xUzJEbh9pxQ=", + "dev": true, + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true, + "peer": true + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/beasties": { + "version": "0.3.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/beasties/-/beasties-0.3.2.tgz", + "integrity": "sha1-wPftE2Lf8O6PnESLzRsdb+Fsxgk=", + "dev": true, + "dependencies": { + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "htmlparser2": "^10.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.49", + "postcss-media-query-parser": "^0.2.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/bent": { + "version": "7.3.12", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/bent/-/bent-7.3.12.tgz", + "integrity": "sha1-4KJ3XUQl52dMZLeLJCr09J2msDU=", + "dev": true, + "dependencies": { + "bytesish": "^0.4.1", + "caseless": "~0.12.0", + "is-stream": "^2.0.0" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha1-9uFKl4WNMnJSIAJC1Mz+UixEVSI=", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/bl/-/bl-4.1.0.tgz", + "integrity": "sha1-RRU1JkGCvsL7vIOmKrmM8R2fezo=", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/blocking-proxy": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha1-gdb9H+E6TA1pV99/kbdemNrEDLI=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "blocking-proxy": "built/lib/bin.js" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha1-GVNDEiHG+1zWPEs21T+rCSjlSMY=", + "dev": true, + "peer": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/debug/-/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", + "dev": true, + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "peer": true + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/qs/-/qs-6.13.0.tgz", + "integrity": "sha1-bKO9WEOffiRWVXmJl3h7DYilGQY=", + "dev": true, + "peer": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/bonjour-service": { + "version": "1.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha1-gNhnQwtaDaZOgqgEf8HjVb23FyI=", + "dev": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha1-VPxTI3phPYVMe9N0Y6rRffhyFOc=", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/braces/-/braces-3.0.3.tgz", + "integrity": "sha1-SQMy9AkZRSJy1VqEgK3AxEE1h4k=", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.27.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/browserslist/-/browserslist-4.27.0.tgz", + "integrity": "sha1-dVZUdE/q6Xj7sSNxiy8Tm8D6Zpc=", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "baseline-browser-mapping": "^2.8.19", + "caniuse-lite": "^1.0.30001751", + "electron-to-chromium": "^1.5.238", + "node-releases": "^2.0.26", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/browserstack": { + "version": "1.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/browserstack/-/browserstack-1.6.1.tgz", + "integrity": "sha1-4FH5cz7DtQdlnzlcekdlobHjWLM=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "https-proxy-agent": "^2.2.1" + } + }, + "node_modules/browserstack/node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha1-gWXwHENgCbzK0LHRIvBe13Dvxu4=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/browserstack/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/debug/-/debug-3.2.7.tgz", + "integrity": "sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/browserstack/node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha1-TuenN6vZJniik9mzShr00NCMeHs=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha1-6302UwenLPl0zGzadraDVK0za9g=", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/bser/-/bser-2.1.1.tgz", + "integrity": "sha1-5nh9og7OnQeZhTPP2d5vXDj0vAU=", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha1-umLnwTEzBTWCGXFghRqPZI6Z7tA=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha1-KxRqb9cugLT1XSVfNe1Zo6mkG9U=", + "dev": true + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha1-87lrNBYNZDGhnXaIE1r3z7h5eIk=", + "dev": true, + "peer": true, + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha1-iwvuuYYFrfGxKPpDhkA8AJ4CIaU=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytesish": { + "version": "0.4.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/bytesish/-/bytesish-0.4.4.tgz", + "integrity": "sha1-87U1oPEVN0dCeu4nJWdIz/kjR+Y=", + "dev": true + }, + "node_modules/cacache": { + "version": "19.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cacache/-/cacache-19.0.1.tgz", + "integrity": "sha1-M3DMKKdYQ0yFwlhQCL1b3P8X1s0=", + "dev": true, + "dependencies": { + "@npmcli/fs": "^4.0.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "tar": "^7.4.3", + "unique-filename": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/cacache/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha1-mFXmTs0kCpzEJnzopKpdJKHaFeQ=", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/glob/-/glob-10.4.5.tgz", + "integrity": "sha1-9NnwuQ/9urCcnXf18ptCYlF7CVY=", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha1-QQ/IoXtw5ZgBPfJXwkRrfzOD8Rk=", + "dev": true + }, + "node_modules/cacache/node_modules/tar": { + "version": "7.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tar/-/tar-7.5.1.tgz", + "integrity": "sha1-dQqL1jt8RMGEjnv5giYKCDz3R8k=", + "dev": true, + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cacache/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha1-AOLeRDY57Q14/YfeDSdGn7z/tTM=", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha1-BzapZg9TfjOIgm9EDV7EX3ROqkw=", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha1-S1QowiK+mF15w9gmV0edvgtZstY=", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha1-I43pNdKippKSjFOMfM+pEGf9Bio=", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001751", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha1-2s1dn0uu6oQWQWQBOdKypN9CJq0=", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha1-P3PCv1JlkfV0zEksUeJFY0n4ROQ=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha1-10Q1giYhf5ge1Y9Hmx1rzClUXc8=", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chardet": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha1-EAf0QaGun5GZpKZ/bpePsKqao/4=", + "dev": true + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha1-e+N6TAPJruHs/oYqSiOyxwwgXTA=", + "dev": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha1-Fb++U9LqtM9w8YqM1o6+Wzyx3s4=", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha1-Bb/9f/koRlCTMUcIyTvfqb0fD1s=", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha1-Z6npZL4xpR4V5QENWObxKDQAL0Y=", + "dev": true + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha1-D3lzHrjP4exyrNQGbvrJ1hmRsA0=", + "dev": true + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha1-JKSDHs9aawHd6zL7caSyCIsNzjg=", + "dev": true, + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha1-F3Oo9LnE1qwxVj31Oz/B15Ri/kE=", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha1-bMKKKST+6eJc6R6XPbVscGbmFyo=", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha1-QtqsQdPCVO84rYrAN2chMBc2kcU=", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha1-DASwddsCy/5g3I5s8vVIaxo2CKo=", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", + "dev": true + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha1-JpxxF9J7Ba0uU2gwqOyJXvnG0BA=", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha1-Z+FFz/UQpqaYS98RUpEdadLrnkM=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha1-wZ/Zvbv4WUK0/ZechNz31fB8I4c=", + "dev": true, + "peer": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", + "dev": true, + "peer": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha1-zB8B640CKYy8mkN8dMcKtOUhC4A=", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha1-nreT5oMwZ/cjWQL807CZF6AAqVo=", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/commander/-/commander-13.1.0.tgz", + "integrity": "sha1-d2Fn22jHjzjczh+bjXuLmkiKv0Y=", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha1-va/q03lhrAeb4R637GXE0CHq+cw=", + "dev": true, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha1-fQB6fgfFjEtNX0MxMaGRQbKfEeA=", + "dev": true, + "peer": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/compare-versions": { + "version": "3.6.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha1-GlaJkTaF5ah2N7jT/8p1UU7EHWI=", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha1-r1PMprBw1MPAdQ+9dyhqbXzEb7o=", + "dev": true, + "peer": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/compression/-/compression-1.8.1.tgz", + "integrity": "sha1-SkXZCawWUJGVqaKL2RCUiJwYDXk=", + "dev": true, + "peer": true, + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/debug/-/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "peer": true + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha1-d3lI4kUmUcVwtxLdAcI+JicT//c=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha1-ZHJkhFJRoNryW5fOh4NMrOD18cg=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha1-i4K076yCUSoCuwsdzsnSxejrW/4=", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha1-i3cxYmVtHRCGeEyPI6VM5tc9eRg=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha1-f6rmI1P7QhM2bQypg1jSLoNosF8=", + "dev": true + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha1-L3PEIULV1c9xMQp0/ErmFnDl28k=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true, + "peer": true + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha1-CSRU6pWEp7etVXMGKyqH9ZAPxIA=", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "12.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz", + "integrity": "sha1-k15XuOYYPIL5W9k332WKWfai2ig=", + "dev": true, + "peer": true, + "dependencies": { + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.1", + "globby": "^14.0.0", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^6.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha1-2TM9+nsGXjR8xWgiGdb2kIWcwuw=", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true + }, + "node_modules/core-js-compat": { + "version": "3.46.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/core-js-compat/-/core-js-compat-3.46.0.tgz", + "integrity": "sha1-DIcSahmhrwA3HhKwKisIikDzxvc=", + "dev": true, + "peer": true, + "dependencies": { + "browserslist": "^4.26.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha1-FEO5r6WWtnAILqRsvY9qYrhGNfY=", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha1-hO0BwKe6OAr+CdkKjBgNzZ0DBDs=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha1-IwHF/78StGfejaIzOkWeKeeSDks=", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha1-o1XFs8seGvAroXf+ev1/7uSaUyA=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/create-jest/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/create-jest/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha1-wdfo8eX2z8n/ZfnNNS03NIdWwzM=", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha1-ilj+ePANzXDDcEUXWd+/rwPo7p8=", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-loader": { + "version": "7.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/css-loader/-/css-loader-7.1.2.tgz", + "integrity": "sha1-ZGcVQcbv4GsOIudQUDEGvdhogPg=", + "dev": true, + "peer": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha1-Abbo0WNje7LdbJgspO1lhjaCeG4=", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha1-zcyPm2l3cZ/fvR3nrsJKv3Vrneo=", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha1-N3QZGZA7hoVl4cCep0dEXNGJg+4=", + "dev": true, + "peer": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha1-0lT6ks2Lb72DgRufuu00ZjzBfDY=", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha1-/2ZaDdvcMYZLCWR/NBY0Q9kLCFI=", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha1-nxJ29bK0Y/IRTT8sdSUK+MGjb0o=", + "dev": true + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha1-nPJKR3riK871zV9vC/vB0tO+kUM=", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha1-IRoDupXsr3eYqMcZjXlTYhH4hXA=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha1-noD3ylJFPOPpPSWjUxh2fqdwRzU=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha1-BoMH+bcat2274QKROJ4CCFZgYZE=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/debug/-/debug-4.4.3.tgz", + "integrity": "sha1-xq5DLZvZZiWC/OCHCbA4xY6ePWo=", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha1-5kmkPjq5U6chkv9Zg4ZeUJ837Zo=", + "dev": true + }, + "node_modules/dedent": { + "version": "1.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha1-wflEUzXwF1qWWHviRaKC/0UURso=", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha1-pvLc5hL63S7x9Rm3NVHxfoUZmDE=", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha1-RLXyFHzTsA1LVhN2hZZvJv0l3Uo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha1-e3umEgT/PkJbVWhprm0+nZ8XEs8=", + "dev": true, + "peer": true, + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha1-odmL+WDBUILYo/pp6DFQzMzDryY=", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha1-sLAgYsHiqmL/XZUo8PmLqpCXjXo=", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha1-iU3BQbt9MGCuQ2b2oBB+aPvkjF4=", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha1-27Ga37dG1/xtc0oGty9KANAhJV8=", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha1-EHgcxhbrlRqAoDS6/Kpzd/avK2w=", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/del": { + "version": "2.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w=", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/depd/-/depd-2.0.0.tgz", + "integrity": "sha1-tpYWPMdXVg0JzyLMj60Vcbeedt8=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dependency-graph": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/dependency-graph/-/dependency-graph-1.0.0.tgz", + "integrity": "sha1-u16FrsExC8E7ItvXbjGWxO5MENI=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha1-SANzVQmti+VSk0xn32FPlOZvoBU=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha1-aJxdzcGQDvVYOky59te0c3QgdK0=", + "dev": true, + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha1-V29d/GOuGhkv8ZLYrTr2MImRtlE=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha1-yccHdaScPQO8LAbZpzvlUPl4+LE=", + "dev": true, + "peer": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/diff/-/diff-4.0.2.tgz", + "integrity": "sha1-YPOuy4nV+uUgwRqhnvwruYKq3n0=", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha1-Ter4lNEUB8Ue/IQYAS+ecLhOqSE=", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha1-roiK1CWp0UeKBnQlarhm3hASzy8=", + "dev": true, + "peer": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha1-5BuALh7t+fbK4YPOXmIteJ19jlM=", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha1-XEXo6GmVJiYzHXqrMm0B2vZdWJ0=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha1-StG+VsytyG/HbQMzU5magDfQNnM=", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha1-zDhff3UfHR/GUMITdIBCVFOMfTE=", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha1-7b/itmiwwdl8JLrw8QYrEyIhvHg=", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha1-165mfh3INIL4tw/Q9u78UNow9Yo=", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha1-aWzi7Aqg5uqTo5f/zySqeEDIJ8s=", + "dev": true + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true, + "peer": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.243", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/electron-to-chromium/-/electron-to-chromium-1.5.243.tgz", + "integrity": "sha1-sTtKBG9J9GV01kPU4uwuozzoz+c=", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha1-wEuMNFdJDghHrlH87Tr1LTOOPa0=", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha1-vz1uj3+P0ipl2XA0dbwBRzV6aw0=", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha1-e46omAd9fkCdOsRUdOo46vCFelg=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha1-VldK/deR9UqOmyeFwFgqLSYhD6k=", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha1-pS+AvzjaGVLrXGgXkHGYcaGnJQE=", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha1-c0TXEd6kDgt0q8LtSXeHQ8ztsIw=", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha1-m19MXAdrh4fHj+VAOSznaoiFW0Q=", + "dev": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/entities/-/entities-4.5.0.tgz", + "integrity": "sha1-XSaOpecRPsdMTQM7eepaNaSI+0g=", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha1-QgOZ1BbOH76bwKB8Yvpo1n/Q+PI=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/environment/-/environment-1.1.0.tgz", + "integrity": "sha1-jobGaxgPNjx6sxF4fgJZZl9FqfE=", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha1-I8Lzt1b/38YI0w4nyalBAkgH5/k=", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/errno/-/errno-0.1.8.tgz", + "integrity": "sha1-i7Ppx9Rjvkl2/4iPdrSAnrwugR8=", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha1-s6jYu2+S7swWKePifTyGB6ijJBQ=", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha1-xEcy0r6wrMHtYN+ECGnjEG568yg=", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha1-mD6y+aZyTpMD9hrd8BHHLgngsPo=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha1-BfdaJdq5jk+x3NXhRywFRtUFfI8=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha1-kVlgFWGICoXyc0VgqQmbLDHlNyo=", + "dev": true, + "peer": true + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha1-HE8sSDcydZfOadLKGQp/3RcjOME=", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha1-8x274MGDsAptJutjJcgQwP0YvU0=", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha1-Q43zVSDaxdEF85Q9knVJ6jsA9LU=", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha1-lsicgsxJ/YeUokg1uj4f+H8hThg=", + "dev": true, + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha1-TrIVlMlyvEBVPSduUQU5FD21Pgo=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/esbuild": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/esbuild/-/esbuild-0.25.4.tgz", + "integrity": "sha1-u5oWM01O8sM8cwGpJLi4YzUaCFQ=", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.4", + "@esbuild/android-arm": "0.25.4", + "@esbuild/android-arm64": "0.25.4", + "@esbuild/android-x64": "0.25.4", + "@esbuild/darwin-arm64": "0.25.4", + "@esbuild/darwin-x64": "0.25.4", + "@esbuild/freebsd-arm64": "0.25.4", + "@esbuild/freebsd-x64": "0.25.4", + "@esbuild/linux-arm": "0.25.4", + "@esbuild/linux-arm64": "0.25.4", + "@esbuild/linux-ia32": "0.25.4", + "@esbuild/linux-loong64": "0.25.4", + "@esbuild/linux-mips64el": "0.25.4", + "@esbuild/linux-ppc64": "0.25.4", + "@esbuild/linux-riscv64": "0.25.4", + "@esbuild/linux-s390x": "0.25.4", + "@esbuild/linux-x64": "0.25.4", + "@esbuild/netbsd-arm64": "0.25.4", + "@esbuild/netbsd-x64": "0.25.4", + "@esbuild/openbsd-arm64": "0.25.4", + "@esbuild/openbsd-x64": "0.25.4", + "@esbuild/sunos-x64": "0.25.4", + "@esbuild/win32-arm64": "0.25.4", + "@esbuild/win32-ia32": "0.25.4", + "@esbuild/win32-x64": "0.25.4" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.25.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/esbuild-wasm/-/esbuild-wasm-0.25.4.tgz", + "integrity": "sha1-BnRL56eQrNCmXJjFpiibMaF6Dcs=", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha1-ARo/aYVroYnf+n3I/M6Z0qh5A+U=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true, + "peer": true + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha1-FLqDpdNz49MR5a/KKc9b+tllvzQ=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha1-upO7t6Q5htKdYEH5n1Ji2nc+Lhc=", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha1-ffEJZUq6fju+XI6uUzxeRh08bKk=", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha1-FXNM5K+MJ3jMMvCwGzewtc0ey5c=", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha1-1OqsUrii58PNGQPrAPfgUzVhGKw=", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/debug/-/debug-3.2.7.tgz", + "integrity": "sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o=", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha1-920yIL+4PAV2UTWSlatYVOqtdf8=", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/debug/-/debug-3.2.7.tgz", + "integrity": "sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o=", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha1-YCtV+qbkyuql6XDBmLXACjdwiYA=", + "dev": true, + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha1-q5tFRGblqMw6GHvqrVgEEqnFuEM=", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/debug/-/debug-3.2.7.tgz", + "integrity": "sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o=", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json5/-/json5-1.0.2.tgz", + "integrity": "sha1-Y9mNYPIbMTt3xNbaGL+mnYDh1ZM=", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha1-Gc0ZS/0+Qo8EmnCBfAONiatL41s=", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha1-VW0u+GiRRuRtzqS/3QlfNDTf/LQ=", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-import/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha1-UpnsYF5VsauyPsk57xXtr0gwcNQ=", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "52.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-52.0.4.tgz", + "integrity": "sha1-05GzPdjWgI1XMRhYhFEinU9B8g0=", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.52.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.4.1", + "escape-string-regexp": "^4.0.0", + "espree": "^10.4.0", + "esquery": "^1.6.0", + "parse-imports-exports": "^0.2.4", + "semver": "^7.7.2", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": ">=20.11.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha1-TP6mD+fdCtjoFuHtAmwdUlG1EsE=", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/espree": { + "version": "10.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/espree/-/espree-10.4.0.tgz", + "integrity": "sha1-1U9JSdRikAWh+haNk3w/8ffiqDc=", + "dev": true, + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-7.7.3.tgz", + "integrity": "sha1-S19BQ9AHYzqNxnHNCm75FHuLuUY=", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-prefer-arrow": { + "version": "1.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", + "integrity": "sha1-5/uz+kzYT/EBW5xRrYZVDlUEEEE=", + "dev": true, + "peerDependencies": { + "eslint": ">=2.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha1-iOZGogf61hQ2/6OetQUUcgBlXII=", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha1-DNcv6FUOPC6uFWqWpN3c0cisWAA=", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha1-q5tFRGblqMw6GHvqrVgEEqnFuEM=", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha1-3rT5JWM5DzIAaJSvYqItuhxGQj8=", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha1-PNQOcp82Q/2HywTlC/DrcivFlvU=", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", + "dev": true + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha1-Gc0ZS/0+Qo8EmnCBfAONiatL41s=", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/espree/-/espree-9.6.1.tgz", + "integrity": "sha1-oqF7jkNGkKVDLy+AGM5x0zGkjG8=", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha1-kUGSNPgE2FKoLc7sPhbNwiz52uc=", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha1-eteWTWeauyi+5yzsY3WLHF0smSE=", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha1-LupSkHAvJquP5TcDcP+GyWXSESM=", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha1-UvAQF4wqTBF6d1fP6UKtt9LaTKw=", + "dev": true + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha1-Lem2j2Uo1WRO9cWVJqG0oHMGFp8=", + "dev": true, + "peer": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/events/-/events-3.3.0.tgz", + "integrity": "sha1-Mala0Kkk4tLEGagTrrLE6HjqdAA=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/execa/-/execa-5.1.1.tgz", + "integrity": "sha1-+ArZy/Qpj3vR1MlVXCHpN0HEEd0=", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha1-qaF2f4r4QVURTqq9c/mSc8j1mtk=", + "dev": true + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/expect/-/expect-30.2.0.tgz", + "integrity": "sha1-1AE77SZwE8FLwRmc7IqlfO6bWGk=", + "dev": true, + "dependencies": { + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha1-Uc+SwcBJPHZgU/nTq+5ENMJE0vY=", + "dev": true + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/express/-/express-4.21.2.tgz", + "integrity": "sha1-zyUOSDYhdOrWzqSlZqvvAWLB7DI=", + "dev": true, + "peer": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/debug/-/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "peer": true + }, + "node_modules/express/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/qs/-/qs-6.13.0.tgz", + "integrity": "sha1-bKO9WEOffiRWVXmJl3h7DYilGQY=", + "dev": true, + "peer": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/extend/-/extend-3.0.2.tgz", + "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=", + "dev": true + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", + "dev": true + }, + "node_modules/fast-equals": { + "version": "2.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fast-equals/-/fast-equals-2.0.4.tgz", + "integrity": "sha1-Ot2UEFheLXNkwt7ranB76tskuSc=", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha1-0G1YXOjbqQoWsFBcVDw8z7OuuBg=", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ=", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha1-Zu7P9sdkwN+bdi5iyn7c+1O07fo=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha1-1Q6rqAPIhGqIPBZJKCHrzSzaVfU=", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha1-fw2Sdc/dhqHJY9yLZfzEUe3Lsdo=", + "dev": true, + "peer": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha1-6VJO5rXHfp5QAa8PhfOtu4YjJVw=", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha1-7Sq5Z6MxreYvGNB32uGSaE1Q01A=", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha1-IRst2WWcsDlLBz5zI6w8kz1SICc=", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha1-RCZdPKwH4+p9wkdRY4BkN1SgUpI=", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha1-DFdfHR0yTd0do1rX7OPffRkIgBk=", + "dev": true, + "peer": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/debug/-/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "peer": true + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha1-ow7gRI+Bo5kHCPZFNjPHM+L27sI=", + "dev": true, + "peer": true, + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha1-TJKBnstwg1YeT0okCoa+UZj1Nvw=", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-versions": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/find-versions/-/find-versions-4.0.0.tgz", + "integrity": "sha1-PFflc7+XdpuMuN8Wk0tieRXaSWU=", + "dev": true, + "dependencies": { + "semver-regex": "^3.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/flat/-/flat-5.0.2.tgz", + "integrity": "sha1-jKb+MyBp/6nTJMMnGYxZglnOskE=", + "dev": true, + "peer": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha1-LAwtUEDJmxYydxqdEFclwBFTY+4=", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha1-Z8j62VRUp8er6/dLt47nSkQCM1g=", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha1-d31z1yqS+OxNLkEOtHNSpWuOg0A=", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "peer": true, + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha1-1lBogCeCaSD+6wr3R+57lCGkHUc=", + "dev": true, + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha1-Mujp7Rtoo0l777msK2rfkqY4V28=", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.5.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/form-data/-/form-data-2.5.5.tgz", + "integrity": "sha1-pfY2Stfk5n6VtKB+LYxvcRx09iQ=", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha1-ImmTZCiq1MFcfr6XeahL8LKoGBE=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha1-BsoAhRV+Qv2n+ecm55/vxAaIQPc=", + "dev": true, + "peer": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha1-eahZgcTcEgBl6W9iCGv2+dwmzFQ=", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha1-ysZAd4XQNnWipeGlMFxpezR9kNY=", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha1-LALYZNl/PqbIgwxGTL0Rq26rehw=", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha1-5o4d97JZpclJ7u+Vzb3lPt/6u3g=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha1-BAT+TuK6L2B/Dg7DyAuumUEzuDQ=", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha1-DnXdQQ0SQ2h6C6LpUblO7bj3N6I=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha1-MqbudsPX9S1GsrGuXZP+qFgKJeA=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha1-m8TKoTFwK0thcpy35Cc1vFUMnuY=", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha1-dD8OO2lkqTpUke0b/6rgVNf5jQE=", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha1-jeLYA8/0TfO8bEVuZmizbDkm4Ro=", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha1-FQs/J0OGnvPoUewMSdFbHRTQDuE=", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha1-omLY7vZ6ztV8KFKtYWdSakPL97c=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha1-e91U4L7+j/yfO04gMiDZ8eiBtu4=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/glob/-/glob-7.2.3.tgz", + "integrity": "sha1-uN8PuAK7+o6JvR2Ti04WV47UTys=", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha1-bSN9mQg5UMeSkPJMdkKj3poo+eM=", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regex.js": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", + "integrity": "sha1-KzI3KCcdEzgwhQ4yMR9AdmxfZBM=", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha1-x1KXCHyFG5pXi9IX3VmpL1n+VG4=", + "dev": true + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha1-q5tFRGblqMw6GHvqrVgEEqnFuEM=", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha1-Gc0ZS/0+Qo8EmnCBfAONiatL41s=", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/globals/-/globals-13.24.0.tgz", + "integrity": "sha1-hDKhnXjODB6DOUnDats0VAC7EXE=", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha1-dDDtOpddl7+1m8zkH1yruvplEjY=", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/globby/-/globby-14.1.0.tgz", + "integrity": "sha1-E4t453z1qNeU4yexXc6Avx+wpz4=", + "dev": true, + "peer": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha1-ifVrghe9vIgCvSmd9tfxCB1+UaE=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha1-QYPk6L8Iu24Fu7L30uDI9xLKQOM=", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha1-+y8dVeDjoYSa7/yQxPoN1ToOZsY=", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha1-hX95zjWVgMNA1DCBzGSJcNC7I04=", + "dev": true, + "peer": true + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha1-QcQsGLG+I2VDkYjHfGr65xwM2ek=", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha1-HwgDufjLIMD6E4It8ezds2veHv0=", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", + "dev": true + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha1-KGB+llrJZ+A80qLHCiY2oe2tSf4=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha1-lj7X0HHce/XwhMW/vg0bYiJYaFQ=", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha1-XeWm6r2V/f/ZgYtDBV6AZeOf6dU=", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha1-/JxqeDoISVHQuXH+EBjegTcHozg=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha1-LNxC1AvvLltO6rfAGnPFTOerWrw=", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha1-AD6vkb563DcuhOxZ3DclLO24AAM=", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "8.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha1-FTzYTAPGchSB4WpXCet0saCrLtA=", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha1-QQ/IoXtw5ZgBPfJXwkRrfzOD8Rk=", + "dev": true + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "peer": true + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha1-kRJegEK7obmIf0k0X2J3Anzovps=", + "dev": true, + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", + "dev": true, + "peer": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha1-LLGozw21JBR3blsqegTV3ZgVjek=", + "dev": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha1-39YAJ9o2o238viNiYsAKWCJoFFM=", + "dev": true + }, + "node_modules/htmlparser2": { + "version": "10.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/htmlparser2/-/htmlparser2-10.0.0.tgz", + "integrity": "sha1-d60kkDe2a/jMmcbihu9zuDrrYh0=", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.1", + "entities": "^6.0.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/entities/-/entities-6.0.1.tgz", + "integrity": "sha1-wow0pDN5yn9h0HQTCy9fcCCjBpQ=", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha1-IF9Ntk+FYrdqT/kjWqUnmDmgndU=", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true, + "peer": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha1-t3dKFIbvc892Z6ya4IWMASxXudM=", + "dev": true, + "peer": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha1-syd71tftVYjiDqc79yT8vkRgkHU=", + "dev": true, + "peer": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha1-QBVB8FNIhLv5UmAzTnL4juOXZUk=", + "dev": true, + "peer": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha1-USmAAgNSDUNPFCvHj/PBcIAPK0M=", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha1-Sf/1hXfP7j83F2/qtMIuAPhtf3c=", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "3.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/http-proxy-middleware/-/http-proxy-middleware-3.0.5.tgz", + "integrity": "sha1-nc3mY+3EQHm8Wpxj4D/l5dYDf6s=", + "dev": true, + "peer": true, + "dependencies": { + "@types/http-proxy": "^1.17.15", + "debug": "^4.3.6", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.3", + "is-plain-object": "^5.0.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha1-2o3+rH2hMLBcK6S1nJts1mYRprk=", + "dev": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha1-3JH8ukLk0G5Kuu0zs+ejwC9RTqA=", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/husky": { + "version": "4.3.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/husky/-/husky-4.3.8.tgz", + "integrity": "sha1-MRRAYL6WP9aFDlzI8Bmh3+GUKW0=", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "compare-versions": "^3.6.0", + "cosmiconfig": "^7.0.0", + "find-versions": "^4.0.0", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^5.0.0", + "please-upgrade-node": "^3.2.0", + "slash": "^3.0.0", + "which-pm-runs": "^1.0.0" + }, + "bin": { + "husky-run": "bin/run.js", + "husky-upgrade": "lib/upgrader/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/husky" + } + }, + "node_modules/husky/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/husky/node_modules/pkg-dir": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha1-oC1q6+a6EzqSj3Suwguv3+a452A=", + "dev": true, + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/husky/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha1-WWaNMjrakiKNKoadPkdNWjO2nms=", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.18" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha1-xQzYDmdGyoEV65h0OvqBqg4Uej4=", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha1-xr5oWKvQE9do6YNmrkfiXViHsa4=", + "dev": true, + "peer": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha1-jrehCmP/8l0VpXsAFYbRd9Gw01I=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha1-TLX2zX1MerA2VzjHrqiIuqbX79k=", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "7.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ignore-walk/-/ignore-walk-7.0.0.tgz", + "integrity": "sha1-g1Dkdc9DdZacEutJYYs/2cymcE8=", + "dev": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/immutable": { + "version": "5.1.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/immutable/-/immutable-5.1.4.tgz", + "integrity": "sha1-4/jB/ntWfVbPJmmPMZGMJB2ujB8=", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha1-nOy1ZQPAraHydB271lRuSxO1fM8=", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha1-w9XHRXmMAqb4uJdyarpRABhu4mA=", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha1-8JkTPfft5CLoHR2ESCcO6z5CYfM=", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=", + "dev": true + }, + "node_modules/ini": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ini/-/ini-5.0.0.tgz", + "integrity": "sha1-p6RhUzmEPZqMzC2Fydgc+T/7xjg=", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/injection-js": { + "version": "2.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/injection-js/-/injection-js-2.6.1.tgz", + "integrity": "sha1-++OVKXC8DDnChWqXzlGMb221SjA=", + "dev": true, + "dependencies": { + "tslib": "^2.0.0" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha1-HqyRdilH0vcFa8g42T4TsulgSWE=", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip-address": { + "version": "10.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha1-qBgLeDzneId315YobWG85CdoGO0=", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha1-0z+nusKE9N56+UljjJ1oFXxrkug=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha1-ZXQuHmh70sxmYlMGj9hwf+TUQoA=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha1-PmkBjI4E5ztzh5PQIL/ohLn9NSM=", + "dev": true, + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha1-3aejRF31ekJYPbQihoLrp8QXBnI=", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=", + "dev": true, + "peer": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha1-cGf0dwmAmjk8cf9bs+E12KkhXZ4=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha1-O8KoXqdC2eNiBdys3XLKH9xRsFU=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha1-KpiAGoSfQ+Kt1kT7trxiKbGaTvQ=", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha1-uuCkG5aImGwhiN2mZX5WuPnmO44=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha1-rYVUGZb8eqiycpcB0ntzGfldgvc=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha1-kAk6oxBid9inelkQ265xdH4VogA=", + "dev": true, + "peer": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha1-7v3NxslN3QZ02chYh7+T+USpfJA=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha1-+uMWfHKedGP4RhzlErCApJJoqog=", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha1-fRQK3DiarzARqPKipM+m+q3/sRg=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha1-rjth49XqTkg5uQutIrAjNQUaF9U=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha1-ZPYeQsu7LuwgcanawLKLoeZdUIQ=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha1-6B+6aZZi6zHb2vJnZqYdSBRxfqQ=", + "dev": true, + "peer": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha1-zqbmrlyHCnsKAAQHC3tYfgJSkS4=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha1-7elrf+HicLPERl46RlZYdkkm1i4=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha1-ztkDoCespjgbd3pXQwadc3akl0c=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-network-error": { + "version": "1.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-network-error/-/is-network-error-1.3.0.tgz", + "integrity": "sha1-LOYsvKREq9UG+KkA850guJjTdRI=", + "dev": true, + "peer": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha1-FEsh6VobwUggXcwoFKkTTsQbJUE=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-cwd": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha1-WsSLNF72dTOb1sekipEhELJBz1I=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "is-path-inside": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-in-cwd/node_modules/is-path-inside": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "path-is-inside": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha1-0jE2LlOgf/Kw4Op/7QSRYf/RYoM=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha1-r28uoUrFpkYYOlu9tbqrvBVq2dc=", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha1-RCf1CrNCnpAl6n1S6QQ6nvQVk0Q=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha1-Fx7W8Z46xVQ5Tt94yqBXhKRb67U=", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha1-dtcKPtEO+b5I61d4h9dCBb8MrSI=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha1-irIJ6kJGCBQTct7W4MsgDvHZ0B0=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha1-m2eES9m38ka6BwjDqT40Jpx3T28=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha1-+sHj1TuXrVqdCunO8jifWBClwHc=", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha1-kuo/PVxbbgOcqGd+WsjQfqdzy7k=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha1-9HdhJ59TLisFpwJKdQbbvtrNBjQ=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha1-S/tKRbYc7oOlpG+6d45OjVnAzgs=", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha1-PybHaoCVk7Ur+i7LVxDtJ3m1Iqc=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha1-v3JhXWSd/l9pkHnFS4PkfRrhnP0=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha1-7qQwGCvo1kF0vZa/+8RvIb8/kpM=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha1-yfXesLwZBsbW8QJ/KE3fRZJJ2so=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha1-4SIvRt3ahd6tD9HJ3xMXYOd3VcE=", + "dev": true + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha1-4cZX45wQCQr8vt7GFyD2uSTDy9I=", + "dev": true, + "peer": true, + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha1-ivHkwSISRMxiRZ+vOJQNTmRKVyM=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha1-LRZsSwZE1Do58Ev2wu3R5YXzF1Y=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha1-+hVAHfbBWHS8shBfdzMl14xmZ2U=", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha1-kIMFusmlvRdaxqdEier9D8JEWn0=", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha1-iV86cJ/PujTG3lpCk5Ai8+Q1hVE=", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha1-y0U1FitXhKpiPO4hpyUs8sgHrJM=", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha1-iDOp2Jq0rN5hiJQr0cU7Y5DtWoo=", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jasmine": { + "version": "2.8.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" + }, + "bin": { + "jasmine": "bin/jasmine.js" + } + }, + "node_modules/jasmine-core": { + "version": "2.8.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/jasmine-marbles": { + "version": "0.9.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jasmine-marbles/-/jasmine-marbles-0.9.2.tgz", + "integrity": "sha1-Wt/uX3LH8kJwaH+mSm6KhhP/qEE=", + "dev": true, + "dependencies": { + "lodash": "^4.17.20" + }, + "peerDependencies": { + "rxjs": "^7.0.0" + } + }, + "node_modules/jasminewd2": { + "version": "2.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">= 6.9.x" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest/-/jest-29.7.0.tgz", + "integrity": "sha1-mUZ2/CQXfwiPHF43N/VpcgT/JhM=", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha1-HAbQfnfHjhWF0CBCTe3BDW4XrDo=", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-changed-files/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-changed-files/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha1-toF6RfzINdixbVli0MAmRz7jZoo=", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha1-AXk0pm67fs9vIF6EaZvhCv1wRYo=", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha1-ro/sef8kn9WSzoDj7kdOg6bETxI=", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha1-i8OS4gTpXf51ZKu+cqQE4o5R9/M=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha1-VZLJQHmODK5nfuwWkmTy2DmjeZU=", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha1-vL2ogG28wBseMWpGu3QIWoSwJF8=", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-config/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha1-4+w6bqXFdH9gXJ6HT4PXVsujaCU=", + "dev": true, + "dependencies": { + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha1-j922rcPNyVXJPiqH9hz9NQ1dEZo=", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha1-FiqbPyMovdmRvqq/+7dHReVld9E=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-each/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", + "integrity": "sha1-0gb6NVGTPD/VGeXf21ig9ROag38=", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jest-environment-jsdom/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-environment-jsdom/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha1-ToNs9g6Zxvz6vp+Z0Bfz/dUKY0c=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-jsdom/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-jsdom/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha1-C5PhEd2o7BILyDAObR+5V24WQ3Y=", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-environment-node/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-node/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha1-ToNs9g6Zxvz6vp+Z0Bfz/dUKY0c=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha1-NvSZ/c6hl8EEWhJzGcBIFyOQj9E=", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha1-PCOWUkSC9aBQY3bmyFjDu8wXsQQ=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-haste-map/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-haste-map/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-haste-map/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-jasmine2": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-jasmine2/-/jest-jasmine2-29.7.0.tgz", + "integrity": "sha1-w3BOKcp9dd+1RleOfoIavFpjFKE=", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha1-AXk0pm67fs9vIF6EaZvhCv1wRYo=", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha1-ro/sef8kn9WSzoDj7kdOg6bETxI=", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha1-i8OS4gTpXf51ZKu+cqQE4o5R9/M=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-jasmine2/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha1-W37A2t/f7Ayjg9yaoBbTa16kxyg=", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha1-aaDUwnEGZVnsiw2BdIKa3D8jp4M=", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util": { + "version": "30.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha1-/Je/kNEfEYsx5hMeK2f8Tzn5IVI=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.2.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha1-e99p/Fo2ilq9tJ/ZEDbFUiWEZHM=", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha1-HGeKeSS49Z6v1Md9VrbQupdtYrg=", + "dev": true, + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha1-qlGmwZRt8sWhFJSizbkxjgJtsWw=", + "dev": true + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "30.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha1-afmRYU7rQGAYlFnTWE9xCEW/9F4=", + "dev": true, + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha1-e99p/Fo2ilq9tJ/ZEDbFUiWEZHM=", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock/node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha1-HGeKeSS49Z6v1Md9VrbQupdtYrg=", + "dev": true, + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock/node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha1-qlGmwZRt8sWhFJSizbkxjgJtsWw=", + "dev": true + }, + "node_modules/jest-mock/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha1-kwsVRhZNStWTfVVA5xHU041MrS4=", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-preset-angular": { + "version": "14.6.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-preset-angular/-/jest-preset-angular-14.6.2.tgz", + "integrity": "sha1-GgAFhVC/7kdGUGJUqA6vJpBGXzQ=", + "dev": true, + "dependencies": { + "bs-logger": "^0.2.6", + "esbuild-wasm": ">=0.15.13", + "jest-environment-jsdom": "^29.7.0", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0", + "ts-jest": "^29.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "optionalDependencies": { + "esbuild": ">=0.15.13" + }, + "peerDependencies": { + "@angular/compiler-cli": ">=15.0.0 <21.0.0", + "@angular/core": ">=15.0.0 <21.0.0", + "@angular/platform-browser-dynamic": ">=15.0.0 <21.0.0", + "jest": "^29.0.0", + "jsdom": ">=20.0.0", + "typescript": ">=4.8" + }, + "peerDependenciesMeta": { + "jsdom": { + "optional": true + } + } + }, + "node_modules/jest-preset-angular/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-preset-angular/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-preset-angular/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-preset-angular/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-preset-angular/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-preset-angular/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha1-SlVtnHdq9o4cX0gZT00DJ9JOilI=", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha1-ZNaomS3Sb2NasMAeXu9Dmca8vDA=", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha1-GwTywJXzf8d2/0CAPckpIbHohCg=", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-resolve/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha1-gJrwctQIpT3P0uhJpMl20xMvcY4=", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha1-i8OS4gTpXf51ZKu+cqQE4o5R9/M=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-runner/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha1-MbJKnC5zwt6FBmwP631Edn7VKTI=", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha1-7+yzFBz303Z6OgzI98mZBYfT2Bc=", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha1-i8OS4gTpXf51ZKu+cqQE4o5R9/M=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha1-ToNs9g6Zxvz6vp+Z0Bfz/dUKY0c=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-runtime/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha1-wsV0w/UYZdobsykDZ3imm/iKa+U=", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha1-Aj7+XSaopw8hZ30KGvwPCkTjocY=", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/expect/-/expect-29.7.0.tgz", + "integrity": "sha1-V4h0WQ3LMhRRQITAgRXYruYeEbw=", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha1-AXk0pm67fs9vIF6EaZvhCv1wRYo=", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha1-ro/sef8kn9WSzoDj7kdOg6bETxI=", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha1-i8OS4gTpXf51ZKu+cqQE4o5R9/M=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-3.0.0.tgz", + "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha1-UUKtvK1vTlPCd2wGek2zwU+RNwU=", + "dev": true, + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha1-e99p/Fo2ilq9tJ/ZEDbFUiWEZHM=", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha1-HGeKeSS49Z6v1Md9VrbQupdtYrg=", + "dev": true, + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha1-qlGmwZRt8sWhFJSizbkxjgJtsWw=", + "dev": true + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha1-NVrVcZIIELViPhHUAjL0Q/FvHao=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha1-e/cFURxk2lkdRrFfzkFADVIUfZw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha1-VoW5XrIJrJwMF3Rnd4ychN9Yupo=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha1-ykLHWDEPNlv6caC9oKgHFgt3aBI=", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha1-eBDTDWGcOmIJMiPOa7NZyhsoovI=", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha1-rK0HOsu663JivVOJ4bz0PhAFjUo=", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-worker/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha1-zW/BfihQDP9WwbhsCn/UpUpzAFw=", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha1-ndgQQ0JKPShFixk9ll8NGKIwC6k=", + "dev": true, + "peer": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha1-wftl+PUBeQHN0slRhkuhhFihBgI=", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha1-/2tKPzOcNKbBiMv1ChYIeFjSIRM=", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha1-iGpBuh1HJvZ6iFgCjJlIn+1q1Ns=", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha1-Sf/1hXfP7j83F2/qtMIuAPhtf3c=", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/jsdom/node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha1-eEzczgZpqdaOlNEaxO6pgIjt0sQ=", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha1-xZ7yJKBP6LdU89sAY6Jeow0ABdY=", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha1-dNM1ojT2ftGZB/2t+sfM+dQJgl0=", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha1-kziAKjDTtmBfvgYT4JQAjKjAWhM=", + "dev": true + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha1-u4Z8+zRQ5pEHwTHRxRS6s9yLyqk=", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", + "integrity": "sha1-0/Z71ZJegdPjGqRmrMghyDdc7EM=", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha1-995M9u+rg4666zI2R0y7paGTCrU=", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha1-rnvLNlard6c7pcSb9lTzjmtoYOI=", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json5/-/json5-2.2.3.tgz", + "integrity": "sha1-eM1vGhm9wStz21rQxh79ZsHikoM=", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha1-8qUktPf9EePXkeVZl3rWC5i3mLQ=", + "dev": true + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha1-cSxlUzoVyHi6WentXw4m1bd8X+s=", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha1-NK7nDrGOofrsL1iSCKFX0f6wkcI=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha1-kRJegEK7obmIf0k0X2J3Anzovps=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha1-WFJs7M9+hzDlbv/Zek3o1xKsDWs=", + "dev": true, + "peer": true, + "dependencies": { + "source-map-support": "^0.5.5" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha1-qHmpnilFL5QkOfKkBeOvizHU3pM=", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha1-p5yezIbuHOP6YgbRIWxQHxR/wH4=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/launch-editor": { + "version": "2.12.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/launch-editor/-/launch-editor-2.12.0.tgz", + "integrity": "sha1-zHQPTgJjprYurSSF+YluVFMh+Bc=", + "dev": true, + "peer": true, + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" + } + }, + "node_modules/less": { + "version": "4.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/less/-/less-4.2.2.tgz", + "integrity": "sha1-S1nt4ROTO1irFSGQ7fkYD8NoRtg=", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "12.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/less-loader/-/less-loader-12.2.0.tgz", + "integrity": "sha1-4elFIvar6eBk7zlsKaMVG8bBtsw=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/less/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha1-XwMQ4YuL6JjMBwCSlaMK5B6R5vU=", + "dev": true, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pify/-/pify-4.0.1.tgz", + "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-5.7.2.tgz", + "integrity": "sha1-SNVdtzfDKHzUg14X+hP+rOHEHvg=", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/leven/-/leven-3.1.0.tgz", + "integrity": "sha1-d4kd6DQGTMy6gq54QrtrFKE+1/I=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/levn/-/levn-0.4.1.tgz", + "integrity": "sha1-rkViwAdHO5MqYgDUAyaN0v/8at4=", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha1-HhhELtILdUuC8a3v9CJJuB0RrsY=", + "dev": true, + "peer": true, + "dependencies": { + "webpack-sources": "^3.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lie/-/lie-3.3.0.tgz", + "integrity": "sha1-3Pgt7lRfRgdNryAMfBxaCOD0D2o=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha1-7KKE910pZQeTCdwK2SVauy68FjI=", + "dev": true + }, + "node_modules/listr2": { + "version": "8.2.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/listr2/-/listr2-8.2.5.tgz", + "integrity": "sha1-XJ25luGv6wXbBEgZbT1fZP7CWT0=", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha1-YCFu6kZNhkWXzigyAAc4oFiWUME=", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha1-wETV3MUhoHZBNHJZehrLHxA8QEE=", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha1-U/X/0KSSrIAHIbtCxmuEHelkI8Q=", + "dev": true + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha1-Eyh1q95njH6o1pFTPy5+Irt0Tbo=", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha1-lWgy3qlJQwbm0gnrhxZDu4c9fJg=", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/lmdb": { + "version": "3.2.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lmdb/-/lmdb-3.2.6.tgz", + "integrity": "sha1-3Ri65jI2efmbw8tX34HcUH9Q9QU=", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "msgpackr": "^1.11.2", + "node-addon-api": "^6.1.0", + "node-gyp-build-optional-packages": "5.2.2", + "ordered-binary": "^1.5.3", + "weak-lru-cache": "^1.2.2" + }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "3.2.6", + "@lmdb/lmdb-darwin-x64": "3.2.6", + "@lmdb/lmdb-linux-arm": "3.2.6", + "@lmdb/lmdb-linux-arm64": "3.2.6", + "@lmdb/lmdb-linux-x64": "3.2.6", + "@lmdb/lmdb-win32-x64": "3.2.6" + } + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/loader-runner": { + "version": "4.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha1-bHbtKbDMzprzeSCCmfB/h23nN+M=", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/loader-utils": { + "version": "3.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha1-c1uaGf1jZIynrb0xwjJ9/igTBOU=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha1-VTIeswn+u8WcSAHZMackUqaB0oY=", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=", + "dev": true + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha1-Q+YmxG5lkbd1C+srUBFzkMYJ4+4=", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true, + "peer": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha1-VYqlO0O2YeGSWgr9+japoQhf5Xo=", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha1-P727lbRoOsn8eFER55LlWNSr1QM=", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha1-GgT/OBZvlGR64a9WL0vWoVsbfNQ=", + "dev": true, + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "7.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-escapes/-/ansi-escapes-7.1.1.tgz", + "integrity": "sha1-/dOUJ6flomIz5IqLQ2Y1Fin/6hs=", + "dev": true, + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha1-YCFu6kZNhkWXzigyAAc4oFiWUME=", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha1-wETV3MUhoHZBNHJZehrLHxA8QEE=", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha1-BGsqbU9rFWsiM9MgfUtal4OZm5g=", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha1-rfe+cKptchYtkHzQ5tXBH1B7VAM=", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha1-Eyh1q95njH6o1pFTPy5+Irt0Tbo=", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha1-lWgy3qlJQwbm0gnrhxZDu4c9fJg=", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA=", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha1-RQpElnPSRg5bvPupphkWoXFMdFM=", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha1-w8IwencSd82WODBfkVwprnQbYU4=", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha1-LrLjfqm2fEiR9oShOUeZr0hM96I=", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "14.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", + "integrity": "sha1-10w+ywAo8Iq2BAEeC8a67Ug/zc0=", + "dev": true, + "dependencies": { + "@npmcli/agent": "^3.0.0", + "cacache": "^19.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "ssri": "^12.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha1-Pl3SB5qC6BLpg8xmEMSiyw6qgBo=", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha1-oN10voHiqlwvJ+Zc4oNgXuTit/k=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "4.50.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/memfs/-/memfs-4.50.0.tgz", + "integrity": "sha1-GDIXfVWS7B5qgW+0/gEBKtooVuc=", + "dev": true, + "peer": true, + "dependencies": { + "@jsonjoy.com/json-pack": "^1.11.0", + "@jsonjoy.com/util": "^1.9.0", + "glob-to-regex.js": "^1.0.1", + "thingies": "^2.5.0", + "tree-dump": "^1.0.3", + "tslib": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha1-2AMZpl88eTU1Hlz9rI+TGFBNvtU=", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A=", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha1-Q2iJL4hekHRVpv19xVwMnUBJkK4=", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha1-1m+hjzpHB2eJMgubGvMr2G2fogI=", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/mime/-/mime-1.6.0.tgz", + "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha1-u6vNwChZ9JhzAchW4zh85exDv3A=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha1-OBqHG2KnNEUGYK497uRIE/cNlZo=", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha1-rL4rM0n5m53qyn+3Dki4PpTmcHY=", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.9.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", + "integrity": "sha1-lmAxtGiRelRG9MJKgIVLKUdQPFs=", + "dev": true, + "peer": true, + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha1-LhlN4ERibUoQ5/f7wAznPoPk1cc=", + "dev": true, + "peer": true + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha1-10+d1rV9g9jpjPuCEzsDl4vJKeU=", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha1-waRk52kzAuCCoHXO4MBXdBrEdyw=", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha1-k6libOXl5mvU24aEnnUV6SNApwc=", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha1-FiG8d+EiWKEsYNNOInbsXCBoCGM=", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "4.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minipass-fetch/-/minipass-fetch-4.0.1.tgz", + "integrity": "sha1-8tcX1aQYrQsacnT5uRNRXT54+eU=", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha1-gucTXX6JpQ/+ZGEKeHlTxMTLs3M=", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha1-e7o4TbOhUg0YycDlJRw0ROld2Uo=", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", + "dev": true + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha1-aEcveXEcCEZXwGfFxq2Tzd6oIUw=", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha1-e7o4TbOhUg0YycDlJRw0ROld2Uo=", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", + "dev": true + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha1-cO5afFBSBwr6z7wil36nne81O3A=", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha1-e7o4TbOhUg0YycDlJRw0ROld2Uo=", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", + "dev": true + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha1-atdsOo8QInybUdHJrI4wsn9aJRw=", + "dev": true, + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha1-5E5MVgf7J5wWgkFxPMbg/qmty1A=", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/mri/-/mri-1.2.0.tgz", + "integrity": "sha1-ZyFID+wqEaSImGERWki2y+fMjws=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha1-vD6H95h4U6VMmFDusfEHjNRK3dw=", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ms/-/ms-2.1.3.tgz", + "integrity": "sha1-V0yBOM4dK1hh8LRFedut1gxmFbI=", + "dev": true + }, + "node_modules/msgpackr": { + "version": "1.11.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/msgpackr/-/msgpackr-1.11.5.tgz", + "integrity": "sha1-7fC52ct9jtaJfdDkLPuGWi9LYC4=", + "dev": true, + "optional": true, + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha1-6dhwI945znFIcvnpUE48GZbWEBI=", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + } + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha1-d+tGBX9NetvRbZKQ+nKZ9vpkzO0=", + "dev": true, + "peer": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha1-pURvwMUStxyDxE2QjVx7e0xJOys=", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha1-T08RLO++MDIC8hmYOBKJNiZtGFs=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/needle/-/needle-3.3.1.tgz", + "integrity": "sha1-Y/da7FgMLnfiCfPzJOLN89Kb0Ek=", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha1-pS+AvzjaGVLrXGgXkHGYcaGnJQE=", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha1-tskbtHFy1p+Tz9fDV7u1KQGbX2o=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha1-tKr7k+OustgXTKU88WOrfXMIMF8=", + "dev": true + }, + "node_modules/ng-packagr": { + "version": "19.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ng-packagr/-/ng-packagr-19.2.2.tgz", + "integrity": "sha1-THQD//PNLwx65AicLbzqvsNjzko=", + "dev": true, + "dependencies": { + "@rollup/plugin-json": "^6.1.0", + "@rollup/wasm-node": "^4.24.0", + "ajv": "^8.17.1", + "ansi-colors": "^4.1.3", + "browserslist": "^4.22.1", + "chokidar": "^4.0.1", + "commander": "^13.0.0", + "convert-source-map": "^2.0.0", + "dependency-graph": "^1.0.0", + "esbuild": "^0.25.0", + "fast-glob": "^3.3.2", + "find-cache-dir": "^3.3.2", + "injection-js": "^2.4.0", + "jsonc-parser": "^3.3.1", + "less": "^4.2.0", + "ora": "^5.1.0", + "piscina": "^4.7.0", + "postcss": "^8.4.47", + "rxjs": "^7.8.1", + "sass": "^1.81.0" + }, + "bin": { + "ng-packagr": "cli/main.js" + }, + "engines": { + "node": "^18.19.1 || >=20.11.1" + }, + "optionalDependencies": { + "rollup": "^4.24.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^19.0.0 || ^19.1.0-next.0 || ^19.2.0-next.0", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "tslib": "^2.3.0", + "typescript": ">=5.5 <5.9" + }, + "peerDependenciesMeta": { + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/ng-packagr/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha1-S1YPZJ/E6RjdCrdc9JYei8iC2Co=", + "dev": true + }, + "node_modules/ng-packagr/node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha1-swxbbv8HMHMa6pu9nb7L2AJW1ks=", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/ng-packagr/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ng-packagr/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ng-packagr/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha1-QV6WcEazp/HRhSd9hKpYIDcmoT8=", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ng-packagr/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ng-packagr/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ng-packagr/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha1-8JkTPfft5CLoHR2ESCcO6z5CYfM=", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ng-packagr/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha1-VW0u+GiRRuRtzqS/3QlfNDTf/LQ=", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y=", + "dev": true + }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha1-rIRwA05Y5n0MbxIEoYrmmV2cDXY=", + "dev": true, + "optional": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha1-vo2iryQ7JBfV9kancGY6krfp3tM=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "11.5.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/node-gyp/-/node-gyp-11.5.0.tgz", + "integrity": "sha1-gmYbX0BkenNh7+kY486nbSl/zFY=", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^14.0.3", + "nopt": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "tar": "^7.4.3", + "tinyglobby": "^0.2.12", + "which": "^5.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha1-Ui9QwtUxNNfzp2zXJV3kq2yWo6Q=", + "dev": true, + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha1-mFXmTs0kCpzEJnzopKpdJKHaFeQ=", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha1-SkB+K9eN37FL6gwnxvcHLd53Xw0=", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/node-gyp/node_modules/tar": { + "version": "7.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tar/-/tar-7.5.1.tgz", + "integrity": "sha1-dQqL1jt8RMGEjnv5giYKCDz3R8k=", + "dev": true, + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/which/-/which-5.0.0.tgz", + "integrity": "sha1-2T8tk/eYNNQ2PH0MI+ANB8RmyNY=", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha1-AOLeRDY57Q14/YfeDSdGn7z/tTM=", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.26", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/node-releases/-/node-releases-2.0.26.tgz", + "integrity": "sha1-/fonLycYoTCUidGK7071un9d+1I=", + "dev": true + }, + "node_modules/nopt": { + "version": "8.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha1-sR04yvD4ZDzohYGFGAZBJ/YC6uM=", + "dev": true, + "dependencies": { + "abbrev": "^3.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha1-5m2xg4sgDB38IzIl0SyzZSDiNKg=", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha1-3/wL+aIcAiCQkPKqaUKeFBTa8/k=", + "dev": true + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-5.7.2.tgz", + "integrity": "sha1-SNVdtzfDKHzUg14X+hP+rOHEHvg=", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/npm-bundled/-/npm-bundled-4.0.0.tgz", + "integrity": "sha1-9bmD8FP+fGFWbPByQfqy1OnVE9M=", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-install-checks": { + "version": "7.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/npm-install-checks/-/npm-install-checks-7.1.2.tgz", + "integrity": "sha1-4zjTM5MO4Y4PsL5r2LZ6+Yvj0vo=", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", + "integrity": "sha1-33nnDNChE7d8AtH+JDyWuOYYrLE=", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-package-arg": { + "version": "12.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/npm-package-arg/-/npm-package-arg-12.0.2.tgz", + "integrity": "sha1-Ox4E6+ZRzEUCjimGZOjBXOnAykA=", + "dev": true, + "dependencies": { + "hosted-git-info": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^6.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-packlist": { + "version": "9.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/npm-packlist/-/npm-packlist-9.0.0.tgz", + "integrity": "sha1-jpsGG6uUDeY53ZPWWtyVw0QSx9A=", + "dev": true, + "dependencies": { + "ignore-walk": "^7.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "10.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/npm-pick-manifest/-/npm-pick-manifest-10.0.0.tgz", + "integrity": "sha1-bMEgxkc87qVt/q1QDwBzWyuJKFE=", + "dev": true, + "dependencies": { + "npm-install-checks": "^7.1.0", + "npm-normalize-package-bin": "^4.0.0", + "npm-package-arg": "^12.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "18.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/npm-registry-fetch/-/npm-registry-fetch-18.0.2.tgz", + "integrity": "sha1-NAQy9WtaixrwaN+RquBDXS3mRrU=", + "dev": true, + "dependencies": { + "@npmcli/redact": "^3.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^14.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^12.0.0", + "proc-log": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-run-all": { + "version": "4.1.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha1-BEdiAqFe4OLiFAgIYb/xKlHZj7o=", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm-run-all/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha1-q5tFRGblqMw6GHvqrVgEEqnFuEM=", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npm-run-all/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/npm-run-all/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/npm-run-all/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha1-MNDvoHEt2361p24ehyG/+vprXVc=", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/npm-run-all/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/npm-run-all/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha1-Gc0ZS/0+Qo8EmnCBfAONiatL41s=", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npm-run-all/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-5.7.2.tgz", + "integrity": "sha1-SNVdtzfDKHzUg14X+hP+rOHEHvg=", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npm-run-all/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/which": { + "version": "1.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/which/-/which-1.3.1.tgz", + "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha1-t+zR5e1T2o43pV4cImnguX7XSOo=", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha1-yeq0KO/842zWuSySS9sADvHx7R0=", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.22", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/nwsapi/-/nwsapi-2.2.22.tgz", + "integrity": "sha1-EJ+VMM2mwVbWpxPN9ZOenw3pi50=", + "dev": true + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha1-g3UmXiG8IND6WCwi4bE0hdbgAhM=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha1-jBTKGkJMalYbC7KiL2b1BJqUXT0=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha1-9xldipuXvZXLwZmeqTns0aKwDGU=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha1-mxJcNiOBKfb3thlUoecXYUjVAC4=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha1-3u1SClCAn/f3Wnz9S8ZMegOMYhY=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha1-Cb6jND1BhZ69RGKS0RydTbYZCE4=", + "dev": true, + "peer": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha1-WMjEQRblSEWtV/FKsQsDUzGErD8=", + "dev": true, + "peer": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha1-WdpPkcRfX5icbkvO3Fo7Cu1w/2U=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4=", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/open/-/open-10.1.0.tgz", + "integrity": "sha1-p3lebl1Rmr5ChtmTe7JLURIlmOE=", + "dev": true, + "peer": true, + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha1-eg//l49tv6TQBiOPusmO1BmMMlk=", + "dev": true, + "bin": { + "opencollective-postinstall": "index.js" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha1-fqHBpdkddk+yghOciP4R4YKjpzQ=", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ora/-/ora-5.4.1.tgz", + "integrity": "sha1-GyZ4Qmr0rEpQkAjl5KyemVnbnhg=", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha1-JkMFp65JDR0Dvwybp8kl0XU68wc=", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha1-OfZ8VLOnpYzqUjbZXPADQjljH34=", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha1-qaF2f4r4QVURTqq9c/mSc8j1mtk=", + "dev": true + }, + "node_modules/ordered-binary": { + "version": "1.6.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ordered-binary/-/ordered-binary-1.6.0.tgz", + "integrity": "sha1-nEkNrcCxM2ymkX2NQd1HS4wL/zI=", + "dev": true, + "optional": true + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha1-5ABpEKK/kTWFKJZ27r1vOQz1E1g=", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha1-4drMvnjQ0TiMoYxk/qOOPlfjcGs=", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha1-g8gxXGeFAF470CGDlBHJ4RDm2DQ=", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "7.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-map/-/p-map-7.0.3.tgz", + "integrity": "sha1-esIQotNvgewotzYTSBD3ukQYzbY=", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "6.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha1-gYKPjcYcbvWoAFhUkVcsyYknA68=", + "dev": true, + "peer": true, + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/retry/-/retry-0.13.1.tgz", + "integrity": "sha1-GFsVh6z2eRnWOzVzSeA1N7JIRlg=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha1-TxRxoBCCeob5TP2bByfjbSZ95QU=", + "dev": true + }, + "node_modules/pacote": { + "version": "20.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pacote/-/pacote-20.0.0.tgz", + "integrity": "sha1-yXQ3PY4IWdAOj5FYV0NQ+MGxaOU=", + "dev": true, + "dependencies": { + "@npmcli/git": "^6.0.0", + "@npmcli/installed-package-contents": "^3.0.0", + "@npmcli/package-json": "^6.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "@npmcli/run-script": "^9.0.0", + "cacache": "^19.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^12.0.0", + "npm-packlist": "^9.0.0", + "npm-pick-manifest": "^10.0.0", + "npm-registry-fetch": "^18.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^3.0.0", + "ssri": "^12.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pako/-/pako-1.0.11.tgz", + "integrity": "sha1-bJWZ00DVTf05RjgCUqNXBaa5kr8=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha1-4/s7XiZM+1XCW138vn9BD43E568=", + "dev": true, + "dependencies": { + "parse-statements": "1.0.11" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha1-x2/Gbe5UIxyWKyK8yKcs8vmXU80=", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-json/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha1-fEeAWpQxmSjgV3dAXcEuH3pO4C0=", + "dev": true + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha1-4rXb7eAOf6m8NjYH9TMn6LBzGJs=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha1-h4fF04OuV0ZWhXFhS+crBolYQ0Q=", + "dev": true + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha1-1+Ik+nI5nHoXUJn0X8KtAksF7AU=", + "dev": true, + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream": { + "version": "7.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha1-43bT52LSlQzLtrtZgj/B1+n9rDY=", + "dev": true, + "dependencies": { + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-sax-parser": { + "version": "7.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha1-TAUGQlTwSIZ2rKdfs5ygaeyW3uU=", + "dev": true, + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/entities/-/entities-6.0.1.tgz", + "integrity": "sha1-wow0pDN5yn9h0HQTCy9fcCCjBpQ=", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha1-+8EUtgykKzDZ2vWFjkvWi77bZzU=", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha1-eWCmaIiFlKByCxKpEdGnQqufEdI=", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha1-QQ/IoXtw5ZgBPfJXwkRrfzOD8Rk=", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha1-1eGhLkeKl21DLvPFjVNLmSMWS7c=", + "dev": true, + "peer": true + }, + "node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha1-Lxu2eRqRzpkZTK7eXWxZIO2B61E=", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha1-PTIa8+q5ObCDyPkpodEs2oHCa2s=", + "dev": true + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha1-d8dCkx6PO4gglGx2zQwfE3MNHas=", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha1-7wmsLMBTPfHzJQzPLE02aw0SEUo=", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha1-ZDtKGMQlfIplEEtz8wSc6aChXiI=", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/piscina": { + "version": "4.8.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/piscina/-/piscina-4.8.0.tgz", + "integrity": "sha1-X1xbH08/UPjeiUI5yYt7ENQbpKY=", + "dev": true, + "optionalDependencies": { + "@napi-rs/nice": "^1.0.1" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha1-jwwI1t9EdnVsX/KbMoLQurdRfRE=", + "dev": true, + "peer": true, + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha1-Krqz0ygLLcesEBme8yTE4ALIx5A=", + "dev": true, + "peer": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha1-acsXeb2Qs1qx53Hh8viaICwqioo=", + "dev": true, + "peer": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha1-kUr2VE7TK/pUZwsGHK/L0EmEtkQ=", + "dev": true, + "peer": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha1-PamknUk0uQEIncozAvpl3FoFwE8=", + "dev": true, + "peer": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha1-pqrZSJIAsh+rMeSc8JJ35RFvuec=", + "dev": true, + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/pkg-dir/node_modules/yocto-queue": { + "version": "1.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha1-NtfEc593Wzy8KOYTbiGqBXrexBg=", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha1-rt3T+ZTJM+StmLmdmlVu+g4v6UI=", + "dev": true, + "dependencies": { + "semver-compare": "^1.0.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha1-k+NYK8DlQmWG2dB7ee5A/IQd5K4=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/postcss/-/postcss-8.5.2.tgz", + "integrity": "sha1-57mcudLsPo3UJAAufBZRfLK4Rr0=", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-loader": { + "version": "8.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha1-KCJYnnUiknNElUrLVbvybosZXf4=", + "dev": true, + "peer": true, + "dependencies": { + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/postcss-loader/node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha1-NMP8WCh7kV866QWrbcPeJYtVrZ0=", + "dev": true, + "peer": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=", + "dev": true + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha1-tEl8uFqcDEtaq+t1m7JejYnxUAI=", + "dev": true, + "peer": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha1-0VD0ODeDHa4l5AhVluhPb11uw2g=", + "dev": true, + "peer": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha1-G7zN3LOY8delEeCi0dBHcYr0B4w=", + "dev": true, + "peer": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha1-18Xn5ow7s8myfL9Iyguz/7RgLJw=", + "dev": true, + "peer": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha1-TWr5frpl1zvE2EvLND6GXX3RYmI=", + "dev": true, + "peer": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha1-cjwJkgg2um0+WvAZ+SvAlxwC5RQ=", + "dev": true, + "peer": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha1-3rxkidem5rDnYRiIzsiAM30xY5Y=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha1-6MXX6YpDBf/j3i4fxKyhpxwosdo=", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha1-LUT+YTRSmu0YUG9tEVCdimJ3Xr4=", + "dev": true, + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha1-e99p/Fo2ilq9tJ/ZEDbFUiWEZHM=", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha1-qlGmwZRt8sWhFJSizbkxjgJtsWw=", + "dev": true + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha1-B0SWkK1Fd30ZJKwquy/IiV26g2s=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-quick": { + "version": "3.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pretty-quick/-/pretty-quick-3.3.1.tgz", + "integrity": "sha1-z96X/sd6jSAaDgyccdmZDhJYfuI=", + "dev": true, + "dependencies": { + "execa": "^4.1.0", + "find-up": "^4.1.0", + "ignore": "^5.3.0", + "mri": "^1.2.0", + "picocolors": "^1.0.0", + "picomatch": "^3.0.1", + "tslib": "^2.6.2" + }, + "bin": { + "pretty-quick": "dist/cli.js" + }, + "engines": { + "node": ">=10.13" + }, + "peerDependencies": { + "prettier": "^2.0.0" + } + }, + "node_modules/pretty-quick/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/execa/-/execa-4.1.0.tgz", + "integrity": "sha1-TlSRrRVy8vF6d9OIxshXE1sihHo=", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/pretty-quick/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-quick/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha1-SWaheV7lrOZecGxLe+txJX1uItM=", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-quick/node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha1-xbHNFPUK6uCatsWf5jujOV/k36M=", + "dev": true, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/pretty-quick/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha1-PNQOcp82Q/2HywTlC/DrcivFlvU=", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/pretty-quick/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-quick/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-quick/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-quick/node_modules/picomatch": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-3.0.1.tgz", + "integrity": "sha1-gXAzFh3vVeyWOFZ6Lzu8h2s+dRY=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pretty-quick/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha1-qaF2f4r4QVURTqq9c/mSc8j1mtk=", + "dev": true + }, + "node_modules/proc-log": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/proc-log/-/proc-log-5.0.0.tgz", + "integrity": "sha1-5sk883rvM/g1xTSF8xT1DqkGqdg=", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=", + "dev": true, + "peer": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha1-/3R6E2IKtXumiPX8Z4VUEMNw2iI=", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha1-e1fnOzpIAprRDr1E90sBcipMsGk=", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/protractor": { + "version": "7.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/protractor/-/protractor-7.0.0.tgz", + "integrity": "sha1-w+JjYIvXLiwtyAKxGncnEaR5LQM=", + "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.1.7", + "yargs": "^15.3.1" + }, + "bin": { + "protractor": "bin/protractor", + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=10.13.x" + } + }, + "node_modules/protractor/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha1-UR1wLAxOQcoVbX0OlgIfI+EyJbE=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha1-CCyyyJyf6GWaMRpTvWpNxTAdswQ=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha1-nibGPTD1NEPpSJSVshBdN7Z6hdk=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/protractor/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/protractor/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/protractor/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w=", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/protractor/node_modules/selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha1-K6h6FmLAILiYjJga5iyyoBKY6vw=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "engines": { + "node": ">= 6.9.0" + } + }, + "node_modules/protractor/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/source-map-support": { + "version": "0.4.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha1-Aoam3ovkJkEzhZTpfM6nXwosWF8=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/protractor/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha1-JpxxF9J7Ba0uU2gwqOyJXvnG0BA=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha1-CCyyyJyf6GWaMRpTvWpNxTAdswQ=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha1-nibGPTD1NEPpSJSVshBdN7Z6hdk=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/protractor/node_modules/tmp": { + "version": "0.0.30", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "os-tmpdir": "~1.0.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/protractor/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha1-tfJZyCzW4zaSHv17/Yv1YN6e7t8=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/protractor/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha1-DYehbeAa7p2L7Cv7909nhRcw9Pg=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha1-vmjEl1xrKr9GkjawyHA2L6sJp7A=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha1-8Z/mnOqzEe65S0LnDowgcPm6ECU=", + "dev": true, + "peer": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true, + "optional": true + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/psl/-/psl-1.15.0.tgz", + "integrity": "sha1-vazjGJbx2XzsannoIkiYzpPZdMY=", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pump/-/pump-3.0.3.tgz", + "integrity": "sha1-FR2XnxopZo3AAl7FiaRVtTKCJo0=", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha1-AnQi4vrsCyXhVJw+G9gwm5EztuU=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha1-0XPPIyWCMZdsy9sFJHyXh5V2BPI=", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/q": { + "version": "1.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/qs/-/qs-6.5.3.tgz", + "integrity": "sha1-Ou7/yRln7241wOSI70b7KWq3aq0=", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha1-M0WUG0FTy50ILY7uTNogFqmu9/Y=", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha1-SSkii7xyTfrEPg77BYyve2z7YkM=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo=", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha1-mf69g7kOCJdQh+jx+UGaFJNmtoo=", + "dev": true, + "peer": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", + "dev": true, + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha1-6DVX3BLq5jqZ4AOkY4ix3LtE234=", + "dev": true + }, + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha1-zvMdyOCho7sNEFwM2Xzzv0f0428=", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha1-VqmzbqllwAxak+8x6xEaDxEFaWc=", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha1-64WAFDX78qfuWPGeCSGwaPxplI0=", + "dev": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha1-QAyEW2y6h6IfLGXErrFY9PpNnFs=", + "dev": true + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha1-xikhnnijMW2LYEx2XvaJlpZOe/k=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha1-uTRtiCfo9aMve6KWN9OYtpAUhIo=", + "dev": true, + "peer": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha1-qhE4ErqJm2MGWMdiNGa+ceH4b2Y=", + "dev": true, + "peer": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha1-NWreECY/aF3aElEAzYYsHbiVMn8=", + "dev": true, + "peer": true + }, + "node_modules/regex-parser": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/regex-parser/-/regex-parser-2.3.1.tgz", + "integrity": "sha1-7j9w5QvdgaIh1QUkLLmpwnWirZE=", + "dev": true, + "peer": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha1-GtbGLUSiWQB+VbOXDgD3Ru+8qhk=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha1-NYDODE+u3vWZ7MsUZhJDa2KhduU=", + "dev": true, + "peer": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha1-3yP/JuDFswCmRwytFgqdCQw6N6s=", + "dev": true, + "peer": true + }, + "node_modules/regjsparser": { + "version": "0.13.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha1-Afg1EzXPeJjUNoa8dNLdcchH7MA=", + "dev": true, + "peer": true, + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/request/-/request-2.88.2.tgz", + "integrity": "sha1-1zyRhzHLWofaBH4gcjQUb2ZNErM=", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha1-3M5SwF9kTymManq5Nr1yTO/786Y=", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha1-zZ+yoKodWhK0c72fuW+j3P9lreI=", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha1-iaf92TgmEmcxjq/hT5wy5ZjDaQk=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha1-tmPoP/sJu/I4aURza6roAwKbizk=", + "dev": true, + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha1-DwB18bslRHZs9zumpuKt/ryxPy0=", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha1-w1IlhD3493bfIcV1V7wIfp39/Gk=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha1-7jFC+x8eDZ25Uk1TnPoWbpMU95U=", + "dev": true, + "peer": true, + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha1-i1yzi1w0qaAY7h/A5qBm0d/MUow=", + "dev": true, + "peer": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha1-QZVebxtAE7dYb4c3SaY13qB+vj8=", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha1-B2bZVpnvrLFBUJk/VbrwlT6h6+c=", + "dev": true, + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha1-nxbJLYye9RIOOs2d2ZV8zuzBq2A=", + "dev": true, + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha1-D+E7lSLhRz9RtVjueW4I8R+bSJ8=", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha1-d492xPtzHZNBTo+SX77PZMzn9so=", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha1-8aVAK6YiCtUswSgrrBrjqkn9Bho=", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.34.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rollup/-/rollup-4.34.8.tgz", + "integrity": "sha1-6FnBpR2Jmrqbz0UdTu0dEfuOKm4=", + "dev": true, + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.34.8", + "@rollup/rollup-android-arm64": "4.34.8", + "@rollup/rollup-darwin-arm64": "4.34.8", + "@rollup/rollup-darwin-x64": "4.34.8", + "@rollup/rollup-freebsd-arm64": "4.34.8", + "@rollup/rollup-freebsd-x64": "4.34.8", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", + "@rollup/rollup-linux-arm-musleabihf": "4.34.8", + "@rollup/rollup-linux-arm64-gnu": "4.34.8", + "@rollup/rollup-linux-arm64-musl": "4.34.8", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", + "@rollup/rollup-linux-riscv64-gnu": "4.34.8", + "@rollup/rollup-linux-s390x-gnu": "4.34.8", + "@rollup/rollup-linux-x64-gnu": "4.34.8", + "@rollup/rollup-linux-x64-musl": "4.34.8", + "@rollup/rollup-win32-arm64-msvc": "4.34.8", + "@rollup/rollup-win32-ia32-msvc": "4.34.8", + "@rollup/rollup-win32-x64-msvc": "4.34.8", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup/node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha1-Yo7/7q4gZKG055946B2Ht+X8e1A=", + "dev": true + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha1-Lp5UxGZOwxBsW1Yw4knT1llcSRE=", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha1-ZtE2jae9+SHrnZW9GpIp5/IaQ+4=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha1-lVvEc+2K8RoAKivlIHG/R1Y4YHs=", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/rxjs-marbles": { + "version": "7.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rxjs-marbles/-/rxjs-marbles-7.0.1.tgz", + "integrity": "sha1-kumTZqJklxl/DHAf+UTcRrqHZIc=", + "dev": true, + "dependencies": { + "fast-equals": "^2.0.0", + "rxjs-report-usage": "^1.0.4" + }, + "peerDependencies": { + "rxjs": "^7.0.0" + } + }, + "node_modules/rxjs-report-usage": { + "version": "1.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rxjs-report-usage/-/rxjs-report-usage-1.0.6.tgz", + "integrity": "sha1-bgYDTZ4VkuikW+6HdjFjjkusJXY=", + "dev": true, + "dependencies": { + "@babel/parser": "^7.10.3", + "@babel/traverse": "^7.10.3", + "@babel/types": "^7.10.3", + "bent": "~7.3.6", + "chalk": "~4.1.0", + "glob": "~7.2.0", + "prompts": "~2.4.2" + }, + "bin": { + "rxjs-report-usage": "bin/rxjs-report-usage" + } + }, + "node_modules/rxjs-report-usage/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha1-yeVOxPYDsLu45+UAel7nrs0VOMM=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha1-AYUOmBwWAtOYyFCB82Dk5tA9J/U=", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha1-f4fftnoxUHguqvGFg/9dFxGsEME=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", + "dev": true + }, + "node_modules/sass": { + "version": "1.85.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/sass/-/sass-1.85.0.tgz", + "integrity": "sha1-ASfvaX2DFESWQBVT8KDoe+g99F0=", + "dev": true, + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass-loader": { + "version": "16.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/sass-loader/-/sass-loader-16.0.5.tgz", + "integrity": "sha1-JXvJARmt4GaFHK/n8sPzUEx82pg=", + "dev": true, + "peer": true, + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/saucelabs": { + "version": "1.5.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha1-lAWnPDYNRJsjKDmRmobDltN5/Z0=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "https-proxy-agent": "^2.2.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/saucelabs/node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha1-gWXwHENgCbzK0LHRIvBe13Dvxu4=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/saucelabs/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/debug/-/debug-3.2.7.tgz", + "integrity": "sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/saucelabs/node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha1-TuenN6vZJniik9mzShr00NCMeHs=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/sax/-/sax-1.4.1.tgz", + "integrity": "sha1-RMyJiDd/EmME07P8EBDHM7kp7w8=", + "dev": true, + "optional": true + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha1-/ltKR2jfTxSiAbG6amXB89mYjMU=", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha1-WxhQkS+jHfkHFpY9RdkSH9/An0Y=", + "dev": true, + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha1-bmaUAGWet0lzu/LjMycYCgmWtSA=", + "dev": true, + "peer": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true, + "peer": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha1-Vg2QVlRCo+01tnQDTOxOldzrSuA=", + "dev": true, + "peer": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.7.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-7.7.1.tgz", + "integrity": "sha1-q9UJjYKxjGyB9gdP8mR/0+ciDJ8=", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, + "node_modules/semver-regex": { + "version": "3.1.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver-regex/-/semver-regex-3.1.4.tgz", + "integrity": "sha1-EwU8DUqhHQcKLyhytrHjrh4ZcbQ=", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/send/-/send-0.19.0.tgz", + "integrity": "sha1-u8WjiMjqbASJZwSdvqwOSj8J1/g=", + "dev": true, + "peer": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/debug/-/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "peer": true + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha1-3voeBVyDv21Z6oBdjahiJU62psI=", + "dev": true, + "peer": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "peer": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/debug/-/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "peer": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true, + "peer": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "peer": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=", + "dev": true, + "peer": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha1-tqU0PaR/a90mc4SL9FdUlB6AMpY=", + "dev": true, + "peer": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha1-qscjFBmOrtl1z3eyw7a4gGleVEk=", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha1-FqcFxaDcL15jjKltiozU4cK5CYU=", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha1-B2Dbz/MLLX6AH9bhmYPlbaM3Vl4=", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha1-ZsmiSnP5/CjL5msJ/tPTPcrxtCQ=", + "dev": true, + "peer": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha1-jymBrZJTH1UDWwH7IwdppA4C76M=", + "dev": true, + "peer": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo=", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha1-VeQO8zz1xomQI1Oj2M0aZyXwi0s=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha1-w/z/nE2pMnhIczNeyXZfqU/2a8k=", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha1-EMtZhCYxFdO3oOM2WR4pCoMK+K0=", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha1-1rtrN5Asb+9RdOX1M/q0xzKib0I=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha1-Ed2hnVNo5Azp7CvcH7DsvAeQ7Oo=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha1-lSGIwcvVRgcOLdIND0HArgUwywQ=", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sigstore": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/sigstore/-/sigstore-3.1.0.tgz", + "integrity": "sha1-CNxsDEJSY+n9q4X/22R3VQ4sUR0=", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^3.1.0", + "@sigstore/core": "^2.0.0", + "@sigstore/protobuf-specs": "^0.4.0", + "@sigstore/sign": "^3.1.0", + "@sigstore/tuf": "^3.1.0", + "@sigstore/verify": "^2.1.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha1-E01oEpd1ZDfMBcoBNw06elcQde0=", + "dev": true + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slash/-/slash-5.1.0.tgz", + "integrity": "sha1-vjrd3N8JrDjuvo3Nx7GlenWwlc4=", + "dev": true, + "peer": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha1-tzBjxXqpb5zYgWVLFSlNldKFxCo=", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha1-wETV3MUhoHZBNHJZehrLHxA8QEE=", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha1-bh1x+k8YwF99D/IW3RakgdDo2a4=", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha1-ybyJlfM6ERvqA5XsMKoyBr21zM4=", + "dev": true, + "peer": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha1-gNW1ztJxu5r2xEXyGhoExgbO++I=", + "dev": true, + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/socks/-/socks-2.8.7.tgz", + "integrity": "sha1-4vsdmmA63XUFCiBn24w4GgtWaeo=", + "dev": true, + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha1-uc205+mYUJ12WdaJznaXrCFkW+4=", + "dev": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha1-qbvnBcnYhG9OCP9nZazw8bCJhlY=", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha1-HOVlD93YerwJnto33P8CTCZnrkY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map-loader/-/source-map-loader-5.0.0.tgz", + "integrity": "sha1-9ZOpFuHMVEcc/IhRuQXIqEX8fjg=", + "dev": true, + "peer": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" + } + }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha1-pS+AvzjaGVLrXGgXkHGYcaGnJQE=", + "dev": true, + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha1-BP58f54e0tZiIzwoyys1ufY/bk8=", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha1-T1qwZo8AWeNPnADc4zF4ShLeTpw=", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha1-z3D1BILu/cmOPOCmgz5KU87rpnk=", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha1-XWB9J/yAb2bXtkp2ZlD6iQ8E7WY=", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha1-ojr58xMhFUZdrCFcCZMD5M6sV5Q=", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha1-q/Wgim9dcnlVm2afR/CkPo80ZO8=", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha1-t09GYgOj7aRSwCSSuR+56EonZ3s=", + "dev": true, + "peer": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha1-ANSGOmQArXXfkzYaFghgXl3NzzE=", + "dev": true, + "peer": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha1-FmPlXN301oi4aka3fw1f42OroCg=", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "12.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ssri/-/ssri-12.0.0.tgz", + "integrity": "sha1-vLQlhBfHAkcvgZGYHTyKdx/uaDI=", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha1-qvB0gWnAL8M8gjKrzPkz9Uocw08=", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha1-owME6Z2qMuI7L9IPUbq9B8/8o0Q=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha1-VcsADM8dSHKL0jxoWgY5mM8aG2M=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha1-9IH/cKVI9hJNAxLDqhTL+nqlQq0=", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4=", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha1-qKjce9XBqCubPIuH4SX2aHG25Xo=", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha1-tbuOIWXOJ11NQ0dt0nAK2Qkdttw=", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha1-JpxxF9J7Ba0uU2gwqOyJXvnG0BA=", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha1-YCFu6kZNhkWXzigyAAc4oFiWUME=", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha1-Eyh1q95njH6o1pFTPy5+Irt0Tbo=", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.padend": { + "version": "3.1.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", + "integrity": "sha1-unnPiZJgmpHIctqkfGuxRO5/YqU=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha1-QLLdXulMlZtNz7HWXOcukNpIDIE=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha1-YuJzEnLNKFBBs2WWBU6fZlabaUI=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha1-fug03ajHwX7/MRhHK7Nb/tqjTd4=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha1-nibGPTD1NEPpSJSVshBdN7Z6hdk=", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha1-nibGPTD1NEPpSJSVshBdN7Z6hdk=", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha1-nDUFwdtFvO3KPZz3oW9cWqOQGHg=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha1-ibhS+y/L6Tb29LMYevsKEsGrWK0=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY=", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha1-btpL00SjyUrqN21MwxvHcxEDngk=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha1-W0JfGSJ56H8vm5N6yFQNGYSzkgU=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha1-QwY30ki6d+B4iDlR+5qg7tfGP6I=", + "dev": true + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha1-fj6m1coxuo4Hi1YPDYPOmhSqi+Y=", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tar/-/tar-6.2.1.tgz", + "integrity": "sha1-cXVJxUG8PCrxV1G+qUsd0GjUsDo=", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha1-f1A2/b8SxjwWkZDL5BmchSJx+fs=", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha1-e7o4TbOhUg0YycDlJRw0ROld2Uo=", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha1-PpeI/7kLaUpdDslEeaRbXYc4Ez0=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha1-6Q00Zrogm5MkUVCKEc49NjIUWTE=", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha1-e7o4TbOhUg0YycDlJRw0ROld2Uo=", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha1-PrXtYmInVteaXw4qIh3+utdcL34=", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", + "dev": true + }, + "node_modules/terser": { + "version": "5.39.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/terser/-/terser-5.39.0.tgz", + "integrity": "sha1-DoIDPtV7Pd8flnCNEjzKcX2Gyjo=", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.14", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha1-kDHUjlerJ1Z/AqzoXH1pDbZsPgY=", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha1-jRRvCQDolzsQa29zzB6ajLhvjbA=", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha1-zW/BfihQDP9WwbhsCn/UpUpzAFw=", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/commander/-/commander-2.20.3.tgz", + "integrity": "sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=", + "dev": true, + "peer": true + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha1-BKhphmHYBepvopO2y55jrARO8V4=", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha1-q5tFRGblqMw6GHvqrVgEEqnFuEM=", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha1-Gc0ZS/0+Qo8EmnCBfAONiatL41s=", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/thingies": { + "version": "2.5.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/thingies/-/thingies-2.5.0.tgz", + "integrity": "sha1-X3uILJM7hZifhGa1KKYkemiB4E8=", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "^2" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha1-Wrr3FKlAXbBQRzK7zNLO3Z75U30=", + "dev": true, + "peer": true + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha1-4ijdHmOM6pk9L9tPzS1GAqeZUcI=", + "dev": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha1-eWx2E20e6tcV2x57rXhd7daVoEI=", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha1-hoPguQK7nCDE9ybjwLafNlGMB8w=", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha1-O+NDIaiKgg7RvYDfqjPkefu43TU=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha1-lF8UYbRbWox2ghwz6knDrBksGzY=", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha1-ZFF2BWb6hXU0dFqx3elS0bF2G+A=", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha1-VVxOKXqVBhfo7t3vYzyH1NnWy/k=", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/tree-dump": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tree-dump/-/tree-dump-1.1.0.tgz", + "integrity": "sha1-qykSkWncRgBEFPWp1KPG6J8T6KQ=", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha1-TKCakJLIi3OnzcXooBtQeweQoMw=", + "dev": true, + "peer": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha1-WV9wlORu7TZME/0j51+VE9Kbr5E=", + "dev": true, + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-jest": { + "version": "29.4.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ts-jest/-/ts-jest-29.4.5.tgz", + "integrity": "sha1-prDcQB5SFRXVNCI0vofxypY5Cm8=", + "dev": true, + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.3", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-7.7.3.tgz", + "integrity": "sha1-S19BQ9AHYzqNxnHNCm75FHuLuUY=", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha1-auHI5XMSc8K/H1itOcuuLJGkbFg=", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ts-node": { + "version": "9.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ts-node/-/ts-node-9.0.0.tgz", + "integrity": "sha1-52mdKhEMyMDTuDFxXkF2iGg0YLM=", + "dev": true, + "dependencies": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "typescript": ">=2.7" + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha1-73jhkDkTNEbSRL6sD9ahYy4tEHw=", + "dev": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha1-YS7+TtI11Wfoq6Xypfq3AoCt6D8=" + }, + "node_modules/tuf-js": { + "version": "3.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tuf-js/-/tuf-js-3.1.0.tgz", + "integrity": "sha1-YbhH/pqoan1b2mVaRkfgJqpzob4=", + "dev": true, + "dependencies": { + "@tufjs/models": "3.0.1", + "debug": "^4.4.1", + "make-fetch-happen": "^14.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha1-B7ggO/pwVsBlcFDjzNLDdzC6uPE=", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha1-dkb7XxiHHPu3dJ5pvTmmOI63RQw=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha1-G/IH9LKPkVg2ZstfvTJ4hzAc1fQ=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", + "dev": true, + "peer": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha1-pyOVRQpIaewDP9VJNxtHrzou5TY=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha1-hAegT314aE89JSqhoUPSt3tBYM4=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha1-rjaYuOyRqKuUUBYQiu8A1b/xI1U=", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha1-7k3v+YS2S+HhGLDejJyHfVznPT0=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha1-ivnU+TQyxJcOxxfjAG8z8TWwYhM=", + "dev": true, + "peer": true + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha1-kvij5ePPSXNW9BeMNM1lp/XoRA4=", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha1-gjFem7xvKyWIiFis0f/4RBA1t38=", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha1-jZ0snt7qhGDH81AzqIhnlEk00eI=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha1-vNU5iT0AtW6WT9JlekhmsiGmVhc=", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha1-yzFz/kfKdD4ighbko93EyE1ijMI=", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha1-VP0W4OyxZ88Ezx91a9zJLrp5dsM=", + "dev": true, + "peer": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha1-Zaet+thXTCGYkOIZKFzkxk7Wfqo=", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha1-MB1PikPSt1yXrfrYfJ3VNQyUddE=", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha1-Tv1FyFpp4N1XbSVTL7+iKqXIoQQ=", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-filename": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/unique-filename/-/unique-filename-4.0.0.tgz", + "integrity": "sha1-oGU003DnyXepOc0dEffwq48f7RM=", + "dev": true, + "dependencies": { + "unique-slug": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/unique-slug": { + "version": "5.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/unique-slug/-/unique-slug-5.0.0.tgz", + "integrity": "sha1-ynKvA60NurTa2KpoP2M4eLGszag=", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha1-eAKqKukUd/JVuG4ORtvHh6IGrUo=", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha1-mxpSWVIlhZ5V9mnZKPiMbFfyp34=", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha1-nTwvc2wddd070r5QfcwRHx4uqcE=", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha1-Yzbo1xllyz01obu3hoRFp8BSZL8=", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha1-uVcqv6Yr1VbBbXX968GkEdX/MXU=", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha1-S1YPZJ/E6RjdCrdc9JYei8iC2Co=", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha1-/JH2uce6FchX9MssXe/uw51PQQo=", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha1-z3D1BILu/cmOPOCmgz5KU87rpnk=", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "6.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/validate-npm-package-name/-/validate-npm-package-name-6.0.2.tgz", + "integrity": "sha1-To0sTZOZdac90bemXo8I1EyF35Y=", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/vite/-/vite-6.4.1.tgz", + "integrity": "sha1-r74UUYzdaIfiQKSwIhq20M5zP5Y=", + "dev": true, + "peer": true, + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", + "integrity": "sha1-D0Si+GaO2HsEC2/mWTWKySOdpNs=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", + "integrity": "sha1-JbmgHe72UYqUhDFWTJh7yyBSdPU=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", + "integrity": "sha1-ihAoaciPN4DH1eZ3av0/GQhOzX8=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", + "integrity": "sha1-jlJkF81vVNrx0MBM82EWAhZYGVY=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", + "integrity": "sha1-DnAnBUST80CbHyGaPqxe/RKO+Jk=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", + "integrity": "sha1-crIEqSATnp7D0zG9nP2aDCSMyxA=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", + "integrity": "sha1-qxtSLr5bfgbJlQTMOPbNi4CLpBw=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", + "integrity": "sha1-+Mwwtjjx7n49GOrCSvR+op2b6wA=", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", + "integrity": "sha1-evN6noXyXbWdyCFBcpB7fhRsEsw=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", + "integrity": "sha1-piPrDTYXwDt6c3FuuFxuN7d29+A=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", + "integrity": "sha1-h6sDPuvRqaHde2BQn2Mz7B+C2ZQ=", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", + "integrity": "sha1-97wQ++CWq0RpQjPcQqIpHtVFPUs=", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", + "integrity": "sha1-oVHLEjTMmyz16M/AKqkUNrj54ng=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", + "integrity": "sha1-eFnhllAcw7MGLUXSd2z7TS86k1A=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", + "integrity": "sha1-5iNX0ARY2xcne4itv2kLuFXKyTc=", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", + "integrity": "sha1-/HzUD0SDSnA8Hxw/6LzCfOR2zVA=", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/vite/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", + "integrity": "sha1-Flf1Yya74KyA7tyfnBj8Hd0k4Qc=", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/vite/node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha1-KCUAZhWmGbT2Kp50JswSCzSajzw=", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/vite/node_modules/rollup": { + "version": "4.52.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rollup/-/rollup-4.52.5.tgz", + "integrity": "sha1-lpgs3K7c3VGxI1mYHyQPlDBOwjU=", + "dev": true, + "peer": true, + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.5", + "@rollup/rollup-android-arm64": "4.52.5", + "@rollup/rollup-darwin-arm64": "4.52.5", + "@rollup/rollup-darwin-x64": "4.52.5", + "@rollup/rollup-freebsd-arm64": "4.52.5", + "@rollup/rollup-freebsd-x64": "4.52.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", + "@rollup/rollup-linux-arm-musleabihf": "4.52.5", + "@rollup/rollup-linux-arm64-gnu": "4.52.5", + "@rollup/rollup-linux-arm64-musl": "4.52.5", + "@rollup/rollup-linux-loong64-gnu": "4.52.5", + "@rollup/rollup-linux-ppc64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-musl": "4.52.5", + "@rollup/rollup-linux-s390x-gnu": "4.52.5", + "@rollup/rollup-linux-x64-gnu": "4.52.5", + "@rollup/rollup-linux-x64-musl": "4.52.5", + "@rollup/rollup-openharmony-arm64": "4.52.5", + "@rollup/rollup-win32-arm64-msvc": "4.52.5", + "@rollup/rollup-win32-ia32-msvc": "4.52.5", + "@rollup/rollup-win32-x64-gnu": "4.52.5", + "@rollup/rollup-win32-x64-msvc": "4.52.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha1-rr3ISSDYBiIpNuPNzkCOMkiKMHM=", + "dev": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/walker/-/walker-1.0.8.tgz", + "integrity": "sha1-vUmNtHev5XPcBBhfAR06uKjXZT8=", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha1-L+6u1nQS58MxhOWnnKc4+9OFZNo=", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha1-wdjRSTFtPqhShIiVy2oL/oh7h98=", + "dev": true, + "peer": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha1-/btnQfNrrpVA0S9IDOglQGDczRk=", + "dev": true, + "optional": true + }, + "node_modules/webdriver-js-extender": { + "version": "2.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", + "integrity": "sha1-V9epPADbTMjVVuTT20tdsKgMO7c=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/selenium-webdriver": "^3.0.0", + "selenium-webdriver": "^3.0.1" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webdriver-js-extender/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w=", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/webdriver-js-extender/node_modules/selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha1-K6h6FmLAILiYjJga5iyyoBKY6vw=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "engines": { + "node": ">= 6.9.0" + } + }, + "node_modules/webdriver-js-extender/node_modules/tmp": { + "version": "0.0.30", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "os-tmpdir": "~1.0.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webdriver-manager": { + "version": "12.1.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/webdriver-manager/-/webdriver-manager-12.1.9.tgz", + "integrity": "sha1-jYNUO5JxG3IXs5/vTNqVikcD0t8=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "adm-zip": "^0.5.2", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + }, + "bin": { + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webdriver-manager/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/webdriver-manager/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ini/-/ini-1.3.8.tgz", + "integrity": "sha1-op2kJbSIBvNHZ6Tvzjlyaa8oQyw=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/webdriver-manager/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w=", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/webdriver-manager/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/semver/-/semver-5.7.2.tgz", + "integrity": "sha1-SNVdtzfDKHzUg14X+hP+rOHEHvg=", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/webdriver-manager/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha1-JWtOGIK+feu/AdBfCqIDl3jqCAo=", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/webpack": { + "version": "5.98.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/webpack/-/webpack-5.98.0.tgz", + "integrity": "sha1-RK4ZqPK6l1N5eCRgcvuJ0Q0fvRc=", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "7.4.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", + "integrity": "sha1-QOJlo9PSZ5VYXP+CB2MNOo/wWHc=", + "dev": true, + "peer": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.6.0", + "mime-types": "^2.1.31", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server": { + "version": "5.2.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/webpack-dev-server/-/webpack-dev-server-5.2.2.tgz", + "integrity": "sha1-lqFD1QxY/vDHkQfmHfkRco186zk=", + "dev": true, + "peer": true, + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/express-serve-static-core": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "express": "^4.21.2", + "graceful-fs": "^4.2.6", + "http-proxy-middleware": "^2.0.9", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha1-GXxsxmnvKo3F57TZfuTgksPrDVs=", + "dev": true, + "peer": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/webpack-dev-server/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ=", + "dev": true, + "peer": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { + "version": "2.0.9", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha1-6eY9aK+qTu49FH85FJq4TAwoFe8=", + "dev": true, + "peer": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", + "dev": true, + "peer": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/webpack-dev-server/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha1-dKNwvYVxFuJFspzJc0DNQxoCpsc=", + "dev": true, + "peer": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha1-UMd2ho4IBXRyWrxYab1uTvChbGo=", + "dev": true, + "peer": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.3.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha1-1L9/mQlnXXoHD/FNDvKk88mCxyM=", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha1-i3YGsDPGzKwU5oQmfLf7H1wqEyo=", + "dev": true, + "peer": true, + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha1-54blmmbLkrP2wfsNUIqrF0hI9Iw=", + "dev": true, + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0=", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/webpack/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha1-fEeAWpQxmSjgV3dAXcEuH3pO4C0=", + "dev": true, + "peer": true + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha1-ia1Slbv2S0gKvLox5JU6ynBvV2A=", + "dev": true, + "peer": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha1-f4RzvIOd/YdgituV1+sHUhFXikI=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha1-52NfWX/YcCCFhiaAWicp+naYrFM=", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha1-pS+AvzjaGVLrXGgXkHGYcaGnJQE=", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha1-X6GnYjhn/xr2yj3HKta4pCCL66c=", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha1-CoSe67X68hGbkBu3b9eVwoSNQBg=", + "dev": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/which/-/which-2.0.2.tgz", + "integrity": "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha1-127Cfff6Fl8Y1YCDdKX+I8KbF24=", + "dev": true, + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha1-iRg9obSQerCJprAgKcxdjWV0Jw4=", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha1-Yn73YkOSChB+fOjpYZHevksWwqA=", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha1-d2sf412Qrr6Z6KwV6yQJM4mkpAk=", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/which-pm-runs": { + "version": "1.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha1-Ncz3saD86HvYuSpHjJ0EV4XTvzU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha1-3wOELocLa4jhF1JKSzZLb8aJ+VY=", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha1-WrENAkhxmJVINrY0n3T/+WHhD2c=", + "dev": true, + "peer": true + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha1-0sRcbdT7zmIaZvE2y+Mor9BBCzQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha1-6Tk7oHEC5skaOyIUePAlfNKFblM=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha1-Z+FFz/UQpqaYS98RUpEdadLrnkM=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha1-JpxxF9J7Ba0uU2gwqOyJXvnG0BA=", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha1-JpxxF9J7Ba0uU2gwqOyJXvnG0BA=", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha1-qd8Brlt3hYoCf9LoB2juQzVV/P0=", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha1-qaF2f4r4QVURTqq9c/mSc8j1mtk=", + "dev": true + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/ws/-/ws-8.18.3.tgz", + "integrity": "sha1-tWuIq//eYnkcY5FwQAyT3LDJVHI=", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha1-eaAG4uYxSahgDxVDDwpHJdFSSDU=", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha1-oMaVFnUkIesqx1juTUzPWIQ+rGY=", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha1-vpuuHIoEbnazESdyY0fQrXACvrM=", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha1-Bg/hvLf5x2/ioX24apvDq4lCEMs=", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha1-f0k00PfKjFb5UxSTndzS3ZHOHVU=", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha1-27fa+b/YusmrRev2ArjLrQ1dCP0=", + "dev": true + }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha1-GHCqArYx9+gyi5P4vFdPrF1sTXk=", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha1-mR3zmspnWhkrgW4eA2P5110qomk=", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha1-kJa87r+ZDSG7MfqVFuDt4pSnfTU=", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", + "dev": true + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha1-JpxxF9J7Ba0uU2gwqOyJXvnG0BA=", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yn/-/yn-3.1.1.tgz", + "integrity": "sha1-HodAGgnXZ8HV6rJqbkwYUYLS61A=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha1-ApTrPe4FAo0x7hpfosVWpqrxChs=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha1-fklk6o7EIrekCskX06NEz9IwS6o=", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zone.js": { + "version": "0.15.1", + "resolved": "https://mdvartrepo01.cpp.nonlive:443/artifactory/api/npm/npm-virtual/zone.js/-/zone.js-0.15.1.tgz", + "integrity": "sha1-HhCa23X4Dp4ATujg1KClLgozZIE=", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fcbbabb --- /dev/null +++ b/package.json @@ -0,0 +1,97 @@ +{ + "name": "cpp.ui.core", + "version": "19.0.5", + "repository": { + "type": "git", + "url": "https://github.com/hmcts/cpp-ui-core" + }, + "license": "UNLICENSED", + "scripts": { + "ng": "ng", + "format": "pretty-quick --staged", + "start": "ng serve", + "build": "ng build", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e", + "build:testing": "rm -rf ./dist/testing && npx tsc --p ./projects/testing/tsconfig.json && cp ./projects/testing/package.json ./dist/testing/package.json", + "ci:build": "ng build core && ng build users-groups && ng build reference-data && ng build scheduling && npm run build:testing", + "ci:aot": "exit 0", + "ci:e2e": "exit 0", + "ci:lint": "mkdirp ./build/lint && ng lint --format checkstyle | sed 's/Linting.*$//' > ./build/lint/checkstyle-result.xml", + "ci:lint:sonar": "exit 0", + "ci:nsp": "exit 0", + "ci:prepublish": "node .scripts/version.js", + "ci:publish": "npm run ci:prepublish && npm publish dist/core/ && npm publish dist/reference-data/ && npm publish dist/testing/ && npm publish dist/users-groups/ && npm publish dist/scheduling/", + "ci:test": "ng test --ci --coverage --silent" + }, + "husky": { + "hooks": { + "pre-commit": "run-s format lint" + } + }, + "devDependencies": { + "@angular-builders/jest": "^19.0.1", + "@angular-devkit/core": "^19.2.15", + "@angular-eslint/builder": "19.8.1", + "@angular-eslint/eslint-plugin": "19.8.1", + "@angular-eslint/eslint-plugin-template": "19.8.1", + "@angular-eslint/schematics": "19.8.1", + "@angular-eslint/template-parser": "19.8.1", + "@angular/animations": "^19.2.14", + "@angular/build": "^19.2.15", + "@angular/cdk": "^19.2.19", + "@angular/cli": "^19.2.15", + "@angular/common": "^19.2.14", + "@angular/compiler": "^19.2.14", + "@angular/compiler-cli": "^19.2.14", + "@angular/core": "^19.2.14", + "@angular/forms": "^19.2.14", + "@angular/language-service": "^19.2.14", + "@angular/platform-browser": "^19.2.14", + "@angular/platform-browser-dynamic": "^19.2.14", + "@angular/router": "^19.2.14", + "@cpp/pdk": "^19.0.2", + "@kolkov/angular-editor": "^2.1.0", + "@ngrx/effects": "^19.2.1", + "@ngrx/store": "^19.2.1", + "@types/jest": "^30.0.0", + "@types/lodash-es": "^4.17.7", + "@types/node": "^18.19.122", + "@types/request": "^2.48.4", + "@types/uuid": "^3.4.4", + "@types/ws": "^8.5.4", + "@typescript-eslint/eslint-plugin": "^8.38.0", + "@typescript-eslint/parser": "^8.38.0", + "chalk": "^3.0.0", + "core-js": "^2.5.4", + "eslint": "^8.57.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-import": "latest", + "eslint-plugin-jsdoc": "^52.0.1", + "eslint-plugin-prefer-arrow": "latest", + "husky": "^4.2.5", + "jasmine-marbles": "^0.9.2", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.5.0", + "jest-jasmine2": "^29.5.0", + "jest-preset-angular": "^14.5.4", + "lodash-es": "^4.17.21", + "ng-packagr": "^19.2.2", + "npm-run-all": "^4.1.5", + "prettier": "^2.8.4", + "pretty-quick": "^3.1.3", + "mkdirp": "^3.0.1", + "request": "^2.88.0", + "rxjs": "^7.8.2", + "rxjs-marbles": "^7.0.1", + "ts-jest": "^29.4.1", + "ts-node": "~9.0.0", + "typescript": "^5.8.3", + "zone.js": "^0.15.1" + }, + "dependencies": { + "@ngrx/operators": "^19.2.1", + "tslib": "^2.0.0" + } +} diff --git a/projects/core/.eslintrc.json b/projects/core/.eslintrc.json new file mode 100644 index 0000000..752fd3e --- /dev/null +++ b/projects/core/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["projects/core/tsconfig.lib.json", "projects/core/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "extends": ["prettier"], + "rules": { + "@angular-eslint/component-class-suffix": "off", + "@typescript-eslint/consistent-type-definitions": "off", + "@typescript-eslint/dot-notation": "off", + "@typescript-eslint/explicit-member-accessibility": [ + "off", + { + "accessibility": "explicit" + } + ], + "@angular-eslint/component-selector": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/unified-signatures": "off", + "id-blacklist": "off", + "id-match": "off", + "no-underscore-dangle": "off" + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/projects/core/ng-package.json b/projects/core/ng-package.json new file mode 100644 index 0000000..11ae972 --- /dev/null +++ b/projects/core/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/core", + "lib": { + "entryFile": "src/index.ts" + } +} diff --git a/projects/core/package.json b/projects/core/package.json new file mode 100644 index 0000000..94c22a0 --- /dev/null +++ b/projects/core/package.json @@ -0,0 +1,14 @@ +{ + "name": "@cpp/core", + "version": "0.0.0-PLACEHOLDER", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": "^19.0.0", + "@angular/core": "^19.0.0", + "@angular/router": "^19.0.0", + "rxjs": "^7.0.0", + "uuid": "^3.3.2" + } +} diff --git a/projects/core/src/capabilities/__tests__/capabilities.spec.ts b/projects/core/src/capabilities/__tests__/capabilities.spec.ts new file mode 100644 index 0000000..015b37f --- /dev/null +++ b/projects/core/src/capabilities/__tests__/capabilities.spec.ts @@ -0,0 +1,318 @@ +import { Component } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { HttpClient } from '@angular/common/http'; +import { By } from '@angular/platform-browser'; +import { marbles } from 'rxjs-marbles/jest'; +import { finalize } from 'rxjs/operators'; + +import { CapabilitiesService } from '../service'; +import { CppHttpBackend } from '../../http/http-backend'; +import { CapabilityRestrictedGuard } from '../guards'; +import { provideCppCapabilities } from '../providers'; +import { provideCppCoreHttpServices } from '../../http/providers'; +import { + CapabilityEnabledComponent as CapabilityEnabledDirective, + CapabilityDisabledComponent as CapabilityDisabledDirective +} from '../directives'; + +describe('CapabilitiesModule', () => { + describe('CapabilitiesService', () => { + let getManifest: jest.Mock; + let getStatuses: jest.Mock; + let http: CppHttpBackend; + let httpClient: HttpClient; + let service: CapabilitiesService; + + beforeEach(() => { + getManifest = jest.fn(); + getStatuses = jest.fn(); + + TestBed.configureTestingModule({ + providers: [ + provideCppCoreHttpServices(), + { + provide: HttpClient, + useValue: { + get: getManifest + } + }, + { + provide: CppHttpBackend, + useValue: { + get: getStatuses + } + }, + provideCppCapabilities({ manifestPath: '/manifest.json' }) + ] + }); + http = TestBed.inject(CppHttpBackend); + httpClient = TestBed.inject(HttpClient); + service = TestBed.inject(CapabilitiesService); + }); + + describe('#load', () => { + it( + 'resolves and caches a list of enabled capabilities', + marbles((m) => { + expect.assertions(4); + + const manifest = { + capabilities: [ + { name: 'capability.a', type: 'ui.component', description: '*' }, + { name: 'capability.b', type: 'ui.component', description: '*' } + ] + }; + const statuses = { + capabilities: [ + { name: 'capability.a', enabled: true }, + { name: 'capability.b', enabled: false } + ] + }; + const capabilities = [ + { name: 'capability.a', type: 'ui.component', description: '*', enabled: true }, + { name: 'capability.b', type: 'ui.component', description: '*', enabled: false } + ]; + const manifest$ = m.cold('-(a|)', { a: manifest }); + const statuses$ = m.cold('-(b|)', { b: statuses }); + const expected$ = m.cold('-(c|)', { c: capabilities }); + + getManifest.mockReturnValue(manifest$); + getStatuses.mockReturnValue(statuses$); + + const loadCapabilities$ = service.loadCapabilites().pipe( + finalize(() => { + expect(httpClient.get).toHaveBeenCalledWith('/manifest.json'); + expect(http.get).toHaveBeenCalledWith( + `/authorisation-service-server/rest/capabilities?type=ui`, + 'application/vnd.authorisation.capabilities+json' + ); + expect(service['capabilities']).toEqual(capabilities); + }) + ); + + m.expect(loadCapabilities$).toBeObservable(expected$); + }) + ); + + it( + 'requires a cross-section of the enabled capabilities with those defined in the manifest', + marbles((m) => { + expect.assertions(1); + + const manifest = { + capabilities: [{ name: 'capability.a', type: 'ui.component', description: '*' }] + }; + const statuses = { + capabilities: [ + { name: 'capability.a', type: 'ui.component', enabled: true }, + { name: 'capability.b', type: 'ui.component', enabled: false } + ] + }; + const capabilities = [ + { name: 'capability.a', type: 'ui.component', description: '*', enabled: true } + ]; + const manifest$ = m.cold('-(a|)', { a: manifest }); + const statuses$ = m.cold('-(b|)', { b: statuses }); + const expected$ = m.cold('-(c|)', { c: capabilities }); + + getManifest.mockReturnValue(manifest$); + getStatuses.mockReturnValue(statuses$); + + m.expect(service.loadCapabilites()).toBeObservable(expected$); + }) + ); + }); + + describe('#getCababilityEnabled', () => { + beforeEach(() => { + service['capabilities'] = [ + { name: 'capability.a', type: 'ui.component', description: '*', enabled: true }, + { name: 'capability.b', type: 'ui.component', description: '*', enabled: false } + ] as any[]; + }); + + it('returns a boolean according to a capability being enabled', () => { + expect(service.getCapabilityEnabled('capability.a')).toEqual(true); + expect(service.getCapabilityEnabled('capability.b')).toEqual(false); + }); + + it('throws an error when a capability is not recognised', () => { + expect(() => service.getCapabilityEnabled('capability.c')).toThrow(); + }); + }); + }); + + describe('CapabilityRestrictedGuard', () => { + let getCapabilityEnabled: jest.Mock; + let guard: CapabilityRestrictedGuard; + + beforeEach(() => { + getCapabilityEnabled = jest.fn(); + + TestBed.configureTestingModule({ + providers: [ + provideCppCoreHttpServices(), + provideCppCapabilities({ manifestPath: '/manifest.json' }), + { provide: CapabilitiesService, useValue: { getCapabilityEnabled } } + ] + }); + guard = TestBed.inject(CapabilityRestrictedGuard); + }); + + it( + 'restricts access to disabled routes', + marbles((m) => { + let canActivate$; + let expected$; + + const activate = (requireCapabilityEnabled: string) => + guard.canActivate({ + data: { requireCapabilityEnabled } + } as any); + + getCapabilityEnabled.mockReturnValueOnce(true); + + canActivate$ = activate('capability.a'); + expected$ = m.cold('(a|)', { a: true }); + + expect(getCapabilityEnabled).toHaveBeenCalledWith('capability.a'); + m.expect(canActivate$).toBeObservable(expected$); + + getCapabilityEnabled.mockReturnValueOnce(false); + + canActivate$ = activate('capability.a'); + expected$ = m.cold('(a|)', { a: false }); + + m.expect(canActivate$).toBeObservable(expected$); + }) + ); + + it( + 'restricts access to disabled routes', + marbles((m) => { + let canActivate$; + let expected$; + + const activate = (requireCapabilityDisabled: string) => + guard.canActivate({ + data: { requireCapabilityDisabled } + } as any); + + getCapabilityEnabled.mockReturnValueOnce(false); + + canActivate$ = activate('capability.a'); + expected$ = m.cold('(a|)', { a: true }); + + expect(getCapabilityEnabled).toHaveBeenCalledWith('capability.a'); + m.expect(canActivate$).toBeObservable(expected$); + + getCapabilityEnabled.mockReturnValueOnce(true); + + canActivate$ = activate('capability.a'); + expected$ = m.cold('(a|)', { a: false }); + + m.expect(canActivate$).toBeObservable(expected$); + }) + ); + + it( + 'throws an error when no capability requirement is specified', + marbles((m) => { + const canActivate$ = guard.canActivate({ data: {} } as any); + const expected = m.cold( + '#', + undefined, + 'No capability provided to capability-restricted route!' + ); + + m.expect(canActivate$).toBeObservable(expected); + }) + ); + }); + + describe('[capability-enabled]', () => { + let getCapabilityEnabled: jest.Mock; + + beforeEach(() => { + getCapabilityEnabled = jest.fn(); + + TestBed.configureTestingModule({ + imports: [CapabilityEnabledDirective], + declarations: [CapabilityEnabledComponent], + providers: [ + provideCppCoreHttpServices(), + provideCppCapabilities({ manifestPath: '/manifest.json' }), + { + provide: CapabilitiesService, + useValue: { getCapabilityEnabled } + } + ] + }); + }); + + it('removes any element from the DOM when a capability is disabled', async () => { + const fixture = TestBed.createComponent(CapabilityEnabledComponent); + getCapabilityEnabled.mockReturnValue(true); + fixture.detectChanges(); + expect(getCapabilityEnabled).toHaveBeenCalledWith('capability.a'); + await fixture.whenRenderingDone(); + await fixture.whenStable(); + expect(fixture.debugElement.query(By.css('p'))).toBeTruthy(); + getCapabilityEnabled.mockReturnValue(false); + fixture.detectChanges(); + expect(fixture.debugElement.query(By.css('p'))).toBeFalsy(); + }); + + @Component({ + selector: 'capability-enabled', + template: `

PDK!

`, + standalone: false + }) + class CapabilityEnabledComponent {} + }); + + describe('[capability-disabled]', () => { + let getCapabilityEnabled: jest.Mock; + + beforeEach(() => { + getCapabilityEnabled = jest.fn(); + + TestBed.configureTestingModule({ + imports: [CapabilityDisabledDirective], + declarations: [CapabilityDisabledComponent], + providers: [ + provideCppCoreHttpServices(), + provideCppCapabilities({ manifestPath: '/manifest.json' }), + { + provide: CapabilitiesService, + useValue: { getCapabilityEnabled } + } + ] + }); + }); + + it('removes any element from the DOM when a capability is enabled', async () => { + const fixture = TestBed.createComponent(CapabilityDisabledComponent); + + getCapabilityEnabled.mockReturnValue(false); + fixture.detectChanges(); + + expect(getCapabilityEnabled).toHaveBeenCalledWith('capability.a'); + await fixture.whenRenderingDone(); + await fixture.whenStable(); + expect(fixture.debugElement.query(By.css('p'))).toBeTruthy(); + + getCapabilityEnabled.mockReturnValue(true); + fixture.detectChanges(); + + expect(fixture.debugElement.query(By.css('p'))).toBeFalsy(); + }); + + @Component({ + selector: 'capability-disabled', + template: `

PDK!

`, + standalone: false + }) + class CapabilityDisabledComponent {} + }); +}); diff --git a/projects/core/src/capabilities/directives.ts b/projects/core/src/capabilities/directives.ts new file mode 100644 index 0000000..17d9c77 --- /dev/null +++ b/projects/core/src/capabilities/directives.ts @@ -0,0 +1,43 @@ +import { Component, Input } from '@angular/core'; +import { CapabilitiesService } from './service'; + +@Component({ + selector: '[capability-enabled]', + template: ` @if (isEnabled) { } `, + imports: [] +}) +export class CapabilityEnabledComponent { + _capabilityName!: string; + constructor(private capabilities: CapabilitiesService) {} + + get isEnabled(): boolean { + return this.capabilities.getCapabilityEnabled(this._capabilityName); + } + + @Input('capability-enabled') set capabilityName(name: string) { + this._capabilityName = name; + } +} + +@Component({ + selector: '[capability-disabled]', + template: ` @if (isDisabled) { } `, + imports: [] +}) +export class CapabilityDisabledComponent { + _capabilityName!: string; + + constructor(private capabilities: CapabilitiesService) {} + get isDisabled(): boolean { + return !this.capabilities.getCapabilityEnabled(this._capabilityName); + } + + @Input('capability-disabled') set capabilityName(name: string) { + this._capabilityName = name; + } +} + +export const CppCapabilityComponents = [ + CapabilityDisabledComponent, + CapabilityEnabledComponent +] as const; diff --git a/projects/core/src/capabilities/guards.ts b/projects/core/src/capabilities/guards.ts new file mode 100644 index 0000000..5457d77 --- /dev/null +++ b/projects/core/src/capabilities/guards.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot } from '@angular/router'; +import { Observable, of, throwError } from 'rxjs'; +import { CapabilitiesService } from './service'; + +@Injectable() +export class CapabilityRestrictedGuard { + constructor(private capabilities: CapabilitiesService) {} + + canActivate({ data }: ActivatedRouteSnapshot): Observable { + if (data.requireCapabilityEnabled) { + return of(this.capabilities.getCapabilityEnabled(data.requireCapabilityEnabled)); + } + if (data.requireCapabilityDisabled) { + return of(!this.capabilities.getCapabilityEnabled(data.requireCapabilityDisabled)); + } + return throwError(`No capability provided to capability-restricted route!`); + } +} diff --git a/projects/core/src/capabilities/providers.ts b/projects/core/src/capabilities/providers.ts new file mode 100644 index 0000000..ca423dd --- /dev/null +++ b/projects/core/src/capabilities/providers.ts @@ -0,0 +1,11 @@ +import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'; +import { CAPABILITIES_CONFIG, CapabilitiesConfig, CapabilitiesService } from './service'; +import { CapabilityRestrictedGuard } from './guards'; + +export const provideCppCapabilities = (config: CapabilitiesConfig): EnvironmentProviders => { + return makeEnvironmentProviders([ + { provide: CAPABILITIES_CONFIG, useValue: config }, + CapabilityRestrictedGuard, + CapabilitiesService + ]); +}; diff --git a/projects/core/src/capabilities/service.ts b/projects/core/src/capabilities/service.ts new file mode 100644 index 0000000..33a007d --- /dev/null +++ b/projects/core/src/capabilities/service.ts @@ -0,0 +1,81 @@ +import { Inject, Injectable, InjectionToken, Injector } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { combineLatest, Observable } from 'rxjs'; +import { map, tap } from 'rxjs/operators'; +import { CppHttpBackend } from '../http/http-backend'; + +export const CAPABILITIES_CONFIG = new InjectionToken('CAPABILITIES_CONFIG'); + +export interface CapabilitiesConfig { + manifestPath: string; +} + +export interface Capability { + name: string; + type: string; + description: string; +} + +export interface CapabilityStatus extends Capability { + enabled: boolean; +} + +@Injectable() +export class CapabilitiesService { + private capabilities: CapabilityStatus[] = []; + + constructor( + @Inject(CAPABILITIES_CONFIG) private config: CapabilitiesConfig, + private httpClient: HttpClient, + private injector: Injector + ) {} + + loadCapabilites(): Observable { + // fetch the manifest file - this is the capability specification + // belonging to an application, and its path is configurable + const fetchManifest$ = this.httpClient + .get<{ capabilities: Capability[] }>(this.config.manifestPath) + .pipe(map((data) => data.capabilities)); + + // fetch the capability statuses from the server, to determine whether + // a capability defined in the manifest is enabled or disabled + const fetchStatuses$ = this.injector + .get(CppHttpBackend) + .get<{ capabilities: CapabilityStatus[] }>( + `/authorisation-service-server/rest/capabilities?type=ui`, + 'application/vnd.authorisation.capabilities+json' + ) + .pipe(map((data) => data.capabilities)); + + // Return an intersection of capabilities defined in the manifest and + // those whose `enabled` statuses are defined remotely. This will, + // therefore, deliberately disregard any capabilities who exist in one place + // only, as their intended behaviour cannot be determined + return combineLatest([fetchManifest$, fetchStatuses$]).pipe( + map(([manifest, statuses]) => + statuses.reduce((capabilities, sc) => { + const mc = manifest.find((item) => sc.name === item.name); + if (mc) { + return [...capabilities, { ...sc, ...mc }]; + } + return capabilities; + }, [] as CapabilityStatus[]) + ), + tap((capabilities) => { + this.capabilities = capabilities; + }) + ); + } + + getCapabilityEnabled(name: string): boolean { + const capability = this.capabilities.find((c) => c.name === name); + + if (!capability) { + throw new Error(` + The capability '${name}' was not recognised. Please ensure that the capability exists + in the capabilities manifest, and that it has been attributed an \`enabled\` status. + `); + } + return capability.enabled; + } +} diff --git a/projects/core/src/cookies/__tests__/__snapshots__/cookies.spec.ts.snap b/projects/core/src/cookies/__tests__/__snapshots__/cookies.spec.ts.snap new file mode 100644 index 0000000..596bd3e --- /dev/null +++ b/projects/core/src/cookies/__tests__/__snapshots__/cookies.spec.ts.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CookiesModule CookiesService should set all cookie preferences 1`] = ` +{ + "realUserMonitoring": true, +} +`; + +exports[`CookiesModule CookiesService when no preferences have previously been set should get the default cookies preferences 1`] = ` +{ + "realUserMonitoring": false, +} +`; diff --git a/projects/core/src/cookies/__tests__/cookies.spec.ts b/projects/core/src/cookies/__tests__/cookies.spec.ts new file mode 100644 index 0000000..3da807d --- /dev/null +++ b/projects/core/src/cookies/__tests__/cookies.spec.ts @@ -0,0 +1,125 @@ +import { TestBed } from '@angular/core/testing'; +import { CookiesPreferences } from '../cookies.service'; +import { provideCppCookieServices } from '../providers'; +import { CookiesService, COOKIES_PREFERENCES_KEY } from '../cookies.service'; +import { DynatraceService } from '../dynatrace/dynatrace.service'; + +describe('CookiesModule', () => { + let cookiesService: CookiesService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideCppCookieServices()] + }); + + cookiesService = TestBed.inject(CookiesService); + }); + + const installCookiePreferences = (preferences: CookiesPreferences) => { + localStorage.setItem(COOKIES_PREFERENCES_KEY, JSON.stringify(preferences)); + }; + + describe('CookiesService', () => { + describe('when no preferences have previously been set', () => { + it('should recognise that cookie preferences have not been persisted', () => { + const hasExistingPreferences = cookiesService.getCookiePreferencesExist(); + + expect(hasExistingPreferences).toEqual(false); + }); + + it('should get the default cookies preferences', () => { + const preferences = cookiesService.getAllCookiePreferences(); + expect(preferences).toMatchSnapshot(); + }); + }); + + describe('when cookie preferences have previously been set', () => { + beforeEach(() => { + installCookiePreferences({ realUserMonitoring: true }); + }); + + it('should recognise that cookie preferences have been persisted', () => { + const hasExistingPreferences = cookiesService.getCookiePreferencesExist(); + + expect(hasExistingPreferences).toEqual(true); + }); + + it('should get a single cookie preference', () => { + const preference = cookiesService.getCookiePreference('realUserMonitoring'); + + expect(preference).toEqual(true); + }); + + it('should get all the persisted cookie preferences', () => { + const preferences = cookiesService.getAllCookiePreferences(); + + expect(preferences).toEqual({ + realUserMonitoring: true + }); + }); + + it('should set all cookies disabled', () => { + cookiesService.setAllCookiesDisabled(); + + const preferences = JSON.parse(localStorage.getItem(COOKIES_PREFERENCES_KEY) || ''); + + expect(preferences).toEqual({ + realUserMonitoring: false + }); + }); + + it('should reset the cookie preferences', () => { + cookiesService.resetCookiePreferences(); + + expect(localStorage.getItem(COOKIES_PREFERENCES_KEY)).toBeFalsy(); + }); + }); + + it('should set all cookies enabled', () => { + cookiesService.setAllCookiesEnabled(); + + const preferences = JSON.parse(localStorage.getItem(COOKIES_PREFERENCES_KEY) || ''); + + expect(preferences).toEqual({ + realUserMonitoring: true + }); + }); + + it('should set a single cookie preference', () => { + cookiesService.setCookiePreference('realUserMonitoring', true); + + const { realUserMonitoring } = JSON.parse( + localStorage.getItem(COOKIES_PREFERENCES_KEY) || '' + ); + + expect(realUserMonitoring).toEqual(true); + }); + + it('should set all cookie preferences', () => { + cookiesService.setAllCookiePreferences({ realUserMonitoring: true }); + + const preferences = JSON.parse(localStorage.getItem(COOKIES_PREFERENCES_KEY) || ''); + + expect(preferences).toMatchSnapshot(); + }); + + it('should manage the real user monitoring', () => { + const dtrum: DynatraceService = TestBed.inject(DynatraceService); + dtrum.start = jest.fn(); + dtrum.stop = jest.fn(); + + installCookiePreferences({ realUserMonitoring: true }); + cookiesService.start(); + expect(dtrum.start).toHaveBeenCalled(); + expect(dtrum.stop).not.toHaveBeenCalled(); + + dtrum.start = jest.fn(); + dtrum.stop = jest.fn(); + + installCookiePreferences({ realUserMonitoring: false }); + cookiesService.restart(); + expect(dtrum.start).not.toHaveBeenCalled(); + expect(dtrum.stop).toHaveBeenCalled(); + }); + }); +}); diff --git a/projects/core/src/cookies/cookies.service.ts b/projects/core/src/cookies/cookies.service.ts new file mode 100644 index 0000000..41d94d6 --- /dev/null +++ b/projects/core/src/cookies/cookies.service.ts @@ -0,0 +1,117 @@ +import { Injectable } from '@angular/core'; +import { DynatraceService } from './dynatrace/dynatrace.service'; + +export const COOKIES_PREFERENCES_KEY = 'cookie-preferences'; + +export interface CookiesPreferences { + realUserMonitoring: boolean; +} + +const defaultCookiePreferences: CookiesPreferences = { + realUserMonitoring: false +}; + +@Injectable({ providedIn: 'root' }) +export class CookiesService { + constructor(private dynatraceService: DynatraceService) {} + + getCookiePreferencesExist(): boolean { + return Boolean(this.getPersistedCookiePreferences()); + } + + getCookiePreference(cookieName: keyof CookiesPreferences): boolean { + return this.getAllCookiePreferences()[cookieName]; + } + + getAllCookiePreferences(): CookiesPreferences { + return this.getPersistedCookiePreferences() || defaultCookiePreferences; + } + + resetCookiePreferences(): void { + localStorage.removeItem(COOKIES_PREFERENCES_KEY); + } + + setAllCookiesDisabled(): void { + this.setAllCookiePreferences( + Object.keys(defaultCookiePreferences).reduce( + (cookiePreferences, cookieName) => ({ + ...cookiePreferences, + [cookieName]: false + }), + {} as CookiesPreferences + ) + ); + } + + setAllCookiesEnabled(): void { + this.setAllCookiePreferences( + Object.keys(defaultCookiePreferences).reduce( + (cookiePreferences, cookieName) => ({ + ...cookiePreferences, + [cookieName]: true + }), + {} as CookiesPreferences + ) + ); + } + + setAllCookiePreferences(preferences: CookiesPreferences): void { + localStorage.setItem(COOKIES_PREFERENCES_KEY, JSON.stringify(preferences)); + } + + setCookiePreference(cookieName: keyof CookiesPreferences, enabled: boolean): void { + const existingCookiePreferences = this.getAllCookiePreferences(); + + this.setAllCookiePreferences({ + ...existingCookiePreferences, + [cookieName]: enabled + }); + } + + start() { + // run any cookie-driven processes here, driven by current preferences + if (this.getCookiePreference('realUserMonitoring')) { + this.dynatraceService.start(); + } + } + + stop() { + this.dynatraceService.stop(); + } + + restart() { + this.stop(); + this.start(); + } + + enterAction( + actionName: string, + actionType?: string, + startTime?: number, + sourceUrl?: string + ): number | null { + return this.dynatraceService.enterAction(actionName, actionType, startTime, sourceUrl); + } + + leaveAction(actionId: number, stopTime?: number, startTime?: number): void { + this.dynatraceService.leaveAction(actionId, stopTime, startTime); + } + private getPersistedCookiePreferences(): CookiesPreferences | null { + const serializedPreferences = localStorage.getItem(COOKIES_PREFERENCES_KEY); + + if (serializedPreferences) { + try { + return { + // spread default preferences prior to persisted preferences to ensure + // any newly added preferences are present + ...defaultCookiePreferences, + ...JSON.parse(serializedPreferences) + }; + } catch { + // if persisted cookie preferences cannot be parsed for some reason, + // treat them as not having been persisted + } + } + return null; + } +} diff --git a/projects/core/src/cookies/dynatrace/dtrum.mock.ts b/projects/core/src/cookies/dynatrace/dtrum.mock.ts new file mode 100644 index 0000000..8b4b7b2 --- /dev/null +++ b/projects/core/src/cookies/dynatrace/dtrum.mock.ts @@ -0,0 +1,18 @@ +import * as Dynatrace from './dynatrace.interfaces'; + +export class DynatraceRealUserMonitoringMock implements Dynatrace.RealUserMonitoring { + enable() { + /* eslint-disable no-console */ + console.info('DynatraceRealUserMonitoringMock#enable()'); + } + disable() { + /* eslint-disable no-console */ + console.info('DynatraceRealUserMonitoringMock#disable()'); + } + enableSessionReplay() {} + disableSessionReplay() {} + enterAction() { + return 0; + } + leaveAction() {} +} diff --git a/projects/core/src/cookies/dynatrace/dynatrace.interfaces.ts b/projects/core/src/cookies/dynatrace/dynatrace.interfaces.ts new file mode 100644 index 0000000..f2f5c23 --- /dev/null +++ b/projects/core/src/cookies/dynatrace/dynatrace.interfaces.ts @@ -0,0 +1,23 @@ +declare global { + interface Window { + dtrum?: RealUserMonitoring; + } +} + +export interface RealUserMonitoring { + defendantsAndOffencesCount?: string; + userGroups?: string[]; + userName?: string; + + enable(): void; + enableSessionReplay(): void; + disable(): void; + disableSessionReplay(): void; + enterAction( + actionName: string, + actionType?: string, + startTime?: number, + sourceUrl?: string + ): number; + leaveAction(actionId: number, stopTime?: number, startTime?: number): void; +} diff --git a/projects/core/src/cookies/dynatrace/dynatrace.service.ts b/projects/core/src/cookies/dynatrace/dynatrace.service.ts new file mode 100644 index 0000000..35973db --- /dev/null +++ b/projects/core/src/cookies/dynatrace/dynatrace.service.ts @@ -0,0 +1,75 @@ +import { Inject, Injectable, InjectionToken } from '@angular/core'; +import * as Dynatrace from './dynatrace.interfaces'; + +export const Dtrum = new InjectionToken('DynatraceRealUserMonitoring'); + +@Injectable({ providedIn: 'root' }) +export class DynatraceService { + private didStartSession = false; + private spinnerWheelActionId: number | undefined; + + constructor(@Inject(Dtrum) private dtrum: Dynatrace.RealUserMonitoring) {} + + start() { + if (!this.didStartSession) { + this.dtrum.enable(); + this.dtrum.enableSessionReplay(); + this.didStartSession = true; + } + } + + stop() { + if (this.didStartSession) { + this.dtrum.disable(); + this.dtrum.disableSessionReplay(); + this.didStartSession = false; + } + } + + restart() { + this.stop(); + this.start(); + } + + trackUserGroups(groupNames: string[]): void { + if (this.didStartSession && !!groupNames) { + this.dtrum.userGroups = groupNames; + } + } + + trackUserName(email: string): void { + if (this.didStartSession && !!email) { + this.dtrum.userName = email; + } + } + + trackCaagData(defendantsAndOffencesCount: string): void { + if (this.didStartSession && !!defendantsAndOffencesCount) { + this.dtrum.defendantsAndOffencesCount = defendantsAndOffencesCount; + } + } + + unTrackCaagData(): void { + if (this.didStartSession) { + delete this.dtrum.defendantsAndOffencesCount; + } + } + + enterAction( + actionName: string, + actionType?: string, + startTime?: number, + sourceUrl?: string + ): number | null { + if (this.didStartSession) { + return this.dtrum.enterAction(actionName, actionType, startTime, sourceUrl); + } + return null; + } + + leaveAction(actionId: number, stopTime?: number, startTime?: number): void { + if (this.didStartSession && !!actionId) { + this.dtrum.leaveAction(actionId, stopTime, startTime); + } + } +} diff --git a/projects/core/src/cookies/providers.ts b/projects/core/src/cookies/providers.ts new file mode 100644 index 0000000..5de4f42 --- /dev/null +++ b/projects/core/src/cookies/providers.ts @@ -0,0 +1,20 @@ +import { EnvironmentProviders, makeEnvironmentProviders, NgModule } from '@angular/core'; +import { DynatraceRealUserMonitoringMock } from './dynatrace/dtrum.mock'; +import { DynatraceService } from './dynatrace/dynatrace.service'; +import { CookiesService } from './cookies.service'; + +export function createDynatraceService() { + const dtrum = window.dtrum || new DynatraceRealUserMonitoringMock(); + + return new DynatraceService(dtrum); +} + +export const provideCppCookieServices = (): EnvironmentProviders => { + return makeEnvironmentProviders([ + CookiesService, + { + provide: DynatraceService, + useFactory: createDynatraceService + } + ]); +}; diff --git a/projects/core/src/fake-session/interceptor.ts b/projects/core/src/fake-session/interceptor.ts new file mode 100644 index 0000000..c78815a --- /dev/null +++ b/projects/core/src/fake-session/interceptor.ts @@ -0,0 +1,37 @@ +import { + HttpEvent, + HttpHandler, + HttpInterceptor, + HttpParams, + HttpRequest +} from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { FakeSessionService } from './service'; + +@Injectable() +export class SessionInterceptor implements HttpInterceptor { + constructor(private fakeSession: FakeSessionService) {} + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + if (request.url && this.isDevEnv(request.url)) { + const params = request.params || new HttpParams(); + const CJSCPPUID = this.fakeSession.getUserId() || ''; + const authenticatedRequest = request.clone({ + params: params.set('CJSCPPUID', CJSCPPUID), + setHeaders: { CJSCPPUID } + }); + return next.handle(authenticatedRequest); + } + + return next.handle(request); + } + + private isDevEnv(url: string): boolean { + return ( + url.toLowerCase().includes('devccm') || + url.toLowerCase().includes('steccm') || + url.toLowerCase().includes('localhost') + ); + } +} diff --git a/projects/core/src/fake-session/providers.ts b/projects/core/src/fake-session/providers.ts new file mode 100644 index 0000000..c734cbb --- /dev/null +++ b/projects/core/src/fake-session/providers.ts @@ -0,0 +1,46 @@ +import { HTTP_INTERCEPTORS } from '@angular/common/http'; +import { InjectionToken, EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'; +import { SessionInterceptor } from './interceptor'; +import { FakeSessionService, INITIAL_USER_ID } from './service'; + +export interface FakeSessionModuleOptions { + defaultUserId?: string; + queryParamInitializer?: boolean; +} + +export const FAKE_SESSION_OPTIONS = new InjectionToken( + 'FAKE_SESSION_OPTIONS' +); + +export function getInitialUserId(options: FakeSessionModuleOptions) { + const searchParams = new URLSearchParams(window.location.search); + return ( + (options.queryParamInitializer && searchParams.get('CJSCPPUID')) || + (options.defaultUserId as string) + ); +} + +export const provideCppFakeSession = ( + options: FakeSessionModuleOptions = { queryParamInitializer: true } +): EnvironmentProviders => { + return makeEnvironmentProviders([ + { + provide: FAKE_SESSION_OPTIONS, + useValue: options + }, + { + provide: INITIAL_USER_ID, + useFactory: getInitialUserId, + deps: [FAKE_SESSION_OPTIONS] + }, + { + provide: FakeSessionService, + useClass: FakeSessionService + }, + { + provide: HTTP_INTERCEPTORS, + useClass: SessionInterceptor, + multi: true + } + ]); +}; diff --git a/projects/core/src/fake-session/service.ts b/projects/core/src/fake-session/service.ts new file mode 100644 index 0000000..87d511b --- /dev/null +++ b/projects/core/src/fake-session/service.ts @@ -0,0 +1,44 @@ +import { Inject, Injectable, InjectionToken, Optional } from '@angular/core'; + +export const INITIAL_USER_ID = new InjectionToken('INITIAL_USER_ID'); + +type UserIdCallbackFn = (userId: string | null) => void; + +@Injectable() +export class FakeSessionService { + listeners: [string, UserIdCallbackFn][] = []; + constructor(@Optional() @Inject(INITIAL_USER_ID) userId: string) { + if (userId) { + this.setUserId(userId); + } + } + + clear() { + this.setUserId(null); + } + + getUserId() { + return window.localStorage.getItem('CJSCPPUID'); + } + + setUserId(cjscppuid: string | null) { + if (cjscppuid) { + window.localStorage.setItem('CJSCPPUID', cjscppuid); + } else { + window.localStorage.removeItem('CJSCPPUID'); + } + this.listeners.forEach(([eventName, callback]) => { + if (eventName === 'CJSCPPUID') { + callback(cjscppuid); + } + }); + } + + addListener(eventName: string, fn: UserIdCallbackFn) { + this.listeners = [...this.listeners, [eventName, fn]]; + } + + removeListener(eventName: string, fn: UserIdCallbackFn) { + this.listeners = this.listeners.filter((item) => item[0] !== eventName && item[1] !== fn); + } +} diff --git a/projects/core/src/http/__tests__/http.spec.ts b/projects/core/src/http/__tests__/http.spec.ts new file mode 100644 index 0000000..348f5bf --- /dev/null +++ b/projects/core/src/http/__tests__/http.spec.ts @@ -0,0 +1,535 @@ +import { HttpClient, HttpHeaders, HttpParams, provideHttpClient } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { concat, merge, Observable } from 'rxjs'; +import { marbles } from 'rxjs-marbles/jest'; +import { finalize, take, takeUntil } from 'rxjs/operators'; +import { NotificationDispatcher, NotificationEvent } from '../dispatcher'; +import { CppHttpBackend, HTTP_CONFIG } from '../http-backend'; +import { CppHttp } from '../http-service'; +import { GENERATE_UNIQUE_KEY } from '../util'; + +describe('HttpModule', () => { + const createEvent = >( + name: string, + payload?: T, + id?: string + ): NotificationEvent => + ({ + ...(payload || {}), + _metadata: { + id: id || '*', + name + } + } as NotificationEvent); + + describe('CppHttpBackend', () => { + let httpBackend: CppHttpBackend; + let get: jest.Mock; + let post: jest.Mock; + + beforeEach(() => { + get = jest.fn(); + post = jest.fn(); + + TestBed.configureTestingModule({ + providers: [ + provideHttpClient(), + CppHttpBackend, + { + provide: HTTP_CONFIG, + useValue: { + baseUrl: 'http://test.url' + } + }, + { + provide: GENERATE_UNIQUE_KEY, + useValue: () => 'unique!' + }, + { + provide: HttpClient, + useValue: { get, post } + } + ] + }); + httpBackend = TestBed.inject(CppHttpBackend); + }); + + describe('#post', () => { + it( + 'correctly performs a post request', + marbles((m) => { + expect.assertions(6); + + const response$ = m.cold('-(a|)'); + + post.mockReturnValue(response$); + + m.expect( + httpBackend.post('/command', 'command.json', { prop: '*' }).pipe( + finalize(() => { + const [url, body, options] = post.mock.calls[0]; + + expect(url).toEqual('http://test.url/command'); + expect(body).toEqual({ prop: '*' }); + expect(options.headers.get('Content-Type')).toEqual('command.json'); + expect(options.headers.get('Accept')).toEqual('*/*'); + expect(options.responseType).toEqual('text'); + }) + ) + ).toBeObservable(response$); + }) + ); + + it('provides an empty body where none is specified', () => { + post.mockReturnValue(new Observable()); + httpBackend.post('/command', 'command.json').subscribe(); + + expect(post.mock.calls[0][1]).toEqual({}); + }); + }); + + describe('#get', () => { + it( + 'correctly performs a get request', + marbles((m) => { + expect.assertions(3); + + const response$ = m.cold('-(a|)'); + + get.mockReturnValue(response$); + + m.expect( + httpBackend.get('/query', 'query.json').pipe( + finalize(() => { + const [url, options] = get.mock.calls[0]; + + expect(url).toEqual('http://test.url/query'); + expect(options.headers.get('Accept')).toEqual('query.json'); + }) + ) + ).toBeObservable(response$); + }) + ); + + it('correctly merges any existing headers', () => { + get.mockReturnValue(new Observable()); + + httpBackend + .get('/query', 'query.json', { headers: new HttpHeaders({ name: '*' }) }) + .subscribe(); + + const options = get.mock.calls[0][1]; + + expect(options.headers.get('name')).toEqual('*'); + }); + + it('attaches a cache-busting query string parameter where `cache` is not truthy', () => { + get.mockReturnValue(new Observable()); + + httpBackend.get('/query', 'query.json', { cache: true }).subscribe(); + expect(get.mock.calls[0][1].params.get('_')).toBeFalsy(); + + httpBackend.get('/query', 'query.json').subscribe(); + expect(get.mock.calls[1][1].params.get('_')).toEqual('unique!'); + }); + }); + }); + + describe('CppHttp', () => { + let http: CppHttp; + let get: jest.Mock; + let getEvents: jest.Mock; + let post: jest.Mock; + + beforeEach(() => { + get = jest.fn(); + post = jest.fn(); + getEvents = jest.fn(); + + TestBed.configureTestingModule({ + providers: [ + { provide: CppHttpBackend, useValue: { get, post } }, + { provide: NotificationDispatcher, useValue: { getEvents } }, + { provide: GENERATE_UNIQUE_KEY, useValue: () => 'CORRELATION_ID' }, + CppHttp + ] + }); + http = TestBed.inject(CppHttp); + }); + + describe('#command', () => { + it( + 'performs a post request using the provided options', + marbles((m) => { + expect.assertions(5); + + const response$ = m.cold('-(a|)'); + const headers = new HttpHeaders({ name: '*' }); + + post.mockReturnValue(response$); + + const command$ = http + .command({ + body: '*', + headers, + requestType: 'command.json', + url: '/command' + }) + .pipe( + finalize(() => { + const [url, requestType, body, options] = post.mock.calls[0]; + + expect(url).toEqual('/command'); + expect(requestType).toEqual('command.json'); + expect(body).toEqual('*'); + expect(options.headers).toEqual(headers); + }) + ); + + m.expect(command$).toBeObservable(response$); + }) + ); + }); + + describe('#commandSync', () => { + let command: jest.Mock; + + beforeEach(() => { + command = jest.fn(); + http.command = command; + }); + + it( + 'completes with a new payload when a success event is received', + marbles((m) => { + const values = { + x: createEvent('success.a'), + y: createEvent('success.b', { _: '*' }), + z: { _: '*' } + }; + const response$ = m.cold('-(a|) ', values); + const incoming$ = m.cold(' ---x-y---', values); + const expected$ = m.cold('------(z|)', values); + + command.mockReturnValueOnce(response$); + getEvents.mockReturnValueOnce(incoming$); + + const config = { + url: '/command', + body: 'BODY', + requestType: 'command.json', + successEvent: 'success.b' + }; + const commandSync$ = http.commandSync(config); + + m.expect(commandSync$).toBeObservable(expected$); + m.flush(); + + const { url, requestType, body, headers } = command.mock.calls[0][0]; + + expect(url).toEqual('/command'); + expect(requestType).toEqual('command.json'); + expect(body).toEqual('BODY'); + expect(headers.get('CPPCLIENTCORRELATIONID')).toEqual('CORRELATION_ID'); + }) + ); + + it( + 'errors the subscription after a failure on the command', + marbles((m) => { + const error = 'Something went wrong!'; + const response$ = m.cold('-#', {}, { error }); + const expected$ = m.cold('-#', {}, { error }); + + command.mockReturnValue(response$); + + const commandSync$ = http.commandSync({ + url: '/command', + requestType: 'command.json', + successEvent: 'event.b' + }); + + m.expect(commandSync$).toBeObservable(expected$); + }) + ); + + it( + 'errors the subscription upon an error notification', + marbles((m) => { + const errorEvent = createEvent('error.a', { message: '*' }); + const values = { + x: createEvent('error.b'), + y: errorEvent + }; + const error = { + status: -1, + originalEvent: errorEvent, + data: { message: '*' } + }; + const response$ = m.cold('-(a|) ', values); + const incoming$ = m.cold(' ----x-y|', values); + const expected$ = m.cold('-------# ', values, error); + + command.mockReturnValueOnce(response$); + getEvents.mockReturnValueOnce(incoming$); + + const commandSync$ = http.commandSync({ + url: '/command', + requestType: 'command.json', + successEvent: 'success.a', + errorEvent: 'error.a' + }); + + m.expect(commandSync$).toBeObservable(expected$); + }) + ); + + it( + 'errors the subscription upon any response error when multiple are specified', + marbles((m) => { + const errorEvent = createEvent('error.b', { message: '*' }); + const values = { + a: undefined, + x: errorEvent + }; + const error = { + status: -1, + originalEvent: errorEvent, + data: { message: '*' } + }; + const response$ = m.cold('-a| ', values); + const incoming$ = m.cold(' ----x|', values); + const expected$ = m.cold('-----# ', undefined, error); + + command.mockReturnValue(response$); + getEvents.mockReturnValueOnce(incoming$); + + const commandSync$ = http.commandSync({ + url: '/command', + requestType: 'command.json', + successEvent: 'success.a', + errorEvent: ['error.a', 'error.b'] + }); + + m.expect(commandSync$).toBeObservable(expected$); + }) + ); + + it( + 'accepts a timeout that spans the initial request and the response event', + marbles((m) => { + const response$ = m.cold('-a| '); + const incoming$ = m.cold(' ----'); + const expected$ = m.cold('10s #', undefined, { status: 0 }); + + command.mockReturnValue(response$); + getEvents.mockReturnValueOnce(incoming$); + + const commandSync$ = http.commandSync({ + url: '/command', + body: '*', + requestType: 'command.json', + successEvent: 'success.a', + timeout: 10000 + }); + + m.expect(commandSync$).toBeObservable(expected$); + }) + ); + }); + + describe('#query', () => { + it( + 'performs a get request using the provided options', + marbles((m) => { + expect.assertions(4); + + const response$ = m.cold('-(a|)'); + const headers = new HttpHeaders({ name: '*' }); + + get.mockReturnValue(response$); + + const query = http + .query({ + url: '/query', + requestType: 'query.json', + headers + }) + .pipe( + finalize(() => { + const [url, requestType, options] = get.mock.calls[0]; + + expect(url).toEqual('/query'); + expect(requestType).toEqual('query.json'); + expect(options.headers).toEqual(headers); + }) + ); + + m.expect(query).toBeObservable(response$); + }) + ); + }); + }); + + describe('NotificationsDispatcher', () => { + let get: jest.Mock; + let post: jest.Mock; + let notificationsDispatcher: NotificationDispatcher; + + beforeEach(() => { + get = jest.fn(); + post = jest.fn(); + + TestBed.configureTestingModule({ + providers: [ + { provide: CppHttpBackend, useValue: { get, post } }, + { + provide: GENERATE_UNIQUE_KEY, + useValue: (() => { + let i = 0; + return () => `SUBSCRIPTION_ID_${i++}`; + })() + }, + NotificationDispatcher + ] + }); + notificationsDispatcher = TestBed.inject(NotificationDispatcher); + }); + + describe('#getEvents', () => { + it( + 'creates a subscription when the first subscription is added', + marbles((m) => { + const subscribed$ = m.cold('-(a|) '); + const poll$ = m.cold(' ------'); + const done$ = m.cold(' ---(x|)'); + const expected$ = m.cold(' ---| '); + + post.mockReturnValue(subscribed$); + get.mockReturnValue(poll$); + + const events$ = notificationsDispatcher.getEvents().pipe(takeUntil(done$)); + + m.expect(events$).toBeObservable(expected$); + m.flush(); + + expect(post).toHaveBeenCalledWith( + `/notification-command-api/command/api/rest/notification/subscriptions/SUBSCRIPTION_ID_0`, + 'application/vnd.notification.subscribe-by-user-id+json' + ); + expect(post).toHaveBeenCalledTimes(1); + }) + ); + + it( + 'should share a subscription during concurrent polling', + marbles((m) => { + const subscribed$ = m.cold('---(a|)'); + const subscribeSub = ' ^--! '; + const poll$ = m.cold(' ------'); + const done$ = m.cold(' ---(x|)'); + const expected$ = m.cold(' ---| '); + + post.mockReturnValueOnce(subscribed$); + get.mockReturnValueOnce(poll$); + + const events$ = notificationsDispatcher.getEvents().pipe(takeUntil(done$)); + + m.expect(merge(events$, events$)).toBeObservable(expected$); + m.expect(subscribed$).toHaveSubscriptions(subscribeSub); + }) + ); + + it( + 'should reuse a subscription id for future subscriptions', + marbles((m) => { + const subscribed$ = m.cold('-(a|) '); + const poll$ = m.cold(' ------'); + const done$ = m.cold(' ---(x|)'); + const expected$ = m.cold(' ------|'); + + post.mockReturnValue(subscribed$); + get.mockReturnValue(poll$); + + const events$ = notificationsDispatcher.getEvents().pipe(takeUntil(done$)); + + m.expect(concat(events$, events$)).toBeObservable(expected$); + m.flush(); + + expect(post).toHaveBeenCalledTimes(1); + expect(get.mock.calls[0][0]).toContain('SUBSCRIPTION_ID_0'); + expect(get.mock.calls[1][0]).toContain('SUBSCRIPTION_ID_0'); + }) + ); + + it( + 'should retry fetching events when a 403 error is encountered', + marbles((m) => { + const subscribe$ = m.cold('-(r|) '); + const poll1$ = m.cold(' --# ', undefined, { status: 403 }); + const poll2$ = m.cold(' ---- '); + const poll2Sub = ' --- 1.5s ^--! '; + const done$ = m.cold(' ---- 1.5s --(x|)'); + const expected$ = m.cold(' ---- 1.5s --| '); + + post.mockReturnValueOnce(subscribe$); + get.mockReturnValueOnce(poll1$).mockReturnValueOnce(poll2$); + + const events$ = notificationsDispatcher.getEvents().pipe(takeUntil(done$)); + + m.expect(events$).toBeObservable(expected$); + m.expect(poll2$).toHaveSubscriptions(poll2Sub); + }) + ); + + it( + 'polls immediately and then every 1.5 seconds', + marbles((m) => { + const a = createEvent('event.a', { _: 'A' }, '1'); + const b = createEvent('event.b', { _: 'B' }, '2'); + const c = createEvent('event.c', { _: 'C' }, '3'); + + const subscribed$ = m.cold('-(s|) '); + const first$ = m.cold(' -(a|) ', { a: { events: [a] } }); + const second$ = m.cold(' --(b|) ', { b: { events: [b, c] } }); + const done$ = m.cold(' --- 1.5s ----x|'); + const expected$ = m.cold(' --x 1.5s (yz)|', { x: a, y: b, z: c }); + + post.mockReturnValue(subscribed$); + get.mockReturnValueOnce(first$).mockReturnValueOnce(second$); + + const params = { clientCorrelationId: 'CORRELATION_ID' }; + const events$ = notificationsDispatcher.getEvents(params).pipe(takeUntil(done$)); + + m.expect(events$).toBeObservable(expected$); + m.flush(); + + expect(get).toHaveBeenCalledWith( + `/notification-query-api/query/api/rest/notifications/subscriptions/SUBSCRIPTION_ID_0/events`, + 'application/vnd.notification.events+json', + { params: new HttpParams({ fromObject: params }) } + ); + }) + ); + + it( + 'does not emit an event for an event id previously received', + marbles((m) => { + const a = createEvent('event.a', { _: 'A' }, '1'); + const b = createEvent('event.a', { _: 'B' }, '2'); + + const subscribed$ = m.cold('-(s|) '); + const poll$ = m.cold(' -(a|)', { a: { events: [a, a, b] } }); + const expected$ = m.cold(' --(xy|)', { x: a, y: b }); + + post.mockReturnValue(subscribed$); + get.mockReturnValue(poll$); + + const events$ = notificationsDispatcher.getEvents().pipe(take(2)); + + m.expect(events$).toBeObservable(expected$); + }) + ); + }); + }); +}); diff --git a/projects/core/src/http/dispatcher.ts b/projects/core/src/http/dispatcher.ts new file mode 100644 index 0000000..a866cad --- /dev/null +++ b/projects/core/src/http/dispatcher.ts @@ -0,0 +1,90 @@ +import { HttpErrorResponse, HttpParams } from '@angular/common/http'; +import { Inject, Injectable } from '@angular/core'; +import { Observable, of, throwError, timer } from 'rxjs'; +import { + exhaustMap, + filter, + map, + mapTo, + mergeMap, + publishReplay, + refCount, + retryWhen, + switchMap, + tap +} from 'rxjs/operators'; +import { CppHttpBackend } from './http-backend'; +import { GENERATE_UNIQUE_KEY } from './util'; + +export type NotificationEvent> = { + _metadata: { + id: string; + name: string; + correlation?: { + client: string; + }; + }; +} & T; + +@Injectable() +export class NotificationDispatcher { + // Create a subscription to the notifications server the very first time that + // the poller connects. This subscription id remains valid for the lifecycle of + // the application, and can be reused even after refCount has dropped to 0 + subscription$ = of(this.generateUniqueKey()).pipe( + switchMap((subscriptionId) => + this.backend + .post( + `/notification-command-api/command/api/rest/notification/subscriptions/${subscriptionId}`, + 'application/vnd.notification.subscribe-by-user-id+json' + ) + .pipe(mapTo(subscriptionId)) + ), + publishReplay(1), + refCount() + ); + + constructor( + @Inject(GENERATE_UNIQUE_KEY) private generateUniqueKey: any, + private readonly backend: CppHttpBackend + ) {} + + getEvents>(params?: { + clientCorrelationId: string; + }): Observable> { + const history = [] as string[]; + + return this.subscription$.pipe( + switchMap((subscriptionId) => + timer(0, 1500).pipe( + exhaustMap(() => + this.backend.get<{ events: NotificationEvent[] }>( + `/notification-query-api/query/api/rest/notifications/subscriptions/${subscriptionId}/events`, + 'application/vnd.notification.events+json', + { params: new HttpParams({ fromObject: params }) } + ) + ), + map((data) => data.events), + mergeMap((events) => events), + // Filter any events that have been seen before so that they're not re-emitted + // to any subscribers. + filter((event) => history.indexOf(event._metadata.id) === -1), + tap((event) => { + history.push(event._metadata.id); + }), + retryWhen((errors) => + errors.pipe( + switchMap((error: HttpErrorResponse) => { + // events will sometimes return 403 for reasons unknown + if (error.status === 403) { + return timer(1500); + } + return throwError(error); + }) + ) + ) + ) + ) + ); + } +} diff --git a/projects/core/src/http/http-backend.ts b/projects/core/src/http/http-backend.ts new file mode 100644 index 0000000..eaa049a --- /dev/null +++ b/projects/core/src/http/http-backend.ts @@ -0,0 +1,76 @@ +import { Inject, Injectable, InjectionToken } from '@angular/core'; +import { HttpClient, HttpEvent, HttpHeaders, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { GENERATE_UNIQUE_KEY, GenerateUniqueKeyFn } from './util'; + +export const HTTP_CONFIG = new InjectionToken('CppHttpConfig'); + +export interface CppHttpConfig { + baseUrl: string; +} + +export interface GetRequestOptions { + cache?: boolean; + headers?: HttpHeaders; + observe?: 'body'; + params?: HttpParams; + responseType?: any; + reportProgress?: boolean; + withCredentials?: boolean; +} + +export interface PostRequestOptions { + headers?: HttpHeaders; + observe?: 'body'; + params?: HttpParams; + responseType?: 'events'; + reportProgress?: boolean; + withCredentials?: boolean; +} + +@Injectable() +export class CppHttpBackend { + constructor( + @Inject(HTTP_CONFIG) private config: CppHttpConfig, + @Inject(GENERATE_UNIQUE_KEY) private generateUniqueKey: GenerateUniqueKeyFn, + private http: HttpClient + ) {} + + get( + url: string, + requestType: string, + { cache, ...options }: GetRequestOptions = {} + ): Observable { + const params = options.params || new HttpParams(); + const headers = options.headers || new HttpHeaders(); + + return this.http.get(`${this.config.baseUrl}${url}`, { + ...options, + headers: headers.set('Accept', requestType), + // where explicit caching is not required, attach a timestamp to to the query + // parameters to prevent aggressive caching by browsers (e.g. IE11) + params: cache ? params : params.set('_', this.generateUniqueKey()) + }) as Observable; + } + + // note that an empty object as the body is required else the content-type will be stripped + post( + url: string, + requestType?: string, + body: FormData | any | null = {}, + options: PostRequestOptions = {} + ): Observable> { + let headers = options.headers || new HttpHeaders(); + headers = headers.set('Accept', '*/*'); + + if (requestType) { + headers = headers.set('Content-Type', requestType); + } + return this.http.post(`${this.config.baseUrl}${url}`, body, { + ...options, + headers, + observe: 'response', + responseType: 'text' + }); + } +} diff --git a/projects/core/src/http/http-service.ts b/projects/core/src/http/http-service.ts new file mode 100644 index 0000000..1d74411 --- /dev/null +++ b/projects/core/src/http/http-service.ts @@ -0,0 +1,116 @@ +import { HttpHeaders } from '@angular/common/http'; +import { Inject, Injectable } from '@angular/core'; +import { merge, Observable, race, throwError, timer } from 'rxjs'; +import { filter, map, share, switchMap, take } from 'rxjs/operators'; +import { NotificationDispatcher, NotificationEvent } from './dispatcher'; +import { CppHttpBackend, GetRequestOptions, PostRequestOptions } from './http-backend'; +import { GenerateUniqueKeyFn, GENERATE_UNIQUE_KEY } from './util'; + +const CORRELATION_KEY = 'CPPCLIENTCORRELATIONID'; +const empty = [] as string[]; + +export interface HttpQueryOptions extends GetRequestOptions { + url: string; + requestType: string; + background?: boolean; +} + +interface HttpCommandBaseOptions extends PostRequestOptions { + url: string; + body?: any; + requestType?: string; +} + +interface JsonCommandRequestOptions extends HttpCommandBaseOptions { + requestType: string; +} + +interface FormDataCommandOptions extends HttpCommandBaseOptions { + body: FormData; +} + +export type HttpComandOptions = JsonCommandRequestOptions | FormDataCommandOptions; + +interface HttpCommandSyncBaseOptions extends HttpCommandBaseOptions { + successEvent: string; + timeout?: number; + errorEvent?: string | string[]; +} + +interface JsonCommandSyncOptions extends HttpCommandSyncBaseOptions { + requestType: string; +} + +interface PostCommandSyncOptions extends HttpCommandSyncBaseOptions { + body: FormData; +} + +export type HttpCommandSyncOptions = JsonCommandSyncOptions | PostCommandSyncOptions; + +export interface CommandError = Record> { + status: -1; + originalEvent: NotificationEvent; + data: T; +} + +@Injectable() +export class CppHttp { + constructor( + @Inject(GENERATE_UNIQUE_KEY) private generateUniqueKey: GenerateUniqueKeyFn, + private http: CppHttpBackend, + private notificationDispatcher: NotificationDispatcher + ) {} + + query({ url, requestType, ...options }: HttpQueryOptions): Observable { + return this.http.get(url, requestType, options); + } + + command({ url, requestType, body, ...options }: HttpComandOptions): Observable { + return this.http.post(url, requestType, body, options); + } + + commandSync>({ + successEvent, + errorEvent, + timeout, + ...options + }: HttpCommandSyncOptions): Observable { + const clientCorrelationId = this.generateUniqueKey(); + const errorNames = empty.concat(errorEvent || []); + + options.headers = options.headers || new HttpHeaders(); + options.headers = options.headers.set(CORRELATION_KEY, clientCorrelationId); + + return merge( + timer(timeout || 30000).pipe(switchMap(() => throwError({ status: 0 }))), + this.command(options).pipe( + switchMap(() => { + const events$ = this.notificationDispatcher + .getEvents({ clientCorrelationId }) + .pipe(share()); + + const success$ = events$.pipe( + filter((event) => event._metadata.name === successEvent), + map(({ _metadata, ...data }) => data as unknown as R), + take(1) + ); + + const error$ = events$.pipe( + filter((event) => errorNames.indexOf(event._metadata.name) !== -1), + switchMap((event) => { + const { _metadata, ...data } = event; + + return throwError({ + data, + originalEvent: event, + status: -1 + }); + }) + ); + + return race(success$, error$); + }) + ) + ).pipe(take(1)); + } +} diff --git a/projects/core/src/http/providers.ts b/projects/core/src/http/providers.ts new file mode 100644 index 0000000..851a6c4 --- /dev/null +++ b/projects/core/src/http/providers.ts @@ -0,0 +1,83 @@ +import { + HttpInterceptorFn, + provideHttpClient, + withInterceptors, + withInterceptorsFromDi +} from '@angular/common/http'; +import { EnvironmentProviders, makeEnvironmentProviders, Provider } from '@angular/core'; +import { NotificationDispatcher } from './dispatcher'; +import { CppHttpBackend, CppHttpConfig, HTTP_CONFIG } from './http-backend'; +import { + detectNetwork, + DETECT_NETWORK, + generateUniqueKey, + GENERATE_UNIQUE_KEY, + DetectNetworkFn +} from './util'; +import { CppHttp } from './http-service'; + +export interface CppHttpConfigKind { + new (...args: any[]): CppHttpConfig; +} + +/** + * + * @param cppHttpConfig - The config class that implements the baseURl - Please Note: This must be an injectable class already provided + * @param cppHttp - The service to override the original cppHttp service + * @param networkDetector - a function that overrides the original detect network function + * @returns + */ +export function withCppHttpOverrides( + cppHttpConfig: CppHttpConfigKind, + cppHttp?: typeof CppHttp, + networkDetector?: DetectNetworkFn +): Provider[] { + const providers: Provider[] = [ + { + provide: HTTP_CONFIG, + useExisting: cppHttpConfig + } + ]; + + if (!!cppHttp) { + providers.push({ + provide: CppHttp, + useClass: cppHttp + }); + } + + if (!!networkDetector) { + providers.push({ + provide: DETECT_NETWORK, + useValue: networkDetector + }); + } + return providers; +} +/** + * When providing interceptors, ensure your interceptor functions are placed in the order you want them chained + */ +export const provideCppCoreHttpServices = ( + overrideProviders: Provider[] = [], + ...interceptorFns: HttpInterceptorFn[] +): EnvironmentProviders => { + return makeEnvironmentProviders([ + { + provide: DETECT_NETWORK, + useValue: detectNetwork + }, + { + provide: GENERATE_UNIQUE_KEY, + useValue: generateUniqueKey + }, + { + provide: HTTP_CONFIG, + useValue: { baseUrl: '/' } + }, + provideHttpClient(withInterceptorsFromDi(), withInterceptors(interceptorFns)), + CppHttpBackend, + NotificationDispatcher, + CppHttp, + ...overrideProviders + ]); +}; diff --git a/projects/core/src/http/util.ts b/projects/core/src/http/util.ts new file mode 100644 index 0000000..bef4af5 --- /dev/null +++ b/projects/core/src/http/util.ts @@ -0,0 +1,43 @@ +import { InjectionToken } from '@angular/core'; +import { distinctUntilChanged, fromEvent, map, merge, Observable, of, startWith } from 'rxjs'; +import uuid from 'uuid/v4'; +import { HttpParams } from '@angular/common/http'; + +export type GenerateUniqueKeyFn = () => string; +export type DetectNetworkFn = () => Observable; + +export const DETECT_NETWORK = new InjectionToken('DETECT_NETWORK'); +export const GENERATE_UNIQUE_KEY = new InjectionToken('GENERATE_UNIQUE_KEY'); + +export const detectNetwork: DetectNetworkFn = (): Observable => { + return merge( + fromEvent(window, 'online').pipe(map(() => true)), + fromEvent(window, 'offline').pipe(map(() => false)) + ).pipe(startWith(navigator.onLine), distinctUntilChanged()); +}; + +export const filterExists = (payload: T) => + Object.keys(payload) + .filter((key) => payload[key as keyof T] !== undefined) + .reduce( + (body, key) => ({ + ...body, + [key]: payload[key as keyof T] + }), + {} as T + ); + +export const generateUniqueKey: GenerateUniqueKeyFn = () => uuid(); + +export const mapObjectToHttpParams = (params: { [key: string]: any }) => + new HttpParams({ + fromObject: Object.keys(params) + .filter((key) => params[key] !== undefined) + .reduce( + (queryParams, key) => ({ + ...queryParams, + [key]: String(params[key]) + }), + {} as { [key: string]: string } + ) + }); diff --git a/projects/core/src/index.ts b/projects/core/src/index.ts new file mode 100644 index 0000000..4aaf8f9 --- /dev/null +++ b/projects/core/src/index.ts @@ -0,0 +1 @@ +export * from './public_api'; diff --git a/projects/core/src/public_api.ts b/projects/core/src/public_api.ts new file mode 100644 index 0000000..7c27402 --- /dev/null +++ b/projects/core/src/public_api.ts @@ -0,0 +1,19 @@ +/* + * Public API Surface of core + */ + +export * from './capabilities/providers'; +export * from './capabilities/service'; +export * from './capabilities/directives'; +export * from './cookies/providers'; +export * from './cookies/cookies.service'; +export * from './cookies/dynatrace/dynatrace.service'; +export * from './fake-session/providers'; +export * from './fake-session/service'; +export * from './http/dispatcher'; +export * from './http/http-backend'; +export * from './http/http-service'; +export * from './http/providers'; +export * from './http/util'; +export * from './rxjs/repeatUntil'; +export * from './utils'; diff --git a/projects/core/src/rxjs/__tests__/repeatUntil.spec.ts b/projects/core/src/rxjs/__tests__/repeatUntil.spec.ts new file mode 100644 index 0000000..c1f61ba --- /dev/null +++ b/projects/core/src/rxjs/__tests__/repeatUntil.spec.ts @@ -0,0 +1,81 @@ +import { Observable, of, TimeoutError } from 'rxjs'; +import { marbles } from 'rxjs-marbles/jest'; +import { switchMap } from 'rxjs/operators'; +import { repeatUntil } from '../repeatUntil'; + +describe('repeatUntil', () => { + it( + 'should repeat the source observable until the predicate can resolve the result', + marbles(m => { + const attempt1$ = m.cold('--(a|) ', { a: 0 }); + const attempt2$ = m.cold(' --(b|)', { b: 1 }); + const expected$ = m.cold('-- 1s --(b|)', { b: 1 }); + + const getValue: () => Observable = jest + .fn() + .mockReturnValueOnce(attempt1$) + .mockReturnValueOnce(attempt2$); + + const source$ = of(null).pipe( + switchMap(getValue), + repeatUntil(value => value > 0) + ); + m.expect(source$).toBeObservable(expected$); + }) + ); + + it( + 'should allow a regular error to pass through', + marbles(m => { + const error = new Error('*'); + const attempt$ = m.cold(' --#', undefined, error); + const expected$ = m.cold('--#', undefined, error); + + const getValue = () => attempt$; + + const source$ = of(null).pipe( + switchMap(getValue), + repeatUntil(value => value > 0) + ); + m.expect(source$).toBeObservable(expected$); + }) + ); + + it( + 'should time out after a default period', + marbles(m => { + const attempt$ = m.cold(' ----a', { a: 0 }); + const expected$ = m.cold('30s #', undefined, new TimeoutError()); + + const getValue = () => attempt$; + + const source$ = of(null).pipe( + switchMap(getValue), + repeatUntil(value => value > 0) + ); + m.expect(source$).toBeObservable(expected$); + }) + ); + + it( + 'should accept options to adapt the repeat and timeout periods', + marbles(m => { + const attempt1$ = m.cold('--(a|) ', { a: 0 }); + const attempt2$ = m.cold(' ---------'); + const attempt2Subs = '-- 750ms ^ 247ms !'; + const expected$ = m.cold('1s #', undefined, new TimeoutError()); + + const getValue: () => Observable = jest + .fn() + .mockReturnValueOnce(attempt1$) + .mockReturnValueOnce(attempt2$); + + const source$ = of(null).pipe( + switchMap(getValue), + repeatUntil(value => value > 0, { period: 750, due: 1000 }) + ); + m.expect(source$).toBeObservable(expected$); + m.expect(attempt2$).toHaveSubscriptions(attempt2Subs); + }) + ); +}); diff --git a/projects/core/src/rxjs/repeatUntil.ts b/projects/core/src/rxjs/repeatUntil.ts new file mode 100644 index 0000000..e4ab19a --- /dev/null +++ b/projects/core/src/rxjs/repeatUntil.ts @@ -0,0 +1,29 @@ +import { Observable, of, throwError, timer } from 'rxjs'; +import { retryWhen, switchMap, timeout } from 'rxjs/operators'; + +class RepeatUntilError extends Error { + constructor(public value: T) { + super('Result failed to resolve predicate.'); + this.name = 'RepeatUntilError'; + } +} + +export const repeatUntil = + (predicate: (value: T) => boolean, { period = 1000, due = 30000 } = {}) => + (source$: Observable) => + source$.pipe( + switchMap((result) => { + if (!predicate(result)) { + throw new RepeatUntilError(result); + } + return of(result); + }), + retryWhen((errors$) => + errors$.pipe( + switchMap((error: Error) => + error.name === 'RepeatUntilError' ? timer(period) : throwError(error) + ) + ) + ), + timeout(due) + ); diff --git a/projects/core/src/utils.ts b/projects/core/src/utils.ts new file mode 100644 index 0000000..61d73d9 --- /dev/null +++ b/projects/core/src/utils.ts @@ -0,0 +1,19 @@ +import { ProviderToken, inject } from '@angular/core'; +import { CanActivateFn } from '@angular/router'; + +/** + * A utility function to lazily convert class guards to functional guards. + * simply wrap guards in routing module with this function to cast as functional guards. + * Functional guards are preferred to Class Guards from NG 15 + * @param guards - an array of guards + * @returns @type CanActivateFn[] + */ +export function functionalGuardsFactory( + ...guards: ProviderToken<{ canActivate: CanActivateFn }>[] +): CanActivateFn[] { + return guards.map( + (guard) => + (...args: Parameters) => + inject(guard).canActivate(...args) + ); +} diff --git a/projects/core/tsconfig.lib.json b/projects/core/tsconfig.lib.json new file mode 100644 index 0000000..72f9139 --- /dev/null +++ b/projects/core/tsconfig.lib.json @@ -0,0 +1,27 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "declarationMap": true, + "module": "es2022", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "inlineSources": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "skipLibCheck": true, + "types": [], + "lib": ["dom", "es2018"] + }, + "angularCompilerOptions": { + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true, + "compilationMode": "partial" + }, + "exclude": ["**/*.spec.ts"] +} diff --git a/projects/core/tsconfig.lib.prod.json b/projects/core/tsconfig.lib.prod.json new file mode 100644 index 0000000..2a2faa8 --- /dev/null +++ b/projects/core/tsconfig.lib.prod.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/projects/core/tsconfig.spec.json b/projects/core/tsconfig.spec.json new file mode 100644 index 0000000..c677e6e --- /dev/null +++ b/projects/core/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "outDir": "../../out-tsc/spec", + "types": ["jest", "node"] + }, + "include": ["**/*.spec.ts", "**/*.d.ts"] +} diff --git a/projects/reference-data/.eslintrc.json b/projects/reference-data/.eslintrc.json new file mode 100644 index 0000000..032813b --- /dev/null +++ b/projects/reference-data/.eslintrc.json @@ -0,0 +1,37 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": [ + "projects/reference-data/tsconfig.lib.json", + "projects/reference-data/tsconfig.spec.json" + ], + "createDefaultProgram": true + }, + "extends": ["prettier"], + "rules": { + "@angular-eslint/component-class-suffix": "off", + "@typescript-eslint/consistent-type-definitions": "off", + "@typescript-eslint/dot-notation": "off", + "@typescript-eslint/explicit-member-accessibility": [ + "off", + { + "accessibility": "explicit" + } + ], + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/unified-signatures": "off", + "id-blacklist": "off", + "id-match": "off", + "no-underscore-dangle": "off" + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/projects/reference-data/ng-package.json b/projects/reference-data/ng-package.json new file mode 100644 index 0000000..62bce90 --- /dev/null +++ b/projects/reference-data/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/reference-data", + "lib": { + "entryFile": "src/index.ts" + } +} diff --git a/projects/reference-data/package.json b/projects/reference-data/package.json new file mode 100644 index 0000000..05062dc --- /dev/null +++ b/projects/reference-data/package.json @@ -0,0 +1,19 @@ +{ + "name": "@cpp/reference-data", + "version": "0.0.0-PLACEHOLDER", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": "^19.0.0", + "@angular/core": "^19.0.0", + "@angular/router": "^19.0.0", + "rxjs": "^7.0.0", + "uuid": "^3.3.2", + "@cpp/core": "^0.0.0-PLACEHOLDER", + "@cpp/users-groups": "^0.0.0-PLACEHOLDER", + "@cpp/pdk": "*", + "@ngrx/store": "^19.0.0" + }, + "peerDepenciesComment": "Do not modify placeholders in this file" +} diff --git a/projects/reference-data/src/actions/index.ts b/projects/reference-data/src/actions/index.ts new file mode 100644 index 0000000..35a2a74 --- /dev/null +++ b/projects/reference-data/src/actions/index.ts @@ -0,0 +1,3 @@ +import * as ReferenceDataActions from './reference-data.actions'; + +export { ReferenceDataActions }; diff --git a/projects/reference-data/src/actions/reference-data.actions.ts b/projects/reference-data/src/actions/reference-data.actions.ts new file mode 100644 index 0000000..0f87dff --- /dev/null +++ b/projects/reference-data/src/actions/reference-data.actions.ts @@ -0,0 +1,304 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { createAction, props } from '@ngrx/store'; +import { + PublicHoliday, + BookingType, + Cluster, + CourtApplicationType, + CPSArea, + CPSBusinessUnit, + CPSCaseStatus, + FixedList, + HearingPriority, + HearingType, + JudiciaryGroupType, + LocalJusticeArea, + OrganisationUnit, + PleaType, + PoliceForce, + PoliceRank, + Prosecutor, + ResultDefinition, + RotaBusinessType, + SpecialRequirement, + TrialType, + WitnessCareUnit, + OrganisationWithType, + OrganisationType +} from '../reference-data.interfaces'; + +export const loadApplicationTypes = createAction('LOAD_APPLICATION_TYPES'); + +export const loadApplicationTypesSuccess = createAction( + 'LOAD_APPLICATION_TYPES_SUCCESS', + props<{ applicationTypes: CourtApplicationType[] }>() +); + +export const loadApplicationTypesError = createAction( + 'LOAD_APPLICATION_TYPES_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadAssignPriorities = createAction('LOAD_ASSIGN_PRIORITIES'); + +export const loadAssignPrioritiesSuccess = createAction( + 'LOAD_ASSIGN_PRIORITIES_SUCCESS', + props<{ assignPriorities: HearingPriority[] }>() +); + +export const loadAssignPrioritiesError = createAction( + 'LOAD_ASSIGN_PRIORITIES_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadBookingTypes = createAction('LOAD_BOOKING_TYPES'); + +export const loadBookingTypesSuccess = createAction( + 'LOAD_BOOKING_TYPES_SUCCESS', + props<{ bookingTypes: BookingType[] }>() +); + +export const loadBookingTypesError = createAction( + 'LOAD_BOOKING_TYPES_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadClusters = createAction('LOAD_CLUSTERS'); + +export const loadClustersSuccess = createAction( + 'LOAD_CLUSTERS_SUCCESS', + props<{ clusters: Cluster[] }>() +); + +export const loadClustersError = createAction( + 'LOAD_CLUSTERS_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadCPSAreas = createAction('LOAD_CPS_AREAS'); + +export const loadCPSAreasSuccess = createAction( + 'LOAD_CPS_AREAS_SUCCESS', + props<{ cpsAreas: CPSArea[] }>() +); + +export const loadCPSAreasError = createAction( + 'LOAD_CPS_AREAS_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadCPSBusinessUnits = createAction('LOAD_CPS_BUSINESS_UNITS'); + +export const loadCPSBusinessUnitsSuccess = createAction( + 'LOAD_CPS_BUSINESS_UNITS_SUCCESS', + props<{ cpsBusinessUnits: CPSBusinessUnit[] }>() +); + +export const loadCPSBusinessUnitsError = createAction( + 'LOAD_CPS_BUSINESS_UNITS_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadCPSCaseStatuses = createAction('LOAD_CPS_CASE_STATUSES'); + +export const loadCPSCaseStatusesSuccess = createAction( + 'LOAD_CPS_CASE_STATUSES_SUCCESS', + props<{ cpsCaseStatuses: CPSCaseStatus[] }>() +); + +export const loadCPSCaseStatusesError = createAction( + 'LOAD_CPS_CASE_STATUSES_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadOrganisationUnits = createAction('LOAD_COURT_CENTRES'); + +export const loadOrganisationUnitsSuccess = createAction( + 'LOAD_COURT_CENTRES_SUCCESS', + props<{ organisationUnits: OrganisationUnit[] }>() +); + +export const loadOrganisationUnitsError = createAction( + 'LOAD_COURT_CENTRES_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadFixedLists = createAction('LOAD_FIXED_LISTS'); + +export const loadFixedListsSuccess = createAction( + 'LOAD_FIXED_LISTS_SUCCESS', + props<{ fixedLists: FixedList[] }>() +); + +export const loadFixedListsError = createAction( + 'LOAD_FIXED_LISTS_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadHearingTypes = createAction('LOAD_HEARING_TYPES'); + +export const loadHearingTypesSuccess = createAction( + 'LOAD_HEARING_TYPES_SUCCESS', + props<{ hearingTypes: HearingType[] }>() +); + +export const loadHearingTypesError = createAction( + 'LOAD_HEARING_TYPES_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadJudiciaryGroupTypes = createAction('LOAD_JUDICIARY_GROUP_TYPES'); + +export const loadJudiciaryGroupTypesSuccess = createAction( + 'LOAD_JUDICIARY_GROUP_TYPES_SUCCESS', + props<{ judiciaryGroupTypes: JudiciaryGroupType[] }>() +); + +export const loadJudiciaryGroupTypesError = createAction( + 'LOAD_JUDICIARY_GROUP_TYPES_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadLocalJusticeAreas = createAction('LOAD_LOCAL_JUSTICE_AREAS'); + +export const loadLocalJusticeAreasSuccess = createAction( + 'LOAD_LOCAL_JUSTICE_AREAS_SUCCESS', + props<{ localJusticeAreas: LocalJusticeArea[] }>() +); + +export const loadLocalJusticeAreasError = createAction( + 'LOAD_LOCAL_JUSTICE_AREAS_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadPleaTypes = createAction('LOAD_PLEA_TYPES'); + +export const loadPleaTypesSuccess = createAction( + 'LOAD_PLEA_TYPES_SUCCESS', + props<{ pleaStatusTypes: PleaType[] }>() +); + +export const loadPleaTypesError = createAction( + 'LOAD_PLEA_TYPES_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadPoliceForceList = createAction('LOAD_POLICE_FORCE_LIST'); + +export const loadPoliceForceListSuccess = createAction( + 'LOAD_POLICE_FORCE_LIST_SUCCESS', + props<{ policeForceList: PoliceForce[] }>() +); + +export const loadPoliceForceListError = createAction( + 'LOAD_POLICE_FORCE_LIST_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadProsecutors = createAction('LOAD_PROSECUTORS'); + +export const loadProsecutorsSuccess = createAction( + 'LOAD_PROSECUTORS_SUCCESS', + props<{ prosecutors: Prosecutor[] }>() +); + +export const loadProsecutorsError = createAction( + 'LOAD_PROSECUTORS_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadResultDefinitions = createAction('LOAD_RESULT_DEFINITIONS'); + +export const loadResultDefinitionsSuccess = createAction( + 'LOAD_RESULT_DEFINITIONS_SUCCESS', + props<{ resultDefinitions: ResultDefinition[] }>() +); + +export const loadResultDefinitionsError = createAction( + 'LOAD_RESULT_DEFINITIONS_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadRotaBusinessTypes = createAction('LOAD_ROTA_BUSINESS_TYPES'); + +export const loadRotaBusinessTypesSuccess = createAction( + 'LOAD_ROTA_BUSINESS_TYPES_SUCCESS', + props<{ rotaBusinessTypes: RotaBusinessType[] }>() +); + +export const loadRotaBusinessTypesError = createAction( + 'LOAD_ROTA_BUSINESS_TYPES_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadSpecialRequirements = createAction('LOAD_SPECIAL_REQUIREMENTS'); + +export const loadSpecialRequirementsSuccess = createAction( + 'LOAD_SPECIAL_REQUIREMENTS_SUCCESS', + props<{ specialRequirements: SpecialRequirement[] }>() +); + +export const loadSpecialRequirementsError = createAction( + 'LOAD_SPECIAL_REQUIREMENTS_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadWitnessCareUnits = createAction('LOAD_WITNESS_CARE_UNITS'); + +export const loadWitnessCareUnitsSuccess = createAction( + 'LOAD_WITNESS_CARE_UNITS_SUCCESS', + props<{ witnessCareUnits: WitnessCareUnit[] }>() +); + +export const loadWitnessCareUnitsError = createAction( + 'LOAD_WITNESS_CARE_UNITS_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadTrialTypes = createAction('LOAD_TRIAL_TYPES'); + +export const loadTrialTypesSuccess = createAction( + 'LOAD_TRIAL_TYPES_SUCCESS', + props<{ trialTypes: TrialType[] }>() +); + +export const loadTrialTypesError = createAction( + 'LOAD_TRIAL_TYPES_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadPoliceRanks = createAction('LOAD_POLICE_RANKS'); + +export const loadPoliceRanksSuccess = createAction( + 'LOAD_POLICE_RANKS_SUCCESS', + props<{ policeRanks: PoliceRank[] }>() +); + +export const loadPoliceRanksError = createAction( + 'LOAD_POLICE_RANKS_ERROR', + props<{ error: HttpErrorResponse }>() +); +export const loadPublicHolidays = createAction('LOAD_PUBLIC_HOLIDAYS'); + +export const loadPublicHolidaysSuccess = createAction( + 'LOAD_PUBLIC_HOLIDAYS_SUCCESS', + props<{ publicHolidays: PublicHoliday[] }>() +); + +export const loadPublicHolidaysError = createAction( + 'LOAD_PUBLIC_HOLIDAYS_ERROR', + props<{ error: HttpErrorResponse }>() +); + +export const loadOrganisationsWithType = createAction( + 'LOAD_ORGANISATIONS_WITH_TYPE', + props<{ organisationType: OrganisationType }>() +); +export const loadOrganisationsWithTypeSuccess = createAction( + 'LOAD_ORGANISATIONS_WITH_TYPE_SUCCESS', + props<{ organisationsWithType: OrganisationWithType[] }>() +); +export const loadOrganisationsWithTypeError = createAction( + 'LOAD_ORGANISATIONS_WITH_TYPE_ERROR', + props<{ error: HttpErrorResponse }>() +); diff --git a/projects/reference-data/src/components/__tests__/__snapshots__/application-type-standalone.autosuggest.spec.ts.snap b/projects/reference-data/src/components/__tests__/__snapshots__/application-type-standalone.autosuggest.spec.ts.snap new file mode 100644 index 0000000..7aa38fc --- /dev/null +++ b/projects/reference-data/src/components/__tests__/__snapshots__/application-type-standalone.autosuggest.spec.ts.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ApplicationTypeStandaloneAutosuggestComponent should render 1`] = ` + + + + + +`; + +exports[`ApplicationTypeStandaloneAutosuggestComponent when application types are read locally should filter application types found in the store 1`] = ` + + + + + +`; diff --git a/projects/reference-data/src/components/__tests__/__snapshots__/application-type.autosuggest.spec.ts.snap b/projects/reference-data/src/components/__tests__/__snapshots__/application-type.autosuggest.spec.ts.snap new file mode 100644 index 0000000..041d550 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/__snapshots__/application-type.autosuggest.spec.ts.snap @@ -0,0 +1,45 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ApplicationTypeAutosuggestComponent should render 1`] = ` + + + + + +`; + +exports[`ApplicationTypeAutosuggestComponent when application types are read locally should filter application types found in the store 1`] = ` + + + + + +`; diff --git a/projects/reference-data/src/components/__tests__/__snapshots__/assign-priority.select.spec.ts.snap b/projects/reference-data/src/components/__tests__/__snapshots__/assign-priority.select.spec.ts.snap new file mode 100644 index 0000000..5954f32 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/__snapshots__/assign-priority.select.spec.ts.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AssignPrioritySelectComponent should render 1`] = ` + + + + [] + + + +`; diff --git a/projects/reference-data/src/components/__tests__/__snapshots__/booking-type.select.spec.ts.snap b/projects/reference-data/src/components/__tests__/__snapshots__/booking-type.select.spec.ts.snap new file mode 100644 index 0000000..f4af1b4 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/__snapshots__/booking-type.select.spec.ts.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`BookingTypesSelectComponent should render 1`] = ` + + + + [] + + + +`; diff --git a/projects/reference-data/src/components/__tests__/__snapshots__/cluster.autosuggest.spec.ts.snap b/projects/reference-data/src/components/__tests__/__snapshots__/cluster.autosuggest.spec.ts.snap new file mode 100644 index 0000000..68a793a --- /dev/null +++ b/projects/reference-data/src/components/__tests__/__snapshots__/cluster.autosuggest.spec.ts.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ClusterAutosuggestComponent should render 1`] = ` + + + + + +`; + +exports[`ClusterAutosuggestComponent when clusters are read locally should filter clusters found in the store 1`] = ` + + + + + +`; diff --git a/projects/reference-data/src/components/__tests__/__snapshots__/cps-business-unit.select.spec.ts.snap b/projects/reference-data/src/components/__tests__/__snapshots__/cps-business-unit.select.spec.ts.snap new file mode 100644 index 0000000..b2744d0 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/__snapshots__/cps-business-unit.select.spec.ts.snap @@ -0,0 +1,73 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CPSBusinessUnitSelectComponent should render 1`] = ` + + + + [] + + + +`; + +exports[`CPSBusinessUnitSelectComponent when cps business types are present in the store should clear previously rendered options if cps area code is changed to a falsy value 1`] = ` + + + + [] + + + +`; + +exports[`CPSBusinessUnitSelectComponent when cps business types are present in the store should render options filtered by cps area code, and reset ngControl on the select input 1`] = ` + + + + [ + { + "value": "1", + "label": "Unit 1" + }, + { + "value": "2", + "label": "Unit 2" + } + ] + + + +`; diff --git a/projects/reference-data/src/components/__tests__/__snapshots__/police-ranks.select.spec.ts.snap b/projects/reference-data/src/components/__tests__/__snapshots__/police-ranks.select.spec.ts.snap new file mode 100644 index 0000000..d66d432 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/__snapshots__/police-ranks.select.spec.ts.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PoliceRanksSelectComponent should render 1`] = ` + + + + [] + + + +`; diff --git a/projects/reference-data/src/components/__tests__/__snapshots__/witness-care-unit.select.spec.ts.snap b/projects/reference-data/src/components/__tests__/__snapshots__/witness-care-unit.select.spec.ts.snap new file mode 100644 index 0000000..06990f1 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/__snapshots__/witness-care-unit.select.spec.ts.snap @@ -0,0 +1,69 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`WitnessCareUnitSelectComponent should render 1`] = ` + + + + [] + + + +`; + +exports[`WitnessCareUnitSelectComponent when witnessCareUnits are present in the store should clear previously rendered options if cps area code is changed to a falsy value 1`] = ` + + + + [] + + + +`; + +exports[`WitnessCareUnitSelectComponent when witnessCareUnits are present in the store should render options filtered by cps area code, and reset ngControl on the select input 1`] = ` + + + + [ + { + "value": "id2", + "label": "Bristol" + } + ] + + + +`; diff --git a/projects/reference-data/src/components/__tests__/application-type-standalone.autosuggest.spec.ts b/projects/reference-data/src/components/__tests__/application-type-standalone.autosuggest.spec.ts new file mode 100644 index 0000000..4de1e0a --- /dev/null +++ b/projects/reference-data/src/components/__tests__/application-type-standalone.autosuggest.spec.ts @@ -0,0 +1,123 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { PdkAutosuggestLiteComponent } from '@cpp/pdk'; +import { provideStore, Store } from '@ngrx/store'; +import { ReferenceDataActions } from '../../actions'; +import { provideReferenceDataStore } from '../../providers'; +import { ReferenceDataState } from '../../reducers'; +import { CourtApplicationType } from '../../reference-data.interfaces'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { ApplicationTypeStandaloneAutosuggestComponent } from '../application-type-standalone.autosuggest'; + +describe('ApplicationTypeStandaloneAutosuggestComponent', () => { + let fixture: ComponentFixture; + let searchApplicationTypes: jest.Mock; + let store: Store; + + beforeEach(() => { + searchApplicationTypes = jest.fn(); + + TestBed.configureTestingModule({ + providers: [ + provideStore({}), + provideReferenceDataStore(), + { + provide: ReferenceDataService, + useValue: { + searchApplicationTypes + } + } + ] + }); + + fixture = TestBed.overrideComponent(ApplicationTypeStandaloneAutosuggestComponent, { + remove: { + imports: [PdkAutosuggestLiteComponent] + }, + add: { + imports: [MockAutosuggestLiteComponent] + } + }).createComponent(ApplicationTypeStandaloneAutosuggestTestComponent); + fixture.detectChanges(); + + store = TestBed.inject(Store); + }); + + it('should render', () => { + expect(fixture).toMatchSnapshot(); + }); + + describe('when application types are read locally', () => { + it('should filter application types found in the store', () => { + store.dispatch( + ReferenceDataActions.loadApplicationTypesSuccess({ + applicationTypes: [{ type: 'Foo' }, { code: 'Bar' }] as CourtApplicationType[] + }) + ); + const autosuggestLiteRef = fixture.debugElement.query( + By.directive(MockAutosuggestLiteComponent) + ); + + autosuggestLiteRef.componentInstance.inputText.emit('b'); + + expect(fixture).toMatchSnapshot(); + }); + + it('should dispatch an action to fetch application types from the store', () => {}); + }); +}); + +@Component({ + selector: 'cpp-application-type-autosuggest-test', + template: ` + + + `, + imports: [ApplicationTypeStandaloneAutosuggestComponent] +}) +class ApplicationTypeStandaloneAutosuggestTestComponent { + ariaDescribedBy = 'ariaDescribedBy'; + ariaLabel = 'ariaLabel'; + ariaLabelledBy = 'ariaLabelledBy'; + debounceTime = 150; + hasError = false; + highlightFirstSuggestion = false; + highlightMatchedText = false; + id = 'id'; + inputText = jest.fn(); + inputWidth = 4; + maxResults = 10; +} + +@Component({ + selector: 'pdk-autosuggest-lite', + template: `` +}) +class MockAutosuggestLiteComponent { + @Input() ariaDescribedBy?: string; + @Input() ariaLabel?: string; + @Input() ariaLabelledBy?: string; + @Input() hasError?: boolean; + @Input() highlightFirstSuggestion?: boolean; + @Input() highlightMatchedText?: boolean; + @Input() id?: string; + @Input() inputWidth?: number; + @Input() suggestions?: any[]; + @Input() suggestionKey?: string; + @Input() suggestionTitle?: string; + @Input() suggestionSubtitle?: string; + @Output() inputText = new EventEmitter(); +} diff --git a/projects/reference-data/src/components/__tests__/application-type.autosuggest.spec.ts b/projects/reference-data/src/components/__tests__/application-type.autosuggest.spec.ts new file mode 100644 index 0000000..9b72a45 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/application-type.autosuggest.spec.ts @@ -0,0 +1,136 @@ +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { Store, StoreModule } from '@ngrx/store'; +import { ReferenceDataActions } from '../../actions'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers'; +import { CourtApplicationType } from '../../reference-data.interfaces'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { ApplicationTypeAutosuggestComponent } from '../application-type.autosuggest'; +import { PdkAutosuggestLiteComponent } from '@cpp/pdk'; + +describe('ApplicationTypeAutosuggestComponent', () => { + let fixture: ComponentFixture; + let searchApplicationTypes: jest.Mock; + let store: Store; + + beforeEach(() => { + searchApplicationTypes = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + CommonModule, + StoreModule.forRoot(() => null, { + runtimeChecks: {} + }), + StoreModule.forFeature('referenceData', referenceDataReducer), + ApplicationTypeAutosuggestComponent + ], + declarations: [ApplicationTypeAutosuggestTestComponent], + providers: [ + { + provide: ReferenceDataService, + useValue: { + searchApplicationTypes + } + } + ] + }); + + TestBed.overrideComponent(ApplicationTypeAutosuggestComponent, { + remove: { + imports: [PdkAutosuggestLiteComponent] + }, + add: { + imports: [AutosuggestLiteMockComponent] + } + }); + + fixture = TestBed.createComponent(ApplicationTypeAutosuggestTestComponent); + fixture.detectChanges(); + + store = TestBed.inject(Store); + }); + + it('should render', () => { + expect(fixture).toMatchSnapshot(); + }); + + describe('when application types are read locally', () => { + it('should filter application types found in the store', () => { + store.dispatch( + ReferenceDataActions.loadApplicationTypesSuccess({ + applicationTypes: [{ type: 'Foo' }, { code: 'Bar' }] as CourtApplicationType[] + }) + ); + const autosuggestLiteRef = fixture.debugElement.query( + By.directive(AutosuggestLiteMockComponent) + ); + + autosuggestLiteRef.componentInstance.inputText.emit('b'); + + expect(fixture).toMatchSnapshot(); + }); + + it('should dispatch an action to fetch application types from the store', () => {}); + }); +}); + +@Component({ + selector: 'cpp-application-type-autosuggest-test', + template: ` + + + `, + standalone: false +}) +class ApplicationTypeAutosuggestTestComponent { + ariaDescribedBy = 'ariaDescribedBy'; + ariaLabel = 'ariaLabel'; + ariaLabelledBy = 'ariaLabelledBy'; + debounceTime = 150; + fetchOptionsOnMount = true; + hasError = false; + highlightFirstSuggestion = false; + highlightMatchedText = false; + id = 'id'; + inputText = jest.fn(); + inputWidth = 4; + maxResults = 10; + search = false; +} + +@Component({ + selector: 'pdk-autosuggest-lite', + template: `` +}) +class AutosuggestLiteMockComponent { + @Input() ariaDescribedBy?: string; + @Input() ariaLabel?: string; + @Input() ariaLabelledBy?: string; + @Input() hasError?: boolean; + @Input() highlightFirstSuggestion?: boolean; + @Input() highlightMatchedText?: boolean; + @Input() id?: string; + @Input() inputWidth?: number; + @Input() suggestions?: any[]; + @Input() suggestionKey?: string; + @Input() suggestionTitle?: string; + @Input() suggestionSubtitle?: string; + @Output() inputText = new EventEmitter(); +} diff --git a/projects/reference-data/src/components/__tests__/assign-priority.select.spec.ts b/projects/reference-data/src/components/__tests__/assign-priority.select.spec.ts new file mode 100644 index 0000000..1880985 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/assign-priority.select.spec.ts @@ -0,0 +1,117 @@ +import { CommonModule, JsonPipe } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { Store, StoreModule } from '@ngrx/store'; +import { ReferenceDataActions } from '../../actions'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { AssignPrioritySelectComponent } from '../assign-priority.select'; + +let reset: jest.Mock; + +describe('AssignPrioritySelectComponent', () => { + let fixture: ComponentFixture; + let fetchAssignPriorities: jest.Mock; + + let store: Store; + + beforeEach(() => { + fetchAssignPriorities = jest.fn(); + reset = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + CommonModule, + StoreModule.forRoot(() => null, { + runtimeChecks: {} + }), + StoreModule.forFeature('referenceData', referenceDataReducer), + AssignPrioritySelectComponent + ], + declarations: [AssignPrioritySelectComponentTestComponent], + providers: [ + { + provide: ReferenceDataService, + useValue: { + fetchAssignPriorities + } + } + ] + }); + + TestBed.overrideComponent(AssignPrioritySelectComponent, { + remove: { + imports: [PdkSelectComponent] + }, + add: { + imports: [SelectTestComponent] + } + }); + store = TestBed.inject(Store); + jest.spyOn(store, 'dispatch'); + fixture = TestBed.createComponent(AssignPrioritySelectComponentTestComponent); + fixture.detectChanges(); + }); + + it('should render', () => { + expect(fixture).toMatchSnapshot(); + }); + + describe('when assignPriorities are not present in the store ', () => { + it('should dispatch an action to load assign priorities', () => { + expect(store.dispatch).toHaveBeenCalledWith(ReferenceDataActions.loadAssignPriorities()); + }); + }); +}); + +@Component({ + selector: 'assign-priority-select-test', + template: ` + + + `, + standalone: false +}) +class AssignPrioritySelectComponentTestComponent { + ariaDescribedBy = 'ariaDescribedBy'; + disabled = false; + fetchOptionsOnMount = true; + id = 'id'; + justified = true; + name = 'name'; + placeholder = 'placeholder'; + policeForceCode: string | undefined = undefined; + required = false; + change = jest.fn(); +} + +@Component({ + selector: 'pdk-select', + template: ` {{ options | json }} `, + imports: [JsonPipe] +}) +class SelectTestComponent { + @Input() ariaDescribedBy?: string; + @Input() disabled?: boolean; + @Input() id?: string; + @Input() justified?: string; + @Input() name?: string; + @Input() options?: SelectOption[]; + @Input() placeholder?: string; + @Input() required?: boolean; + + ngControl = { + reset + }; +} diff --git a/projects/reference-data/src/components/__tests__/booking-type.select.spec.ts b/projects/reference-data/src/components/__tests__/booking-type.select.spec.ts new file mode 100644 index 0000000..5588956 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/booking-type.select.spec.ts @@ -0,0 +1,118 @@ +import { CommonModule, JsonPipe } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { Store, StoreModule } from '@ngrx/store'; +import { ReferenceDataActions } from '../../actions'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { BookingTypesSelectComponent } from '../booking-type.select'; + +let reset: jest.Mock; + +describe('BookingTypesSelectComponent', () => { + let fixture: ComponentFixture; + let fetchBookingTypes: jest.Mock; + + let store: Store; + + beforeEach(() => { + fetchBookingTypes = jest.fn(); + reset = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + CommonModule, + StoreModule.forRoot(() => null, { + runtimeChecks: {} + }), + StoreModule.forFeature('referenceData', referenceDataReducer), + BookingTypesSelectComponent + ], + declarations: [BookingTypesSelectComponentTestComponent], + providers: [ + { + provide: ReferenceDataService, + useValue: { + fetchBookingTypes + } + } + ] + }); + + TestBed.overrideComponent(BookingTypesSelectComponent, { + remove: { + imports: [PdkSelectComponent] + }, + add: { + imports: [SelectTestComponent] + } + }); + + store = TestBed.inject(Store); + jest.spyOn(store, 'dispatch'); + fixture = TestBed.createComponent(BookingTypesSelectComponentTestComponent); + fixture.detectChanges(); + }); + + it('should render', () => { + expect(fixture).toMatchSnapshot(); + }); + + describe('when bookingTypes are not present in the store ', () => { + it('should dispatch an action to load bookingTypes', () => { + expect(store.dispatch).toHaveBeenCalledWith(ReferenceDataActions.loadBookingTypes()); + }); + }); +}); + +@Component({ + selector: 'booking-types-select-test', + template: ` + + + `, + standalone: false +}) +class BookingTypesSelectComponentTestComponent { + ariaDescribedBy = 'ariaDescribedBy'; + disabled = false; + fetchOptionsOnMount = true; + id = 'id'; + justified = true; + name = 'name'; + placeholder = 'placeholder'; + policeForceCode: string | undefined = undefined; + required = false; + change = jest.fn(); +} + +@Component({ + selector: '', + template: ` {{ options | json }} `, + imports: [JsonPipe] +}) +class SelectTestComponent { + @Input() ariaDescribedBy?: string; + @Input() disabled?: boolean; + @Input() id?: string; + @Input() justified?: string; + @Input() name?: string; + @Input() options?: SelectOption[]; + @Input() placeholder?: string; + @Input() required?: boolean; + + ngControl = { + reset + }; +} diff --git a/projects/reference-data/src/components/__tests__/cluster.autosuggest.spec.ts b/projects/reference-data/src/components/__tests__/cluster.autosuggest.spec.ts new file mode 100644 index 0000000..fcea904 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/cluster.autosuggest.spec.ts @@ -0,0 +1,139 @@ +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { Store, StoreModule } from '@ngrx/store'; +import { ReferenceDataActions } from '../../actions'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers'; +import { Cluster } from '../../reference-data.interfaces'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { ClusterAutosuggestComponent } from '../cluster.autosuggest'; +import { PdkAutosuggestLiteComponent } from '@cpp/pdk'; + +describe('ClusterAutosuggestComponent', () => { + let fixture: ComponentFixture; + let fetchClusters: jest.Mock; + let store: Store; + + beforeEach(() => { + fetchClusters = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + CommonModule, + StoreModule.forRoot(() => null, { + runtimeChecks: {} + }), + StoreModule.forFeature('referenceData', referenceDataReducer), + ClusterAutosuggestComponent + ], + declarations: [ClusterAutosuggestComponentTestComponent], + providers: [ + { + provide: ReferenceDataService, + useValue: { + fetchClusters + } + } + ] + }); + + TestBed.overrideComponent(ClusterAutosuggestComponent, { + remove: { + imports: [PdkAutosuggestLiteComponent] + }, + add: { + imports: [AutosuggestLiteMockComponent] + } + }); + + fixture = TestBed.createComponent(ClusterAutosuggestComponentTestComponent); + + store = TestBed.inject(Store); + jest.spyOn(store, 'dispatch'); + + fixture.detectChanges(); + }); + + it('should render', () => { + expect(fixture).toMatchSnapshot(); + }); + + describe('when clusters are read locally', () => { + it('should filter clusters found in the store', () => { + store.dispatch( + ReferenceDataActions.loadClustersSuccess({ + clusters: [{ clusterCode: 'Foo', clusterName: 'foo' }, { code: 'Bar' }] as Cluster[] + }) + ); + const autosuggestLiteRef = fixture.debugElement.query( + By.directive(AutosuggestLiteMockComponent) + ); + + autosuggestLiteRef.componentInstance.inputText.emit('b'); + + expect(fixture).toMatchSnapshot(); + }); + }); + + describe('when clusters are not present in the store ', () => { + it('should dispatch an action to load clusters', () => { + expect(store.dispatch).toHaveBeenCalledWith(ReferenceDataActions.loadClusters()); + }); + }); +}); + +@Component({ + selector: 'cpp-cluster-autosuggest-test', + template: ` + + + `, + standalone: false +}) +class ClusterAutosuggestComponentTestComponent { + ariaDescribedBy = 'ariaDescribedBy'; + ariaLabel = 'ariaLabel'; + ariaLabelledBy = 'ariaLabelledBy'; + fetchOptionsOnMount = true; + hasError = false; + highlightFirstSuggestion = false; + highlightMatchedText = false; + id = 'id'; + inputText = jest.fn(); + inputWidth = 4; + maxResults = 10; + search = false; +} + +@Component({ + selector: 'pdk-autosuggest-lite', + template: `` +}) +class AutosuggestLiteMockComponent { + @Input() ariaDescribedBy?: string; + @Input() ariaLabel?: string; + @Input() ariaLabelledBy?: string; + @Input() hasError?: boolean; + @Input() highlightFirstSuggestion?: boolean; + @Input() highlightMatchedText?: boolean; + @Input() id?: string; + @Input() inputWidth?: number; + @Input() suggestions?: any[]; + @Input() suggestionKey?: string; + @Input() suggestionTitle?: string; + @Input() suggestionSubtitle?: string; + @Output() inputText = new EventEmitter(); +} diff --git a/projects/reference-data/src/components/__tests__/cps-business-unit.select.spec.ts b/projects/reference-data/src/components/__tests__/cps-business-unit.select.spec.ts new file mode 100644 index 0000000..1ae2093 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/cps-business-unit.select.spec.ts @@ -0,0 +1,154 @@ +import { JsonPipe } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { Store, StoreModule } from '@ngrx/store'; +import { ReferenceDataActions } from '../../actions'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers'; +import { CPSBusinessUnit } from '../../reference-data.interfaces'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { CPSBusinessUnitSelectComponent } from '../cps-business-unit.select'; + +let reset: jest.Mock; + +describe('CPSBusinessUnitSelectComponent', () => { + let fixture: ComponentFixture; + let fetchCPSBusinessUnits: jest.Mock; + + let store: Store; + + beforeEach(() => { + fetchCPSBusinessUnits = jest.fn(); + reset = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot(() => null, { + runtimeChecks: {} + }), + StoreModule.forFeature('referenceData', referenceDataReducer), + CPSBusinessUnitSelectComponent + ], + declarations: [CPSBusinessUnitSelectComponentTestComponent], + providers: [ + { + provide: ReferenceDataService, + useValue: { + fetchCPSBusinessUnits + } + } + ] + }); + + TestBed.overrideComponent(CPSBusinessUnitSelectComponent, { + remove: { + imports: [PdkSelectComponent] + }, + add: { + imports: [SelectTestComponent] + } + }); + + store = TestBed.inject(Store); + jest.spyOn(store, 'dispatch'); + fixture = TestBed.createComponent(CPSBusinessUnitSelectComponentTestComponent); + fixture.detectChanges(); + }); + + it('should render', () => { + expect(fixture).toMatchSnapshot(); + }); + + describe('when cps business types are present in the store ', () => { + beforeEach(() => { + store.dispatch( + ReferenceDataActions.loadCPSBusinessUnitsSuccess({ + cpsBusinessUnits: [ + { id: '1', cmsAreaCode: 1, unitCode: 1, unitName: 'Unit 1' }, + { id: '2', cmsAreaCode: 1, unitCode: 2, unitName: 'Unit 2' }, + { id: '3', cmsAreaCode: 2, unitCode: 3, unitName: 'Unit 3' } + ] as CPSBusinessUnit[] + }) + ); + }); + + it('should render options filtered by cps area code, and reset ngControl on the select input', () => { + fixture.componentInstance.cmsAreaCode = '1'; + fixture.detectChanges(); + expect(fixture).toMatchSnapshot(); + expect(reset).toHaveBeenCalledTimes(1); + }); + + it('should clear previously rendered options if cps area code is changed to a falsy value', () => { + fixture.componentInstance.cmsAreaCode = '2'; + fixture.detectChanges(); + fixture.componentInstance.cmsAreaCode = undefined; + fixture.detectChanges(); + expect(fixture).toMatchSnapshot(); + }); + }); + + describe('when cps business types are not present in the store ', () => { + it('should dispatch an action to load cps business units', () => { + expect(store.dispatch).toHaveBeenCalledWith(ReferenceDataActions.loadCPSBusinessUnits()); + }); + }); +}); + +@Component({ + selector: 'cpp-business-unit-select-test', + template: ` + + + `, + standalone: false +}) +class CPSBusinessUnitSelectComponentTestComponent { + ariaDescribedBy = 'ariaDescribedBy'; + disabled = false; + cmsAreaCode: string | undefined = undefined; + fetchOptionsOnMount = true; + id = 'id'; + justified = true; + name = 'name'; + placeholder = 'placeholder'; + required = false; + change = jest.fn(); +} + +@Component({ + selector: '', + template: ` {{ options | json }} `, + imports: [JsonPipe], + providers: [ + { + provide: PdkSelectComponent, + useExisting: SelectTestComponent + } + ] +}) +class SelectTestComponent { + @Input() ariaDescribedBy?: string; + @Input() disabled?: boolean; + @Input() id?: string; + @Input() justified?: string; + @Input() name?: string; + @Input() options?: SelectOption[]; + @Input() placeholder?: string; + @Input() required?: boolean; + + ngControl = { + reset + }; +} diff --git a/projects/reference-data/src/components/__tests__/police-ranks.select.spec.ts b/projects/reference-data/src/components/__tests__/police-ranks.select.spec.ts new file mode 100644 index 0000000..1cf5583 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/police-ranks.select.spec.ts @@ -0,0 +1,116 @@ +import { CommonModule, JsonPipe } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { Store, StoreModule } from '@ngrx/store'; +import { ReferenceDataActions } from '../../actions'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { PoliceRanksSelectComponent } from '../police-ranks.select'; + +let reset: jest.Mock; + +describe('PoliceRanksSelectComponent', () => { + let fixture: ComponentFixture; + let fetchPoliceRanks: jest.Mock; + + let store: Store; + + beforeEach(() => { + fetchPoliceRanks = jest.fn(); + reset = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + CommonModule, + StoreModule.forRoot(() => null, { + runtimeChecks: {} + }), + StoreModule.forFeature('referenceData', referenceDataReducer), + PoliceRanksSelectComponent + ], + declarations: [PoliceRanksSelectComponentTestComponent], + providers: [ + { + provide: ReferenceDataService, + useValue: { + fetchPoliceRanks + } + } + ] + }); + TestBed.overrideComponent(PoliceRanksSelectComponent, { + remove: { + imports: [PdkSelectComponent] + }, + add: { + imports: [SelectTestComponent] + } + }); + store = TestBed.get(Store); + jest.spyOn(store, 'dispatch'); + fixture = TestBed.createComponent(PoliceRanksSelectComponentTestComponent); + fixture.detectChanges(); + }); + + it('should render', () => { + expect(fixture).toMatchSnapshot(); + }); + + describe('when policeRanks are not present in the store ', () => { + it('should dispatch an action to load police ranks', () => { + expect(store.dispatch).toHaveBeenCalledWith(ReferenceDataActions.loadPoliceRanks()); + }); + }); +}); + +@Component({ + selector: 'cpp-police-ranks-select-test', + template: ` + + + `, + standalone: false +}) +class PoliceRanksSelectComponentTestComponent { + ariaDescribedBy = 'ariaDescribedBy'; + disabled = false; + fetchOptionsOnMount = true; + id = 'id'; + justified = true; + name = 'name'; + placeholder = 'placeholder'; + policeForceCode: string | undefined = undefined; + required = false; + change = jest.fn(); +} + +@Component({ + selector: '', + template: ` {{ options | json }} `, + imports: [JsonPipe] +}) +class SelectTestComponent { + @Input() ariaDescribedBy?: string; + @Input() disabled?: boolean; + @Input() id?: string; + @Input() justified?: string; + @Input() name?: string; + @Input() options?: SelectOption[]; + @Input() placeholder?: string; + @Input() required?: boolean; + + ngControl = { + reset + }; +} diff --git a/projects/reference-data/src/components/__tests__/witness-care-unit.select.spec.ts b/projects/reference-data/src/components/__tests__/witness-care-unit.select.spec.ts new file mode 100644 index 0000000..8c2cc65 --- /dev/null +++ b/projects/reference-data/src/components/__tests__/witness-care-unit.select.spec.ts @@ -0,0 +1,146 @@ +import { JsonPipe } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { provideStore, Store } from '@ngrx/store'; +import { ReferenceDataActions } from '../../actions'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers'; +import { WitnessCareUnit } from '../../reference-data.interfaces'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { WitnessCareUnitSelectComponent } from '../witness-care-unit.select'; + +let reset: jest.Mock; + +describe('WitnessCareUnitSelectComponent', () => { + let fixture: ComponentFixture; + let fetchWitnessCareUnits: jest.Mock; + + let store: Store; + + beforeEach(() => { + fetchWitnessCareUnits = jest.fn(); + reset = jest.fn(); + + TestBed.configureTestingModule({ + imports: [WitnessCareUnitSelectComponent], + declarations: [WitnessCareUnitSelectComponentTestComponent], + providers: [ + provideStore({ referenceData: referenceDataReducer }, { runtimeChecks: {} }), + { + provide: ReferenceDataService, + useValue: { + fetchWitnessCareUnits + } + } + ] + }); + TestBed.overrideComponent(WitnessCareUnitSelectComponent, { + remove: { + imports: [PdkSelectComponent] + }, + add: { + imports: [SelectTestComponent] + } + }); + store = TestBed.inject(Store); + jest.spyOn(store, 'dispatch'); + fixture = TestBed.createComponent(WitnessCareUnitSelectComponentTestComponent); + fixture.detectChanges(); + }); + + it('should render', () => { + expect(fixture).toMatchSnapshot(); + }); + + describe('when witnessCareUnits are present in the store ', () => { + beforeEach(() => { + store.dispatch( + ReferenceDataActions.loadWitnessCareUnitsSuccess({ + witnessCareUnits: [ + { id: 'id1', wcuName: 'Manchester', wcuCode: 'wcuCode1', policeForceCode: '22' }, + { id: 'id2', wcuName: 'Bristol', wcuCode: 'wcuCode2', policeForceCode: '36' } + ] as WitnessCareUnit[] + }) + ); + }); + + it('should render options filtered by cps area code, and reset ngControl on the select input', () => { + fixture.componentInstance.policeForceCode = '36'; + fixture.detectChanges(); + expect(fixture).toMatchSnapshot(); + expect(reset).toHaveBeenCalledTimes(1); + }); + + it('should clear previously rendered options if cps area code is changed to a falsy value', () => { + fixture.componentInstance.policeForceCode = '28'; + fixture.detectChanges(); + fixture.componentInstance.policeForceCode = undefined; + fixture.detectChanges(); + expect(fixture).toMatchSnapshot(); + }); + }); + + describe('when witnessCareUnits are not present in the store ', () => { + it('should dispatch an action to load witness care units', () => { + expect(store.dispatch).toHaveBeenCalledWith(ReferenceDataActions.loadWitnessCareUnits()); + }); + }); +}); + +@Component({ + selector: 'witness-care-unit-select-test', + template: ` + + + `, + standalone: false +}) +class WitnessCareUnitSelectComponentTestComponent { + ariaDescribedBy = 'ariaDescribedBy'; + disabled = false; + fetchOptionsOnMount = true; + id = 'id'; + justified = true; + name = 'name'; + placeholder = 'placeholder'; + policeForceCode: string | undefined = undefined; + required = false; + change = jest.fn(); +} + +@Component({ + selector: '', + template: ` {{ options | json }} `, + providers: [ + { + provide: PdkSelectComponent, + useClass: SelectTestComponent + } + ], + imports: [JsonPipe] +}) +class SelectTestComponent { + @Input() ariaDescribedBy?: string; + @Input() disabled?: boolean; + @Input() id?: string; + @Input() justified?: string; + @Input() name?: string; + @Input() options?: SelectOption[]; + @Input() placeholder?: string; + @Input() required?: boolean; + + ngControl = { + reset + }; +} diff --git a/projects/reference-data/src/components/application-type-standalone.autosuggest.ts b/projects/reference-data/src/components/application-type-standalone.autosuggest.ts new file mode 100644 index 0000000..f77f121 --- /dev/null +++ b/projects/reference-data/src/components/application-type-standalone.autosuggest.ts @@ -0,0 +1,128 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { Component, EventEmitter, forwardRef, Input, Output, ViewChild } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { PdkAutosuggestLiteComponent, FormFieldControl, InputWidth } from '@cpp/pdk'; +import { BehaviorSubject, Observable, of, Subject } from 'rxjs'; +import { catchError, delay, filter, map, startWith, switchMap, tap } from 'rxjs/operators'; +import { CourtApplicationType } from '../reference-data.interfaces'; +import { ReferenceDataService } from '../services/reference-data.service'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'cpp-application-type-standalone-autosuggest', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ApplicationTypeStandaloneAutosuggestComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => ApplicationTypeStandaloneAutosuggestComponent) + } + ], + imports: [PdkAutosuggestLiteComponent, AsyncPipe] +}) +export class ApplicationTypeStandaloneAutosuggestComponent + implements ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() ariaLabel: string | null = null; + @Input() ariaLabelledBy: string | null = null; + @Input() debounceTime = 250; + @Input() hasError = false; + @Input() highlightFirstSuggestion?: boolean; + @Input() highlightMatchedText = true; + @Input() id!: string; + @Input() inputWidth?: InputWidth; + @Input() maxResults = 6; + @Input() filterBy: (applicationType: CourtApplicationType) => boolean = () => true; + @Output() error = new EventEmitter(); + @ViewChild(PdkAutosuggestLiteComponent, { static: true }) + autosuggestLiteRef!: PdkAutosuggestLiteComponent; + search$ = new Subject(); + searching$ = new BehaviorSubject(false); + suggestions$: Observable; + suggestionKey: keyof CourtApplicationType = 'id'; + suggestionTitle: keyof CourtApplicationType = 'type'; + suggestionSubtitle: keyof CourtApplicationType = 'code'; + + constructor(private referenceData: ReferenceDataService) { + this.suggestions$ = this.search$.pipe( + filter((search) => !!search && search.trim().length > 2), + map((search) => search.toLowerCase()), + switchMap((search) => + of(search).pipe( + tap(() => this.searching$.next(true)), + delay(this.debounceTime), + switchMap(() => + this.referenceData + .searchApplicationStandAloneTypes({ + search, + limit: this.maxResults + }) + .pipe(map((appTypes) => appTypes.filter(this.filterBy))) + ), + tap({ + error: (error: HttpErrorResponse) => this.error.emit(error) + }), + catchError(() => of([])), + tap(() => this.searching$.next(false)) + ) + ), + startWith([]) + ); + } + + propagateChange: (_: any) => void = (fn: any) => { + this.autosuggestLiteRef.propagateChange(fn); + }; + + registerOnChange(fn: (_: any) => void): void { + this.autosuggestLiteRef.registerOnChange(fn); + } + + registerOnTouched(fn: any) { + this.autosuggestLiteRef.registerOnTouched(fn); + } + + writeValue(value?: T) { + this.autosuggestLiteRef.writeValue(value); + } + + // FormFieldControl forwarding + + get controlType() { + return this.autosuggestLiteRef.controlType; + } + + get multi() { + return this.autosuggestLiteRef.multi; + } + + get ngControl() { + return this.autosuggestLiteRef.ngControl; + } + + get controlRef() { + return this.autosuggestLiteRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/application-type.autosuggest.ts b/projects/reference-data/src/components/application-type.autosuggest.ts new file mode 100644 index 0000000..1006b5d --- /dev/null +++ b/projects/reference-data/src/components/application-type.autosuggest.ts @@ -0,0 +1,194 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { PdkAutosuggestLiteComponent, FormFieldControl, InputWidth } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { BehaviorSubject, Observable, of, Subject } from 'rxjs'; +import { + catchError, + delay, + filter, + map, + startWith, + switchMap, + switchMapTo, + take, + tap +} from 'rxjs/operators'; +import { loadApplicationTypes } from '../actions/reference-data.actions'; +import { + getApplicationTypes, + getApplicationTypesFetching, + ReferenceDataState +} from '../reducers/index'; +import { CourtApplicationType } from '../reference-data.interfaces'; +import { ReferenceDataService } from '../services/reference-data.service'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'cpp-application-type-autosuggest', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ApplicationTypeAutosuggestComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => ApplicationTypeAutosuggestComponent) + } + ], + imports: [PdkAutosuggestLiteComponent, AsyncPipe] +}) +export class ApplicationTypeAutosuggestComponent + implements OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() ariaLabel: string | null = null; + @Input() ariaLabelledBy: string | null = null; + @Input() debounceTime = 250; + @Input() fetchOptionsOnMount = false; + @Input() hasError = false; + @Input() highlightFirstSuggestion?: boolean; + @Input() highlightMatchedText = true; + @Input() filterBy?: (applicationType: CourtApplicationType) => boolean; + @Input() id!: string; + @Input() inputWidth?: InputWidth; + @Input() maxResults = 6; + @Input() search = false; + @Output() error = new EventEmitter(); + @ViewChild(PdkAutosuggestLiteComponent, { static: true }) + autosuggestLiteRef!: PdkAutosuggestLiteComponent; + fetchingApplicationTypes$: Observable; + search$ = new Subject(); + searching$ = new BehaviorSubject(false); + suggestions$: Observable; + suggestionKey: keyof CourtApplicationType = 'id'; + suggestionTitle: keyof CourtApplicationType = 'type'; + suggestionSubtitle: keyof CourtApplicationType = 'code'; + constructor( + private referenceData: ReferenceDataService, + private store: Store + ) { + this.fetchingApplicationTypes$ = this.store.pipe(select(getApplicationTypesFetching)); + this.suggestions$ = this.search$.pipe( + map((q) => q.toLowerCase()), + switchMap((q) => { + if (q.length !== 0) { + if (this.search) { + return of(q).pipe( + tap(() => this.searching$.next(true)), + delay(this.debounceTime), + switchMap(() => + this.referenceData.searchApplicationTypes({ + q, + limit: this.maxResults + }) + ), + tap({ + error: (error: HttpErrorResponse) => this.error.emit(error) + }), + catchError(() => of([])), + tap(() => this.searching$.next(false)) + ); + } + return this.store.pipe( + select(getApplicationTypes), + take(1), + tap((applicationTypes) => { + if (applicationTypes === undefined) { + this.store.dispatch(loadApplicationTypes()); + } + }), + switchMapTo(this.store), + select(getApplicationTypes), + filter((applicationTypes) => applicationTypes !== null), + take(1), + map((applicationTypes) => { + if (applicationTypes) { + const filterBy = this.filterBy || (() => true); + return applicationTypes.filter((applicationType) => { + const { type, code } = applicationType; + const hasKeyWord = + type.toLowerCase().includes(q) || (code || '').toLowerCase().includes(q); + return hasKeyWord && filterBy(applicationType); + }); + } + return []; + }), + map((applicationTypes) => applicationTypes.slice(0, Math.max(this.maxResults, 10))) + ); + } + return of([]); + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount && !this.search) { + this.store.dispatch(loadApplicationTypes()); + } + } + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.autosuggestLiteRef.propagateChange(fn); + }; + + registerOnChange(fn: (_: any) => void): void { + this.autosuggestLiteRef.registerOnChange(fn); + } + + registerOnTouched(fn: any) { + this.autosuggestLiteRef.registerOnTouched(fn); + } + + writeValue(value?: T) { + this.autosuggestLiteRef.writeValue(value); + } + + // FormFieldControl forwarding + + get controlType() { + return this.autosuggestLiteRef.controlType; + } + + get multi() { + return this.autosuggestLiteRef.multi; + } + + get ngControl() { + return this.autosuggestLiteRef.ngControl; + } + get controlRef() { + return this.autosuggestLiteRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/assign-priority.select.ts b/projects/reference-data/src/components/assign-priority.select.ts new file mode 100644 index 0000000..c5d2e2a --- /dev/null +++ b/projects/reference-data/src/components/assign-priority.select.ts @@ -0,0 +1,139 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { FormFieldControl, SelectChangeEvent, PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { map, startWith, take } from 'rxjs/operators'; +import { loadAssignPriorities } from '../actions/reference-data.actions'; +import { getAssignPriorities, ReferenceDataState } from '../reducers/index'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'assign-priority-select', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => AssignPrioritySelectComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => AssignPrioritySelectComponent) + } + ], + imports: [PdkSelectComponent, AsyncPipe] +}) +export class AssignPrioritySelectComponent + implements OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() disabled?: boolean; + @Input() fetchOptionsOnMount = true; + @Input() id!: string; + @Input() justified?: boolean; + @Input() name!: string; + @Input() placeholder?: string; + @Input() required?: boolean; + @Output() change = new EventEmitter(); + + @ViewChild(PdkSelectComponent, { static: true }) selectRef!: PdkSelectComponent; + + options$: Observable; + + constructor(private store: Store) { + this.options$ = this.store.pipe( + select(getAssignPriorities), + map((assignPriorities) => { + if (assignPriorities) { + return assignPriorities.map(({ id, priorityValue }) => ({ + value: id, + label: priorityValue + })); + } + return []; + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.pipe(select(getAssignPriorities), take(1)).subscribe((assignPriorities) => { + if (!assignPriorities) { + this.store.dispatch(loadAssignPriorities()); + } + }); + } + } + + registerOnChange = (fn: (_: any) => void): void => { + this.selectRef.registerOnChange((priorityId?: string) => { + this.store + .pipe( + select(getAssignPriorities), + take(1), + map((assignPriorities) => { + if (assignPriorities) { + return assignPriorities.find(({ id }) => id === priorityId); + } + return undefined; + }) + ) + .subscribe(fn); + }); + }; + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.selectRef.propagateChange(fn); + }; + + registerOnTouched(fn: any) { + this.selectRef.registerOnTouched(fn); + } + + writeValue(value?: string) { + this.selectRef.writeValue(value ? value : undefined); + } + + // FormFieldControl forwarding + + get controlType() { + return this.selectRef.controlType; + } + + get multi() { + return this.selectRef.multi; + } + + get ngControl() { + return this.selectRef.ngControl; + } + + get controlRef() { + return this.selectRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/booking-type.select.ts b/projects/reference-data/src/components/booking-type.select.ts new file mode 100644 index 0000000..e04500f --- /dev/null +++ b/projects/reference-data/src/components/booking-type.select.ts @@ -0,0 +1,137 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { FormFieldControl, SelectChangeEvent, PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { map, startWith, take } from 'rxjs/operators'; +import { loadBookingTypes } from '../actions/reference-data.actions'; +import { getBookingTypes, ReferenceDataState } from '../reducers/index'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'booking-types-select', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => BookingTypesSelectComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => BookingTypesSelectComponent) + } + ], + imports: [PdkSelectComponent, AsyncPipe] +}) +export class BookingTypesSelectComponent implements OnInit, ControlValueAccessor, FormFieldControl { + @Input() ariaDescribedBy: string | null = null; + @Input() disabled?: boolean; + @Input() fetchOptionsOnMount = true; + @Input() id!: string; + @Input() justified?: boolean; + @Input() name!: string; + @Input() placeholder?: string; + @Input() required?: boolean; + @Output() change = new EventEmitter(); + + @ViewChild(PdkSelectComponent, { static: true }) selectRef!: PdkSelectComponent; + + options$: Observable; + + constructor(private store: Store) { + this.options$ = this.store.pipe( + select(getBookingTypes), + map((assignPriorities) => { + if (assignPriorities) { + return assignPriorities.map(({ id, typeValue }) => ({ + value: id, + label: typeValue + })); + } + return []; + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.pipe(select(getBookingTypes), take(1)).subscribe((bookingTypes) => { + if (!bookingTypes) { + this.store.dispatch(loadBookingTypes()); + } + }); + } + } + + registerOnChange = (fn: (_: any) => void): void => { + this.selectRef.registerOnChange((bookingTypeId?: string) => { + this.store + .pipe( + select(getBookingTypes), + take(1), + map((bookingTypes) => { + if (bookingTypes) { + return bookingTypes.find(({ id }) => id === bookingTypeId); + } + return undefined; + }) + ) + .subscribe(fn); + }); + }; + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.selectRef.propagateChange(fn); + }; + + registerOnTouched(fn: any) { + this.selectRef.registerOnTouched(fn); + } + + writeValue(value?: string) { + this.selectRef.writeValue(value ? value : undefined); + } + + // FormFieldControl forwarding + + get controlType() { + return this.selectRef.controlType; + } + + get multi() { + return this.selectRef.multi; + } + + get ngControl() { + return this.selectRef.ngControl; + } + + get controlRef() { + return this.selectRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/cluster.autosuggest.ts b/projects/reference-data/src/components/cluster.autosuggest.ts new file mode 100644 index 0000000..f51cb7d --- /dev/null +++ b/projects/reference-data/src/components/cluster.autosuggest.ts @@ -0,0 +1,156 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { PdkAutosuggestLiteComponent, FormFieldControl, InputWidth } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable, of, Subject } from 'rxjs'; +import { filter, map, startWith, switchMap, switchMapTo, take, tap } from 'rxjs/operators'; +import { loadClusters } from '../actions/reference-data.actions'; +import { getClusters, getClustersFetching, ReferenceDataState } from '../reducers/index'; +import { Cluster } from '../reference-data.interfaces'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'cpp-cluster-autosuggest', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ClusterAutosuggestComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => ClusterAutosuggestComponent) + } + ], + imports: [AsyncPipe, PdkAutosuggestLiteComponent] +}) +export class ClusterAutosuggestComponent + implements OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() ariaLabel: string | null = null; + @Input() ariaLabelledBy: string | null = null; + @Input() fetchOptionsOnMount = false; + @Input() hasError = false; + @Input() highlightFirstSuggestion?: boolean; + @Input() highlightMatchedText = true; + @Input() id!: string; + @Input() inputWidth?: InputWidth; + @Input() maxResults = 6; + @Output() error = new EventEmitter(); + + @ViewChild(PdkAutosuggestLiteComponent, { static: true }) + autosuggestLiteRef!: PdkAutosuggestLiteComponent; + + fetching$: Observable; + search$ = new Subject(); + suggestions$: Observable; + suggestionKey: keyof Cluster = 'id'; + suggestionTitle: keyof Cluster = 'clusterName'; + + constructor(private store: Store) { + this.fetching$ = this.store.pipe(select(getClustersFetching)); + + this.suggestions$ = this.search$.pipe( + switchMap((q) => { + if (q.length !== 0) { + return this.store.pipe( + select(getClusters), + take(1), + tap((clusters) => { + if (clusters === undefined) { + this.store.dispatch(loadClusters()); + } + }), + switchMapTo(this.store), + select(getClusters), + filter((clusters) => clusters !== null), + take(1), + map((clusters) => { + if (clusters) { + const term = q.toLowerCase(); + + return clusters.filter( + ({ clusterCode, clusterName }) => + clusterCode.toLowerCase().includes(term) || + clusterName.toLowerCase().includes(term) + ); + } + return []; + }), + map((clusters) => clusters.slice(0, Math.max(this.maxResults, 10))) + ); + } + return of([]); + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.dispatch(loadClusters()); + } + } + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.autosuggestLiteRef.propagateChange(fn); + }; + + registerOnChange(fn: (_: any) => void): void { + this.autosuggestLiteRef.registerOnChange(fn); + } + + registerOnTouched(fn: any) { + this.autosuggestLiteRef.registerOnTouched(fn); + } + + writeValue(value?: T) { + this.autosuggestLiteRef.writeValue(value); + } + + // FormFieldControl forwarding + + get controlType() { + return this.autosuggestLiteRef.controlType; + } + + get multi() { + return this.autosuggestLiteRef.multi; + } + + get ngControl() { + return this.autosuggestLiteRef.ngControl; + } + + get controlRef() { + return this.autosuggestLiteRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/cps-area.select.ts b/projects/reference-data/src/components/cps-area.select.ts new file mode 100644 index 0000000..51a7e23 --- /dev/null +++ b/projects/reference-data/src/components/cps-area.select.ts @@ -0,0 +1,138 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { FormFieldControl, SelectChangeEvent, PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { map, startWith, take } from 'rxjs/operators'; +import { loadCPSAreas } from '../actions/reference-data.actions'; +import { getCPSAreas, ReferenceDataState } from '../reducers/index'; +import { CPSArea } from '../reference-data.interfaces'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'cps-area-select', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CPSAreaSelectComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => CPSAreaSelectComponent) + } + ], + imports: [PdkSelectComponent, AsyncPipe] +}) +export class CPSAreaSelectComponent implements OnInit, ControlValueAccessor, FormFieldControl { + @Input() ariaDescribedBy: string | null = null; + @Input() disabled?: boolean; + @Input() fetchOptionsOnMount = true; + @Input() id!: string; + @Input() justified?: boolean; + @Input() name!: string; + @Input() placeholder?: string; + @Input() required?: boolean; + @Output() change = new EventEmitter(); + + @ViewChild(PdkSelectComponent, { static: true }) selectRef!: PdkSelectComponent; + + options$: Observable; + + constructor(private store: Store) { + this.options$ = this.store.pipe( + select(getCPSAreas), + map((cpsAreas) => { + if (cpsAreas) { + return cpsAreas.map((cpsArea) => ({ + value: cpsArea.id, + label: cpsArea.areaName + })); + } + return []; + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.pipe(select(getCPSAreas), take(1)).subscribe((cpsAreas) => { + if (!cpsAreas) { + this.store.dispatch(loadCPSAreas()); + } + }); + } + } + + registerOnChange = (fn: (_: any) => void): void => { + this.selectRef.registerOnChange((cpsAreaId?: string) => { + this.store + .pipe( + select(getCPSAreas), + take(1), + map((cpsAreas) => { + if (cpsAreas) { + return cpsAreas.find(({ id }) => id === cpsAreaId); + } + return undefined; + }) + ) + .subscribe(fn); + }); + }; + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.selectRef.propagateChange(fn); + }; + + registerOnTouched(fn: any) { + this.selectRef.registerOnTouched(fn); + } + + writeValue(value?: CPSArea) { + this.selectRef.writeValue(value ? value.id : undefined); + } + + // FormFieldControl forwarding + + get controlType() { + return this.selectRef.controlType; + } + + get multi() { + return this.selectRef.multi; + } + + get ngControl() { + return this.selectRef.ngControl; + } + + get controlRef() { + return this.selectRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/cps-business-unit.select.ts b/projects/reference-data/src/components/cps-business-unit.select.ts new file mode 100644 index 0000000..bc00d6d --- /dev/null +++ b/projects/reference-data/src/components/cps-business-unit.select.ts @@ -0,0 +1,151 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { FormFieldControl, SelectChangeEvent, PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { map, take } from 'rxjs/operators'; +import { loadCPSBusinessUnits } from '../actions/reference-data.actions'; +import { getCPSBusinessUnits, ReferenceDataState } from '../reducers/index'; +import { CPSBusinessUnit } from '../reference-data.interfaces'; + +@Component({ + selector: 'cps-business-unit-select', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CPSBusinessUnitSelectComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => CPSBusinessUnitSelectComponent) + } + ], + imports: [PdkSelectComponent] +}) +export class CPSBusinessUnitSelectComponent + implements OnChanges, OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() cmsAreaCode?: string; + @Input() disabled?: boolean; + @Input() fetchOptionsOnMount = true; + @Input() id!: string; + @Input() justified?: boolean; + @Input() name!: string; + @Input() placeholder?: string; + @Input() required?: boolean; + @Output() change = new EventEmitter(); + + @ViewChild(PdkSelectComponent, { static: true }) selectRef!: PdkSelectComponent; + + options: SelectOption[] = []; + + ngOnChanges(changes: SimpleChanges) { + if (changes.cmsAreaCode) { + if (!changes.cmsAreaCode.firstChange) { + this.ngControl.reset(); + } + this.store + .select(getCPSBusinessUnits) + .pipe(take(1)) + .subscribe((cpsBusinessUnits) => { + this.options = changes.cmsAreaCode.currentValue + ? (cpsBusinessUnits || []) + .filter( + ({ cmsAreaCode }) => + cmsAreaCode && cmsAreaCode.toString() === changes.cmsAreaCode.currentValue + ) + .map((cpsBusinessUnit) => ({ + value: cpsBusinessUnit.id, + label: cpsBusinessUnit.unitName + })) + : []; + }); + } + } + + constructor(private store: Store) {} + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.pipe(select(getCPSBusinessUnits), take(1)).subscribe((cpsBusinessUnits) => { + if (!cpsBusinessUnits) { + this.store.dispatch(loadCPSBusinessUnits()); + } + }); + } + } + + registerOnChange = (fn: (_: any) => void): void => { + this.selectRef.registerOnChange((cpsUnitId?: string) => { + this.store + .pipe( + select(getCPSBusinessUnits), + take(1), + map((cpsBusinessUnits) => { + if (cpsBusinessUnits) { + return cpsBusinessUnits.find(({ id }) => id === cpsUnitId); + } + return undefined; + }) + ) + .subscribe(fn); + }); + }; + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.selectRef.propagateChange(fn); + }; + + registerOnTouched(fn: any) { + this.selectRef.registerOnTouched(fn); + } + + writeValue(value?: CPSBusinessUnit) { + this.selectRef.writeValue(value ? value.id : undefined); + } + + // FormFieldControl forwarding + + get controlType() { + return this.selectRef.controlType; + } + + get multi() { + return this.selectRef.multi; + } + + get ngControl() { + return this.selectRef.ngControl; + } + + get controlRef() { + return this.selectRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/cps-case-status.select.ts b/projects/reference-data/src/components/cps-case-status.select.ts new file mode 100644 index 0000000..cd8fa75 --- /dev/null +++ b/projects/reference-data/src/components/cps-case-status.select.ts @@ -0,0 +1,140 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { FormFieldControl, SelectChangeEvent, PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { map, startWith, take } from 'rxjs/operators'; +import { loadCPSCaseStatuses } from '../actions/reference-data.actions'; +import { getCPSCaseStatuses, ReferenceDataState } from '../reducers/index'; +import { CPSCaseStatus } from '../reference-data.interfaces'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'cps-case-status-select', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CPSCaseStatusSelectComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => CPSCaseStatusSelectComponent) + } + ], + imports: [PdkSelectComponent, AsyncPipe] +}) +export class CPSCaseStatusSelectComponent + implements OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() disabled?: boolean; + @Input() fetchOptionsOnMount = true; + @Input() id!: string; + @Input() justified?: boolean; + @Input() name!: string; + @Input() placeholder?: string; + @Input() required?: boolean; + @Output() change = new EventEmitter(); + + @ViewChild(PdkSelectComponent, { static: true }) selectRef!: PdkSelectComponent; + + options$: Observable; + + constructor(private store: Store) { + this.options$ = this.store.pipe( + select(getCPSCaseStatuses), + map((cpsCaseStatuses) => { + if (cpsCaseStatuses) { + return cpsCaseStatuses.map((cpsCaseStatus) => ({ + value: cpsCaseStatus.id, + label: cpsCaseStatus.statusDescription + })); + } + return []; + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.pipe(select(getCPSCaseStatuses), take(1)).subscribe((cpsCaseStatuses) => { + if (!cpsCaseStatuses) { + this.store.dispatch(loadCPSCaseStatuses()); + } + }); + } + } + + registerOnChange = (fn: (_: any) => void): void => { + this.selectRef.registerOnChange((cpsCaseStatusId?: string) => { + this.store + .pipe( + select(getCPSCaseStatuses), + take(1), + map((cpsCaseStatuses) => { + if (cpsCaseStatuses) { + return cpsCaseStatuses.find(({ id }) => id === cpsCaseStatusId); + } + return undefined; + }) + ) + .subscribe(fn); + }); + }; + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.selectRef.propagateChange(fn); + }; + + registerOnTouched(fn: any) { + this.selectRef.registerOnTouched(fn); + } + + writeValue(value?: CPSCaseStatus) { + this.selectRef.writeValue(value ? value.id : undefined); + } + + // FormFieldControl forwarding + + get controlType() { + return this.selectRef.controlType; + } + + get multi() { + return this.selectRef.multi; + } + + get ngControl() { + return this.selectRef.ngControl; + } + + get controlRef() { + return this.selectRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/fixed-list.autosuggest.ts b/projects/reference-data/src/components/fixed-list.autosuggest.ts new file mode 100644 index 0000000..fa82f81 --- /dev/null +++ b/projects/reference-data/src/components/fixed-list.autosuggest.ts @@ -0,0 +1,171 @@ +import { + Component, + EventEmitter, + forwardRef, + Injector, + Input, + OnInit, + Output, + ViewChild, + Type +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms'; +import { + PdkAutosuggestComponent, + FormFieldControl, + InputWidth, + PdkTypographyDirective +} from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable, of, Subject } from 'rxjs'; +import { filter, map, startWith, switchMap, switchMapTo, take, tap } from 'rxjs/operators'; +import { loadFixedLists } from '../actions/reference-data.actions'; +import { getFixedLists, getFixedListsFetching, ReferenceDataState } from '../reducers/index'; +import { FixedList } from '../reference-data.interfaces'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'cpp-fixed-list-autosuggest', + template: ` + + + + + @for (element of suggestion.elements; track element.code) { + {{ element.code }} + } + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => FixedListAutosuggestComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => FixedListAutosuggestComponent) + } + ], + imports: [PdkAutosuggestComponent, AsyncPipe, PdkTypographyDirective] +}) +export class FixedListAutosuggestComponent + implements OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() ariaLabel: string | null = null; + @Input() ariaLabelledBy: string | null = null; + @Input() fetchOptionsOnMount = false; + @Input() hasError = false; + @Input() highlightFirstSuggestion?: boolean; + @Input() id!: string; + @Input() inputWidth?: InputWidth; + @Input() maxResults = 6; + @Output() error = new EventEmitter(); + + @ViewChild(PdkAutosuggestComponent, { static: true }) autosuggestRef!: PdkAutosuggestComponent; + + fetching$: Observable; + search$ = new Subject(); + suggestions$: Observable; + + controlType = 'autosuggest'; + inputValue = ''; + multi = false; + + get ngControl() { + return this.injector.get(NgControl as Type); + } + + constructor(private store: Store, private injector: Injector) { + this.fetching$ = this.store.pipe(select(getFixedListsFetching)); + + this.suggestions$ = this.search$.pipe( + switchMap((q) => { + if (q.length !== 0) { + return this.store.pipe( + select(getFixedLists), + take(1), + tap((fixedLists) => { + if (fixedLists.length === 0) { + this.store.dispatch(loadFixedLists()); + } + }), + switchMapTo(this.store), + select(getFixedLists), + filter((fixedLists) => fixedLists.length > 0), + take(1), + map((fixedLists) => { + if (fixedLists) { + const term = q.toLowerCase(); + + return fixedLists.filter(({ elements }) => + elements.some( + ({ code, value }) => + code.toLowerCase().includes(term) || value.toLowerCase().includes(term) + ) + ); + } + return []; + }), + map((fixedLists) => fixedLists.slice(0, Math.max(this.maxResults, 10))) + ); + } + return of([]); + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.dispatch(loadFixedLists()); + } + } + + getKey(fixedList: FixedList) { + return fixedList.id; + } + + getLabel() { + return ''; + } + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.autosuggestRef.propagateChange(fn); + }; + + registerOnChange(fn: (_: any) => void): void { + this.autosuggestRef.registerOnChange(fn); + } + + registerOnTouched(fn: any) { + this.autosuggestRef.registerOnTouched(fn); + } + + writeValue(value?: FixedList) { + this.autosuggestRef.writeValue(value); + } +} diff --git a/projects/reference-data/src/components/hearing-type.autosuggest.ts b/projects/reference-data/src/components/hearing-type.autosuggest.ts new file mode 100644 index 0000000..0f01b0e --- /dev/null +++ b/projects/reference-data/src/components/hearing-type.autosuggest.ts @@ -0,0 +1,156 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { PdkAutosuggestLiteComponent, FormFieldControl, InputWidth } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable, of, Subject } from 'rxjs'; +import { filter, map, startWith, switchMap, switchMapTo, take, tap } from 'rxjs/operators'; +import { loadHearingTypes } from '../actions/reference-data.actions'; +import { getHearingTypes, getHearingTypesFetching, ReferenceDataState } from '../reducers/index'; +import { HearingType } from '../reference-data.interfaces'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'cpp-hearing-type-autosuggest', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => HearingTypeAutosuggestComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => HearingTypeAutosuggestComponent) + } + ], + imports: [PdkAutosuggestLiteComponent, AsyncPipe] +}) +export class HearingTypeAutosuggestComponent + implements OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() ariaLabel: string | null = null; + @Input() ariaLabelledBy: string | null = null; + @Input() fetchOptionsOnMount = false; + @Input() hasError = false; + @Input() highlightFirstSuggestion?: boolean; + @Input() highlightMatchedText = true; + @Input() id!: string; + @Input() inputWidth?: InputWidth; + @Input() maxResults = 6; + @Output() error = new EventEmitter(); + + @ViewChild(PdkAutosuggestLiteComponent, { static: true }) + autosuggestLiteRef!: PdkAutosuggestLiteComponent; + + fetching$: Observable; + search$ = new Subject(); + suggestions$: Observable; + suggestionKey: keyof HearingType = 'id'; + suggestionTitle: keyof HearingType = 'hearingDescription'; + + constructor(private store: Store) { + this.fetching$ = this.store.pipe(select(getHearingTypesFetching)); + + this.suggestions$ = this.search$.pipe( + switchMap((q) => { + if (q.length !== 0) { + return this.store.pipe( + select(getHearingTypes), + take(1), + tap((hearingTypes) => { + if (hearingTypes === undefined) { + this.store.dispatch(loadHearingTypes()); + } + }), + switchMapTo(this.store), + select(getHearingTypes), + filter((hearingTypes) => hearingTypes !== null), + take(1), + map((hearingTypes) => { + if (hearingTypes) { + const term = q.toLowerCase(); + + return hearingTypes.filter( + ({ hearingCode, hearingDescription }) => + hearingCode.toLowerCase().includes(term) || + hearingDescription.toLowerCase().includes(term) + ); + } + return []; + }), + map((hearingTypes) => hearingTypes.slice(0, Math.max(this.maxResults, 10))) + ); + } + return of([]); + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.dispatch(loadHearingTypes()); + } + } + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.autosuggestLiteRef.propagateChange(fn); + }; + + registerOnChange(fn: (_: any) => void): void { + this.autosuggestLiteRef.registerOnChange(fn); + } + + registerOnTouched(fn: any) { + this.autosuggestLiteRef.registerOnTouched(fn); + } + + writeValue(value?: T) { + this.autosuggestLiteRef.writeValue(value); + } + + // FormFieldControl forwarding + + get controlType() { + return this.autosuggestLiteRef.controlType; + } + + get multi() { + return this.autosuggestLiteRef.multi; + } + + get ngControl() { + return this.autosuggestLiteRef.ngControl; + } + + get controlRef() { + return this.autosuggestLiteRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/hearing-type.select.ts b/projects/reference-data/src/components/hearing-type.select.ts new file mode 100644 index 0000000..4fc6a7d --- /dev/null +++ b/projects/reference-data/src/components/hearing-type.select.ts @@ -0,0 +1,138 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { FormFieldControl, SelectChangeEvent, PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { map, startWith, take } from 'rxjs/operators'; +import { loadHearingTypes } from '../actions/reference-data.actions'; +import { getHearingTypes, ReferenceDataState } from '../reducers/index'; +import { HearingType } from '../reference-data.interfaces'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'cpp-hearing-type-select', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => HearingTypeSelectComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => HearingTypeSelectComponent) + } + ], + imports: [PdkSelectComponent, AsyncPipe] +}) +export class HearingTypeSelectComponent implements OnInit, ControlValueAccessor, FormFieldControl { + @Input() ariaDescribedBy: string | null = null; + @Input() disabled?: boolean; + @Input() fetchOptionsOnMount = true; + @Input() id!: string; + @Input() justified?: boolean; + @Input() name!: string; + @Input() placeholder?: string; + @Input() required?: boolean; + @Output() change = new EventEmitter(); + + @ViewChild(PdkSelectComponent, { static: true }) selectRef!: PdkSelectComponent; + + options$: Observable; + + constructor(private store: Store) { + this.options$ = this.store.pipe( + select(getHearingTypes), + map((hearingTypes) => { + if (hearingTypes) { + return hearingTypes.map((hearingType) => ({ + value: hearingType.id, + label: hearingType.hearingDescription + })); + } + return []; + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.pipe(select(getHearingTypes), take(1)).subscribe((hearingTypes) => { + if (!hearingTypes) { + this.store.dispatch(loadHearingTypes()); + } + }); + } + } + + registerOnChange = (fn: (_: any) => void): void => { + this.selectRef.registerOnChange((hearingTypeId?: string) => { + this.store + .pipe( + select(getHearingTypes), + take(1), + map((hearingTypes) => { + if (hearingTypes) { + return hearingTypes.find(({ id }) => id === hearingTypeId); + } + return undefined; + }) + ) + .subscribe(fn); + }); + }; + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.selectRef.propagateChange(fn); + }; + + registerOnTouched(fn: any) { + this.selectRef.registerOnTouched(fn); + } + + writeValue(value?: HearingType) { + this.selectRef.writeValue(value ? value.id : undefined); + } + + // FormFieldControl forwarding + + get controlType() { + return this.selectRef.controlType; + } + + get multi() { + return this.selectRef.multi; + } + + get ngControl() { + return this.selectRef.ngControl; + } + + get controlRef() { + return this.selectRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/index.ts b/projects/reference-data/src/components/index.ts new file mode 100644 index 0000000..fd6bf50 --- /dev/null +++ b/projects/reference-data/src/components/index.ts @@ -0,0 +1,63 @@ +import { ApplicationTypeStandaloneAutosuggestComponent } from './application-type-standalone.autosuggest'; +import { ApplicationTypeAutosuggestComponent } from './application-type.autosuggest'; +import { AssignPrioritySelectComponent } from './assign-priority.select'; +import { BookingTypesSelectComponent } from './booking-type.select'; +import { ClusterAutosuggestComponent } from './cluster.autosuggest'; +import { CPSAreaSelectComponent } from './cps-area.select'; +import { CPSBusinessUnitSelectComponent } from './cps-business-unit.select'; +import { CPSCaseStatusSelectComponent } from './cps-case-status.select'; +import { FixedListAutosuggestComponent } from './fixed-list.autosuggest'; +import { HearingTypeAutosuggestComponent } from './hearing-type.autosuggest'; +import { HearingTypeSelectComponent } from './hearing-type.select'; +import { OrganisationUnitAutosuggestComponent } from './organisation-unit.autosuggest'; +import { OrganisationWithTypeAutosuggestComponent } from './organisation-with-type.autosuggest'; +import { PoliceForceAutosuggestComponent } from './police-force.autosuggest'; +import { PoliceRanksSelectComponent } from './police-ranks.select'; +import { ProsecutorAutosuggestComponent } from './prosecutor.autosuggest'; +import { RotaBusinessTypeSelectComponent } from './rota-business-types.select'; +import { SpecialRequirementCheckboxComponent } from './special-requirements.checkbox'; +import { WitnessCareUnitSelectComponent } from './witness-care-unit.select'; + +export const CppReferenceDataComponents = [ + ApplicationTypeAutosuggestComponent, + ApplicationTypeStandaloneAutosuggestComponent, + BookingTypesSelectComponent, + ClusterAutosuggestComponent, + AssignPrioritySelectComponent, + CPSAreaSelectComponent, + CPSBusinessUnitSelectComponent, + CPSCaseStatusSelectComponent, + FixedListAutosuggestComponent, + HearingTypeAutosuggestComponent, + HearingTypeSelectComponent, + OrganisationUnitAutosuggestComponent, + PoliceForceAutosuggestComponent, + ProsecutorAutosuggestComponent, + SpecialRequirementCheckboxComponent, + WitnessCareUnitSelectComponent, + PoliceRanksSelectComponent, + OrganisationWithTypeAutosuggestComponent, + RotaBusinessTypeSelectComponent +] as const; + +export { + ApplicationTypeAutosuggestComponent, + ApplicationTypeStandaloneAutosuggestComponent, + BookingTypesSelectComponent, + ClusterAutosuggestComponent, + AssignPrioritySelectComponent, + CPSAreaSelectComponent, + CPSBusinessUnitSelectComponent, + CPSCaseStatusSelectComponent, + FixedListAutosuggestComponent, + HearingTypeAutosuggestComponent, + HearingTypeSelectComponent, + OrganisationUnitAutosuggestComponent, + PoliceForceAutosuggestComponent, + ProsecutorAutosuggestComponent, + SpecialRequirementCheckboxComponent, + WitnessCareUnitSelectComponent, + PoliceRanksSelectComponent, + OrganisationWithTypeAutosuggestComponent, + RotaBusinessTypeSelectComponent +}; diff --git a/projects/reference-data/src/components/organisation-unit.autosuggest.ts b/projects/reference-data/src/components/organisation-unit.autosuggest.ts new file mode 100644 index 0000000..0f13842 --- /dev/null +++ b/projects/reference-data/src/components/organisation-unit.autosuggest.ts @@ -0,0 +1,180 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { PdkAutosuggestLiteComponent, FormFieldControl, InputWidth } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable, of, Subject } from 'rxjs'; +import { filter, map, startWith, switchMap, switchMapTo, take, tap } from 'rxjs/operators'; +import { loadOrganisationUnits } from '../actions/reference-data.actions'; +import { + getOrganisationUnits, + getOrganisationUnitsFetching, + ReferenceDataState +} from '../reducers/index'; +import { OrganisationUnit } from '../reference-data.interfaces'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'cpp-organisation-unit-autosuggest', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => OrganisationUnitAutosuggestComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => OrganisationUnitAutosuggestComponent) + } + ], + imports: [PdkAutosuggestLiteComponent, AsyncPipe] +}) +export class OrganisationUnitAutosuggestComponent + implements OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() ariaLabel: string | null = null; + @Input() ariaLabelledBy: string | null = null; + @Input() fetchOptionsOnMount = false; + @Input() filterBy?: (organisationUnit: OrganisationUnit) => boolean; + @Input() hasError = false; + @Input() highlightFirstSuggestion?: boolean; + @Input() highlightMatchedText = true; + @Input() id!: string; + @Input() inputWidth?: InputWidth; + @Input() maxResults = 6; + @Input() placeholder?: OrganisationUnit; + @Input() jurisdictionCode?: 'B' | 'C'; + @Output() error = new EventEmitter(); + + @ViewChild(PdkAutosuggestLiteComponent, { static: true }) + autosuggestLiteRef!: PdkAutosuggestLiteComponent; + + fetching$: Observable; + search$ = new Subject(); + suggestions$: Observable; + suggestionKey: keyof OrganisationUnit = 'id'; + suggestionTitle: keyof OrganisationUnit = 'oucodeL3Name'; + disabled = false; + + constructor(private store: Store) { + this.fetching$ = this.store.pipe(select(getOrganisationUnitsFetching)); + + this.suggestions$ = this.search$.pipe( + map((q) => q.toLowerCase()), + switchMap((q) => { + if (q.length !== 0) { + return this.store.pipe( + select(getOrganisationUnits), + take(1), + tap((organisationUnits) => { + if (organisationUnits === undefined) { + this.store.dispatch(loadOrganisationUnits()); + } + }), + switchMapTo(this.store), + select(getOrganisationUnits), + filter((organisationUnits) => organisationUnits !== null), + take(1), + map((organisationUnits) => { + if (organisationUnits) { + const filterBy = this.filterBy || (() => true); + const items = this.placeholder + ? [this.placeholder, ...organisationUnits] + : organisationUnits; + + return items.filter((item) => { + const matchesQuery = + filterBy(item) && item.oucodeL3Name.toLowerCase().includes(q); + if (this.jurisdictionCode) { + return this.jurisdictionCode === item.oucodeL1Code && matchesQuery; + } + return matchesQuery; + }); + } + return []; + }), + map((organisationUnits) => organisationUnits.slice(0, Math.max(this.maxResults, 10))) + ); + } + return of([]); + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.dispatch(loadOrganisationUnits()); + } + } + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.autosuggestLiteRef.propagateChange(fn); + }; + + registerOnChange(fn: (_: any) => void): void { + this.autosuggestLiteRef.registerOnChange(fn); + } + + registerOnTouched(fn: any) { + this.autosuggestLiteRef.registerOnTouched(fn); + } + + writeValue(value?: OrganisationUnit) { + this.autosuggestLiteRef.writeValue(value); + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } + + // FormFieldControl forwarding + + get controlType() { + return this.autosuggestLiteRef.controlType; + } + + get multi() { + if (this.autosuggestLiteRef) { + return this.autosuggestLiteRef.multi; + } + + return false; + } + + get ngControl() { + return this.autosuggestLiteRef.ngControl; + } + + get controlRef() { + return this.autosuggestLiteRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/organisation-with-type.autosuggest.ts b/projects/reference-data/src/components/organisation-with-type.autosuggest.ts new file mode 100644 index 0000000..644e070 --- /dev/null +++ b/projects/reference-data/src/components/organisation-with-type.autosuggest.ts @@ -0,0 +1,195 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { PdkAutosuggestLiteComponent, FormFieldControl, InputWidth } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable, of, Subject } from 'rxjs'; +import { delay, filter, map, startWith, switchMap, switchMapTo, take, tap } from 'rxjs/operators'; +import { loadOrganisationsWithType } from '../actions/reference-data.actions'; +import { + getOrganisationsWithType, + getOrganisationsWithTypeNeedsFetching, + ReferenceDataState +} from '../reducers/index'; +import { + OrganisationType, + OrganisationWithType, + OrganisationWithTypeAddress +} from '../reference-data.interfaces'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'cpp-organisation-with-type-autosuggest', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => OrganisationWithTypeAutosuggestComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => OrganisationWithTypeAutosuggestComponent) + } + ], + imports: [PdkAutosuggestLiteComponent, AsyncPipe] +}) +export class OrganisationWithTypeAutosuggestComponent + implements OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() ariaLabel: string | null = null; + @Input() ariaLabelledBy: string | null = null; + @Input() fetchOptionsOnMount = false; + @Input() debounceTime = 250; + @Input() filterBy?: (organisationWithType: OrganisationWithType) => boolean; + @Input() hasError = false; + @Input() highlightFirstSuggestion?: boolean; + @Input() highlightMatchedText = true; + @Input() id!: string; + @Input() inputWidth?: InputWidth; + @Input() maxResults = 6; + @Input() placeholder?: OrganisationWithType; + @Input() orgType!: OrganisationType; + @Output() error = new EventEmitter(); + + @ViewChild(PdkAutosuggestLiteComponent, { static: true }) + autosuggestLiteRef!: PdkAutosuggestLiteComponent; + + search$ = new Subject(); + suggestions$: Observable; + suggestionKey: keyof OrganisationWithType = 'id'; + suggestionTitle: keyof OrganisationWithType = 'orgName'; + disabled = false; + addresses: (keyof OrganisationWithTypeAddress)[] = [ + 'address1', + 'address2', + 'address3', + 'address4', + 'address5', + 'postcode' + ]; + mapSuggestionToSubtitle = (suggestion: OrganisationWithType) => + this.addresses + .filter((field) => !!suggestion[field]) + .map((existingField) => suggestion[existingField]?.trim()) + .join(', '); + + constructor(private store: Store) { + this.suggestions$ = this.search$.pipe( + delay(this.debounceTime), + map((q) => q.toLowerCase()), + switchMap((q) => { + if (q.length !== 0) { + return this.store.pipe( + select(getOrganisationsWithTypeNeedsFetching), + take(1), + tap((needsFetching) => { + if (needsFetching && !!this.orgType) { + this.store.dispatch(loadOrganisationsWithType({ organisationType: this.orgType })); + } + }), + switchMapTo(this.store), + select(getOrganisationsWithType), + filter((organisationsWithType) => organisationsWithType !== null), + take(1), + map((organisationsWithType) => { + if (!organisationsWithType || organisationsWithType.length === 0) { + return []; + } + + const filterBy = this.filterBy || (() => true); + const items = this.placeholder + ? [this.placeholder, ...organisationsWithType] + : organisationsWithType; + + return items.filter( + (item) => filterBy(item) && item.orgName.toLowerCase().includes(q) + ); + }), + map((organisationsWithType) => + organisationsWithType.slice(0, Math.max(this.maxResults, 10)) + ) + ); + } + return of([]); + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount && !!this.orgType) { + this.store.dispatch(loadOrganisationsWithType({ organisationType: this.orgType })); + } + } + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.autosuggestLiteRef.propagateChange(fn); + }; + + registerOnChange(fn: (_: any) => void): void { + this.autosuggestLiteRef.registerOnChange(fn); + } + + registerOnTouched(fn: any) { + this.autosuggestLiteRef.registerOnTouched(fn); + } + + writeValue(value?: OrganisationWithType) { + this.autosuggestLiteRef.writeValue(value); + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } + + // FormFieldControl forwarding + + get controlType() { + return this.autosuggestLiteRef.controlType; + } + + get multi() { + if (this.autosuggestLiteRef) { + return this.autosuggestLiteRef.multi; + } + + return false; + } + + get ngControl() { + return this.autosuggestLiteRef.ngControl; + } + + get controlRef() { + return this.autosuggestLiteRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/police-force.autosuggest.ts b/projects/reference-data/src/components/police-force.autosuggest.ts new file mode 100644 index 0000000..4c5a46e --- /dev/null +++ b/projects/reference-data/src/components/police-force.autosuggest.ts @@ -0,0 +1,156 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { PdkAutosuggestLiteComponent, FormFieldControl, InputWidth } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable, of, Subject } from 'rxjs'; +import { filter, map, startWith, switchMap, switchMapTo, take, tap } from 'rxjs/operators'; +import { loadPoliceForceList } from '../actions/reference-data.actions'; +import { getPoliceForceList, getPoliceForceFetching, ReferenceDataState } from '../reducers/index'; +import { PoliceForce } from '../reference-data.interfaces'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'police-force-autosuggest', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => PoliceForceAutosuggestComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => PoliceForceAutosuggestComponent) + } + ], + imports: [PdkAutosuggestLiteComponent, AsyncPipe] +}) +export class PoliceForceAutosuggestComponent + implements OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() ariaLabel: string | null = null; + @Input() ariaLabelledBy: string | null = null; + @Input() fetchOptionsOnMount = false; + @Input() hasError = false; + @Input() highlightFirstSuggestion?: boolean; + @Input() highlightMatchedText = true; + @Input() id!: string; + @Input() inputWidth?: InputWidth; + @Input() maxResults = 6; + @Output() error = new EventEmitter(); + + @ViewChild(PdkAutosuggestLiteComponent, { static: true }) + autosuggestLiteRef!: PdkAutosuggestLiteComponent; + + fetching$: Observable; + search$ = new Subject(); + suggestions$: Observable; + suggestionKey: keyof PoliceForce = 'id'; + suggestionTitle: keyof PoliceForce = 'policeForceName'; + + constructor(private store: Store) { + this.fetching$ = this.store.pipe(select(getPoliceForceFetching)); + + this.suggestions$ = this.search$.pipe( + switchMap((q) => { + if (q.length !== 0) { + return this.store.pipe( + select(getPoliceForceList), + take(1), + tap((policeForceList) => { + if (policeForceList === undefined) { + this.store.dispatch(loadPoliceForceList()); + } + }), + switchMapTo(this.store), + select(getPoliceForceList), + filter((policeForceList) => policeForceList !== null), + take(1), + map((policeForceList) => { + if (policeForceList) { + const term = q.toLowerCase(); + + return policeForceList.filter( + ({ policeForceCode, policeForceName }) => + policeForceCode.toLowerCase().includes(term) || + policeForceName.toLowerCase().includes(term) + ); + } + return []; + }), + map((policeForceList) => policeForceList.slice(0, Math.max(this.maxResults, 10))) + ); + } + return of([]); + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.dispatch(loadPoliceForceList()); + } + } + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.autosuggestLiteRef.propagateChange(fn); + }; + + registerOnChange(fn: (_: any) => void): void { + this.autosuggestLiteRef.registerOnChange(fn); + } + + registerOnTouched(fn: any) { + this.autosuggestLiteRef.registerOnTouched(fn); + } + + writeValue(value?: T) { + this.autosuggestLiteRef.writeValue(value); + } + + // FormFieldControl forwarding + + get controlType() { + return this.autosuggestLiteRef.controlType; + } + + get multi() { + return this.autosuggestLiteRef.multi; + } + + get ngControl() { + return this.autosuggestLiteRef.ngControl; + } + + get controlRef() { + return this.autosuggestLiteRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/police-ranks.select.ts b/projects/reference-data/src/components/police-ranks.select.ts new file mode 100644 index 0000000..768b317 --- /dev/null +++ b/projects/reference-data/src/components/police-ranks.select.ts @@ -0,0 +1,138 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { FormFieldControl, SelectChangeEvent, PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { map, startWith, take } from 'rxjs/operators'; +import { loadPoliceRanks } from '../actions/reference-data.actions'; +import { getPoliceRanks, ReferenceDataState } from '../reducers/index'; +import { PoliceRank } from '../reference-data.interfaces'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'cpp-police-ranks-select', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => PoliceRanksSelectComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => PoliceRanksSelectComponent) + } + ], + imports: [PdkSelectComponent, AsyncPipe] +}) +export class PoliceRanksSelectComponent implements OnInit, ControlValueAccessor, FormFieldControl { + @Input() ariaDescribedBy: string | null = null; + @Input() disabled?: boolean; + @Input() fetchOptionsOnMount = true; + @Input() id!: string; + @Input() justified?: boolean; + @Input() name!: string; + @Input() placeholder?: string; + @Input() required?: boolean; + @Output() change = new EventEmitter(); + + @ViewChild(PdkSelectComponent, { static: true }) selectRef!: PdkSelectComponent; + + options$: Observable; + + constructor(private store: Store) { + this.options$ = this.store.pipe( + select(getPoliceRanks), + map((policeRanks) => { + if (policeRanks) { + return policeRanks.map((policeRank) => ({ + value: policeRank.rankCode, + label: policeRank.rankDescription + })); + } + return []; + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.pipe(select(getPoliceRanks), take(1)).subscribe((policeRanks) => { + if (!policeRanks.length) { + this.store.dispatch(loadPoliceRanks()); + } + }); + } + } + + registerOnChange = (fn: (_: any) => void): void => { + this.selectRef.registerOnChange((code?: string) => { + this.store + .pipe( + select(getPoliceRanks), + take(1), + map((policeRanks) => { + if (policeRanks) { + return policeRanks.find(({ rankCode }) => rankCode === code); + } + return undefined; + }) + ) + .subscribe(fn); + }); + }; + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.selectRef.propagateChange(fn); + }; + + registerOnTouched(fn: any) { + this.selectRef.registerOnTouched(fn); + } + + writeValue(value?: PoliceRank) { + this.selectRef.writeValue(value ? value.rankCode : undefined); + } + + // FormFieldControl forwarding + + get controlType() { + return this.selectRef.controlType; + } + + get multi() { + return this.selectRef.multi; + } + + get ngControl() { + return this.selectRef.ngControl; + } + + get controlRef() { + return this.selectRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/prosecutor.autosuggest.ts b/projects/reference-data/src/components/prosecutor.autosuggest.ts new file mode 100644 index 0000000..516ed71 --- /dev/null +++ b/projects/reference-data/src/components/prosecutor.autosuggest.ts @@ -0,0 +1,173 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { PdkAutosuggestLiteComponent, FormFieldControl, InputWidth } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { Observable, of, Subject } from 'rxjs'; +import { filter, map, startWith, switchMap, switchMapTo, take, tap } from 'rxjs/operators'; +import { loadProsecutors } from '../actions/reference-data.actions'; +import { getProsecutors, getProsecutorsFetching, ReferenceDataState } from '../reducers/index'; +import { Prosecutor } from '../reference-data.interfaces'; +import { AsyncPipe } from '@angular/common'; + +@Component({ + selector: 'cpp-prosecutor-autosuggest', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ProsecutorAutosuggestComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => ProsecutorAutosuggestComponent) + } + ], + imports: [PdkAutosuggestLiteComponent, AsyncPipe] +}) +export class ProsecutorAutosuggestComponent + implements OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() ariaLabel: string | null = null; + @Input() ariaLabelledBy: string | null = null; + @Input() fetchOptionsOnMount = false; + @Input() filterBy?: (prosecutor: Prosecutor) => boolean; + @Input() disabled = false; + @Input() hasError = false; + @Input() highlightFirstSuggestion?: boolean; + @Input() highlightMatchedText = true; + @Input() id!: string; + @Input() inputWidth?: InputWidth; + @Input() maxResults = 6; + @Output() error = new EventEmitter(); + @Output() inputText = new EventEmitter(); + + @ViewChild(PdkAutosuggestLiteComponent, { static: true }) + autosuggestLiteRef!: PdkAutosuggestLiteComponent; + + fetching$: Observable; + search$ = new Subject(); + suggestions$: Observable; + suggestionKey: keyof Prosecutor = 'id'; + suggestionTitle: keyof Prosecutor = 'fullName'; + + mapSuggestionToTitle = (suggestion: Prosecutor) => { + if (!suggestion.standard) { + const { fullName, address } = suggestion; + if (address) { + const { address1, postcode } = address; + return `${fullName}, ${address1}, ${postcode}`; + } + } + + return suggestion.fullName; + }; + + constructor(private store: Store) { + this.fetching$ = this.store.pipe(select(getProsecutorsFetching)); + + this.suggestions$ = this.search$.pipe( + tap((q) => this.inputText.next(q)), + map((q) => q.toLowerCase()), + switchMap((q) => { + if (q.length !== 0) { + return this.store.pipe( + select(getProsecutors), + take(1), + tap((fetching) => { + if (!fetching) { + this.store.dispatch(loadProsecutors()); + } + }), + switchMapTo(this.store), + select(getProsecutors), + filter((prosecutors) => prosecutors !== null), + take(1), + map((prosecutors) => { + if (prosecutors) { + const filterBy = this.filterBy || (() => true); + return prosecutors.filter( + (prosecutor) => + filterBy(prosecutor) && prosecutor.fullName.toLowerCase().includes(q) + ); + } + return []; + }), + map((prosecutors) => prosecutors.slice(0, Math.max(this.maxResults, 10))) + ); + } + return of([]); + }), + startWith([]) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.dispatch(loadProsecutors()); + } + } + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.autosuggestLiteRef.propagateChange(fn); + }; + + registerOnChange(fn: (_: any) => void): void { + this.autosuggestLiteRef.registerOnChange(fn); + } + + registerOnTouched(fn: any) { + this.autosuggestLiteRef.registerOnTouched(fn); + } + + writeValue(value?: Prosecutor) { + this.autosuggestLiteRef.writeValue(value); + } + + // FormFieldControl forwarding + + get controlType() { + return this.autosuggestLiteRef.controlType; + } + + get multi() { + return this.autosuggestLiteRef.multi; + } + + get ngControl() { + return this.autosuggestLiteRef.ngControl; + } + + get controlRef() { + return this.autosuggestLiteRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/rota-business-types.select.ts b/projects/reference-data/src/components/rota-business-types.select.ts new file mode 100644 index 0000000..62f351c --- /dev/null +++ b/projects/reference-data/src/components/rota-business-types.select.ts @@ -0,0 +1,161 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { + FormFieldControl, + SelectChangeEvent, + PdkSelectComponent, + SelectInputWidth, + SelectOption +} from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { filter, map, startWith, switchMap, take } from 'rxjs/operators'; +import { loadRotaBusinessTypes } from '../actions/reference-data.actions'; +import { + getRotaBusinessTypesByJurisdiction, + getRotaBusinessTypesFetching, + ReferenceDataState +} from '../reducers/index'; +import { AsyncPipe, CommonModule } from '@angular/common'; +import { RotaBusinessType, RotaBusinessTypeJurisdiction } from '../reference-data.interfaces'; +import { sortSelectOptionAlphabetical } from '../utils/sort-select-options-Alphabetical'; + +@Component({ + selector: 'cpp-rota-business-type-select', + template: ` + + + `, + imports: [PdkSelectComponent, AsyncPipe], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => RotaBusinessTypeSelectComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => RotaBusinessTypeSelectComponent) + } + ] +}) +export class RotaBusinessTypeSelectComponent + implements OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() disabled?: boolean; + @Input() fetchOptionsOnMount = false; + @Input() id!: string; + @Input() justified?: boolean; + @Input() name!: string; + @Input() placeholder?: string; + @Input() required?: boolean; + @Input() inputWidth?: SelectInputWidth; + @Input() set filterBy(fn: () => boolean) { + this._filterBy = fn; + this._buildOptions$.next(); + } + @Input() jurisdiction: RotaBusinessTypeJurisdiction | 'ALL' = 'MAGISTRATES'; + @Output() change = new EventEmitter(); + + @ViewChild(PdkSelectComponent, { static: true }) selectRef!: PdkSelectComponent; + + options$: Observable; + private _filterBy: (businessType: RotaBusinessType) => boolean = () => true; + + // This is neccessary as filters change in some contexts + //depending on user input or radio button selection - not necessarily conditional + private _buildOptions$ = new BehaviorSubject(undefined); + + constructor(private store: Store) { + this.options$ = this._buildOptions$.pipe( + switchMap(() => + this.store.pipe( + select(getRotaBusinessTypesByJurisdiction(this.jurisdiction)), + filter((businessTypes) => businessTypes !== null || businessTypes !== undefined), + take(1), + map((businessTypes) => + businessTypes.filter((businessType) => this._filterBy(businessType)) + ), + map((businessTypes) => { + if (businessTypes) { + return businessTypes + .map(({ typeCode, typeDescription }) => ({ + value: typeCode, + label: typeDescription + })) + .sort(sortSelectOptionAlphabetical); + } + return []; + }), + startWith([]) + ) + ) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.pipe(select(getRotaBusinessTypesFetching), take(1)).subscribe((needsFetching) => { + if (needsFetching) { + this.store.dispatch(loadRotaBusinessTypes()); + } + }); + } + } + + registerOnChange = (fn: (_: any) => void): void => { + this.selectRef.registerOnChange(fn); + }; + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.selectRef.propagateChange(fn); + }; + + registerOnTouched(fn: any) { + this.selectRef.registerOnTouched(fn); + } + + writeValue(value?: string) { + this.selectRef.writeValue(value ? value : undefined); + } + + // FormFieldControl forwarding + + get controlType() { + return this.selectRef.controlType; + } + + get multi() { + return this.selectRef.multi; + } + + get ngControl() { + return this.selectRef.ngControl; + } + + get controlRef() { + return this.selectRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/special-requirements.checkbox.ts b/projects/reference-data/src/components/special-requirements.checkbox.ts new file mode 100644 index 0000000..ae13f10 --- /dev/null +++ b/projects/reference-data/src/components/special-requirements.checkbox.ts @@ -0,0 +1,142 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { + CheckboxOption, + FormFieldControl, + PdkCheckboxGroupComponent, + CheckboxChangeEvent, + PdkPaddingDirective +} from '@cpp/pdk'; +import { getSpecialRequirements, ReferenceDataState } from '../reducers'; +import { select, Store } from '@ngrx/store'; +import { map, take } from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { loadSpecialRequirements } from '../actions/reference-data.actions'; +import { sortBy } from 'lodash-es'; +import { AsyncPipe } from '@angular/common'; +@Component({ + selector: 'special-requirements-chekbox', + template: ` + + + `, + styles: [ + ` + pdk-checkbox-group::-webkit-scrollbar { + -webkit-appearance: none; + width: 7px; + } + pdk-checkbox-group::-webkit-scrollbar-thumb { + border-radius: 4px; + background-color: rgba(0, 0, 0, 0.5); + -webkit-box-shadow: 0 0 1px rgba(255, 255, 255, 0.5); + } + pdk-checkbox-group { + border: 1px solid #eaeaea; + height: 200px; + overflow-y: scroll; + display: block; + } + ` + ], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => SpecialRequirementCheckboxComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => SpecialRequirementCheckboxComponent) + } + ], + imports: [PdkCheckboxGroupComponent, AsyncPipe, PdkPaddingDirective] +}) +export class SpecialRequirementCheckboxComponent + implements ControlValueAccessor, FormFieldControl, OnInit +{ + @Input() id!: string; + @Input() disabled = false; + @Input() ariaDescribedBy!: string; + @Input() fetchOptionsOnMount = true; + @Output() change = new EventEmitter>(); + @ViewChild(PdkCheckboxGroupComponent, { static: true }) + checkboxGroupRef!: PdkCheckboxGroupComponent; + + options$: Observable[]>; + + constructor(private store: Store) { + this.options$ = this.store.pipe( + select(getSpecialRequirements), + map((specialRequirements) => { + if (specialRequirements) { + const sortedItems = sortBy(specialRequirements, (s) => s.requirementValue); + return sortedItems.map((specialRequirement) => ({ + value: specialRequirement.requirementCode, + label: specialRequirement.requirementValue + })); + } + return []; + }) + ); + } + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.pipe(select(getSpecialRequirements), take(1)).subscribe((specialRequirements) => { + if (!specialRequirements) { + this.store.dispatch(loadSpecialRequirements()); + } + }); + } + } + + registerOnChange = (fn: (_: any) => void): void => { + this.checkboxGroupRef.registerOnChange(fn); + }; + + // ControlValueAccessor forwarding + propagateChange: (_: any) => void = (fn: any) => { + this.checkboxGroupRef.propagateChange(fn); + }; + + registerOnTouched(fn: any) { + this.checkboxGroupRef.registerOnTouched(fn); + } + + writeValue(values?: string[]) { + this.checkboxGroupRef.writeValue(values ? values : []); + } + + // FormFieldControl forwarding + get controlType() { + return this.checkboxGroupRef.controlType; + } + + get multi() { + return this.checkboxGroupRef.multi; + } + + get ngControl() { + return this.checkboxGroupRef.ngControl; + } + + get controlRef() { + return this.checkboxGroupRef.controlRef; + } +} diff --git a/projects/reference-data/src/components/witness-care-unit.select.ts b/projects/reference-data/src/components/witness-care-unit.select.ts new file mode 100644 index 0000000..ab25978 --- /dev/null +++ b/projects/reference-data/src/components/witness-care-unit.select.ts @@ -0,0 +1,152 @@ +import { + Component, + EventEmitter, + forwardRef, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { FormFieldControl, SelectChangeEvent, PdkSelectComponent, SelectOption } from '@cpp/pdk'; +import { select, Store } from '@ngrx/store'; +import { map, take } from 'rxjs/operators'; +import { loadWitnessCareUnits } from '../actions/reference-data.actions'; +import { getWitnessCareUnits, ReferenceDataState } from '../reducers/index'; +import { WitnessCareUnit } from '../reference-data.interfaces'; + +@Component({ + selector: 'witness-care-unit-select', + template: ` + + + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => WitnessCareUnitSelectComponent), + multi: true + }, + { + provide: FormFieldControl, + useExisting: forwardRef(() => WitnessCareUnitSelectComponent) + } + ], + imports: [PdkSelectComponent] +}) +export class WitnessCareUnitSelectComponent + implements OnChanges, OnInit, ControlValueAccessor, FormFieldControl +{ + @Input() ariaDescribedBy: string | null = null; + @Input() policeForceCode?: string; + @Input() disabled?: boolean; + @Input() fetchOptionsOnMount = true; + @Input() id!: string; + @Input() justified?: boolean; + @Input() name!: string; + @Input() placeholder?: string; + @Input() required?: boolean; + @Output() change = new EventEmitter(); + + @ViewChild(PdkSelectComponent, { static: true }) selectRef!: PdkSelectComponent; + + options: SelectOption[] = []; + + ngOnChanges(changes: SimpleChanges) { + if (changes.policeForceCode) { + if (!changes.policeForceCode.firstChange) { + this.ngControl.reset(); + } + this.store + .select(getWitnessCareUnits) + .pipe(take(1)) + .subscribe((witnessCareUnits) => { + this.options = changes.policeForceCode.currentValue + ? (witnessCareUnits || []) + .filter( + ({ policeForceCode }) => + policeForceCode && + policeForceCode.toString() === changes.policeForceCode.currentValue + ) + .map((witnessCareUnit) => ({ + value: witnessCareUnit.id, + label: witnessCareUnit.wcuName + })) + : []; + }); + } + } + + constructor(private store: Store) {} + + ngOnInit() { + if (this.fetchOptionsOnMount) { + this.store.pipe(select(getWitnessCareUnits), take(1)).subscribe((witnessCareUnits) => { + if (!witnessCareUnits) { + this.store.dispatch(loadWitnessCareUnits()); + } + }); + } + } + + registerOnChange = (fn: (_: any) => void): void => { + this.selectRef.registerOnChange((wcuId?: string) => { + this.store + .pipe( + select(getWitnessCareUnits), + take(1), + map((witnessCareUnits) => { + if (witnessCareUnits) { + return witnessCareUnits.find(({ id }) => id === wcuId); + } + return undefined; + }) + ) + .subscribe(fn); + }); + }; + + // ControlValueAccessor forwarding + + propagateChange: (_: any) => void = (fn: any) => { + this.selectRef.propagateChange(fn); + }; + + registerOnTouched(fn: any) { + this.selectRef.registerOnTouched(fn); + } + + writeValue(value?: WitnessCareUnit) { + this.selectRef.writeValue(value ? value.id : undefined); + } + + // FormFieldControl forwarding + + get controlType() { + return this.selectRef.controlType; + } + + get multi() { + return this.selectRef.multi; + } + + get ngControl() { + return this.selectRef.ngControl; + } + + get controlRef() { + return this.selectRef.controlRef; + } +} diff --git a/projects/reference-data/src/effects/__tests__/reference-data.effects.spec.ts b/projects/reference-data/src/effects/__tests__/reference-data.effects.spec.ts new file mode 100644 index 0000000..051fa74 --- /dev/null +++ b/projects/reference-data/src/effects/__tests__/reference-data.effects.spec.ts @@ -0,0 +1,1413 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { provideMockActions } from '@ngrx/effects/testing'; +import { Store, StoreModule } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { marbles } from 'rxjs-marbles/jest'; +import { ReferenceDataActions } from '../../actions'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { ReferenceDataEffects } from '../reference-data.effects'; +import { FixedList, OrganisationType } from '../../reference-data.interfaces'; + +describe('ReferenceDataEffects', () => { + let actions$: Observable; + let effects: ReferenceDataEffects; + let fetchApplicationTypes: jest.Mock; + let fetchAssignPriorities: jest.Mock; + let fetchBookingTypes: jest.Mock; + let fetchClusters: jest.Mock; + let fetchCPSAreas: jest.Mock; + let fetchCPSBusinessUnits: jest.Mock; + let fetchCPSCaseStatuses: jest.Mock; + let fetchFixedLists: jest.Mock; + let fetchHearingTypes: jest.Mock; + let fetchOrganisationUnits: jest.Mock; + let fetchPoliceForceList: jest.Mock; + let fetchProsecutors: jest.Mock; + let fetchPleaTypes: jest.Mock; + let fetchWitnessCareUnits: jest.Mock; + let fetchTrialTypes: jest.Mock; + let fetchPoliceRanks: jest.Mock; + let fetchPublicHolidays: jest.Mock; + let fetchOrganisationsWithType: jest.Mock; + let fetchRotaBusinessTypes: jest.Mock; + + let store: Store; + + beforeEach(() => { + fetchApplicationTypes = jest.fn(); + fetchAssignPriorities = jest.fn(); + fetchBookingTypes = jest.fn(); + fetchClusters = jest.fn(); + fetchCPSAreas = jest.fn(); + fetchCPSBusinessUnits = jest.fn(); + fetchCPSCaseStatuses = jest.fn(); + fetchFixedLists = jest.fn(); + fetchHearingTypes = jest.fn(); + fetchOrganisationUnits = jest.fn(); + fetchPoliceForceList = jest.fn(); + fetchProsecutors = jest.fn(); + fetchPleaTypes = jest.fn(); + fetchWitnessCareUnits = jest.fn(); + fetchTrialTypes = jest.fn(); + fetchPoliceRanks = jest.fn(); + fetchPublicHolidays = jest.fn(); + fetchOrganisationsWithType = jest.fn(); + fetchRotaBusinessTypes = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + ReferenceDataEffects, + { + provide: ReferenceDataService, + useValue: { + fetchApplicationTypes, + fetchAssignPriorities, + fetchBookingTypes, + fetchClusters, + fetchCPSAreas, + fetchCPSBusinessUnits, + fetchCPSCaseStatuses, + fetchFixedLists, + fetchHearingTypes, + fetchOrganisationUnits, + fetchPleaTypes, + fetchPoliceForceList, + fetchProsecutors, + fetchWitnessCareUnits, + fetchTrialTypes, + fetchPoliceRanks, + fetchPublicHolidays, + fetchOrganisationsWithType, + fetchRotaBusinessTypes + } + }, + provideMockActions(() => actions$) + ] + }); + + effects = TestBed.inject(ReferenceDataEffects); + store = TestBed.inject(Store); + }); + + describe('fetchApplicationTypes$', () => { + it( + 'should fetch the application types from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadApplicationTypes(); + const successAction = ReferenceDataActions.loadApplicationTypesSuccess({ + applicationTypes: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchApplicationTypes.mockReturnValue(response$); + + m.expect(effects.fetchApplicationTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any further actions while fetching the application types is in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadApplicationTypes(); + const successAction = ReferenceDataActions.loadApplicationTypesSuccess({ + applicationTypes: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchApplicationTypes.mockReturnValue(response$); + + m.expect(effects.fetchApplicationTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the application types are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadApplicationTypesSuccess({ + applicationTypes: [] + }); + + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchApplicationTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the application types fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadApplicationTypes(); + const errorAction = ReferenceDataActions.loadApplicationTypesError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchApplicationTypes.mockReturnValue(response$); + + m.expect(effects.fetchApplicationTypes$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchAssignPriorities$', () => { + it( + 'should fetch the assign priorities from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadAssignPriorities(); + const successAction = ReferenceDataActions.loadAssignPrioritiesSuccess({ + assignPriorities: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchAssignPriorities.mockReturnValue(response$); + + m.expect(effects.fetchAssignPriorities$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any further actions while fetching the assign priorities is in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadAssignPriorities(); + const successAction = ReferenceDataActions.loadAssignPrioritiesSuccess({ + assignPriorities: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchAssignPriorities.mockReturnValue(response$); + + m.expect(effects.fetchAssignPriorities$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the assign priorities are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadAssignPrioritiesSuccess({ + assignPriorities: [] + }); + + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchAssignPriorities$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the assign priorities fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadAssignPriorities(); + const errorAction = ReferenceDataActions.loadAssignPrioritiesError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchAssignPriorities.mockReturnValue(response$); + + m.expect(effects.fetchAssignPriorities$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchBookingTypes$', () => { + it( + 'should fetch the booking types from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadBookingTypes(); + const successAction = ReferenceDataActions.loadBookingTypesSuccess({ + bookingTypes: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchBookingTypes.mockReturnValue(response$); + + m.expect(effects.fetchBookingTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any further actions while fetching the booking types is in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadBookingTypes(); + const successAction = ReferenceDataActions.loadBookingTypesSuccess({ + bookingTypes: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchBookingTypes.mockReturnValue(response$); + + m.expect(effects.fetchBookingTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the booking types are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadBookingTypesSuccess({ + bookingTypes: [] + }); + + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchBookingTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the booking types fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadBookingTypes(); + const errorAction = ReferenceDataActions.loadBookingTypesError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchBookingTypes.mockReturnValue(response$); + + m.expect(effects.fetchBookingTypes$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchClusters$', () => { + it( + 'should fetch the clusters from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadClusters(); + const successAction = ReferenceDataActions.loadClustersSuccess({ + clusters: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchClusters.mockReturnValue(response$); + + m.expect(effects.fetchClusters$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any further actions while fetching the clusters is in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadClusters(); + const successAction = ReferenceDataActions.loadClustersSuccess({ + clusters: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchClusters.mockReturnValue(response$); + + m.expect(effects.fetchClusters$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the clusters are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadClustersSuccess({ + clusters: [] + }); + + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchClusters$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the clusters fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadClusters(); + const errorAction = ReferenceDataActions.loadClustersError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchClusters.mockReturnValue(response$); + + m.expect(effects.fetchClusters$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchCPSAreas$', () => { + it( + 'should fetch the cps Areas from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadCPSAreas(); + const successAction = ReferenceDataActions.loadCPSAreasSuccess({ + cpsAreas: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchCPSAreas.mockReturnValue(response$); + + m.expect(effects.fetchCPSAreas$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the cps Areas is in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadCPSAreas(); + const successAction = ReferenceDataActions.loadCPSAreasSuccess({ + cpsAreas: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchCPSAreas.mockReturnValue(response$); + + m.expect(effects.fetchCPSAreas$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the cps Areas are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadCPSAreasSuccess({ + cpsAreas: [] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchCPSAreas$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the cps Areas fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadCPSAreas(); + const errorAction = ReferenceDataActions.loadCPSAreasError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchCPSAreas.mockReturnValue(response$); + + m.expect(effects.fetchCPSAreas$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchCPSBusinessUnits$', () => { + it( + 'should fetch the cps business units from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadCPSBusinessUnits(); + const successAction = ReferenceDataActions.loadCPSBusinessUnitsSuccess({ + cpsBusinessUnits: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchCPSBusinessUnits.mockReturnValue(response$); + + m.expect(effects.fetchCPSBusinessUnits$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the cps business units is in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadCPSBusinessUnits(); + const successAction = ReferenceDataActions.loadCPSBusinessUnitsSuccess({ + cpsBusinessUnits: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchCPSBusinessUnits.mockReturnValue(response$); + + m.expect(effects.fetchCPSBusinessUnits$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the cps business units are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadCPSBusinessUnitsSuccess({ + cpsBusinessUnits: [] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchCPSBusinessUnits$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the cps business units fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadCPSBusinessUnits(); + const errorAction = ReferenceDataActions.loadCPSBusinessUnitsError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchCPSBusinessUnits.mockReturnValue(response$); + + m.expect(effects.fetchCPSBusinessUnits$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchCPSCaseStatuses$', () => { + it( + 'should fetch the cps case statuses from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadCPSCaseStatuses(); + const successAction = ReferenceDataActions.loadCPSCaseStatusesSuccess({ + cpsCaseStatuses: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchCPSCaseStatuses.mockReturnValue(response$); + + m.expect(effects.fetchCPSCaseStatuses$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the cps case statuses is in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadCPSCaseStatuses(); + const successAction = ReferenceDataActions.loadCPSCaseStatusesSuccess({ + cpsCaseStatuses: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchCPSCaseStatuses.mockReturnValue(response$); + + m.expect(effects.fetchCPSCaseStatuses$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the cps case statuses are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadCPSCaseStatusesSuccess({ + cpsCaseStatuses: [] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchCPSCaseStatuses$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the cps case statuses fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadCPSCaseStatuses(); + const errorAction = ReferenceDataActions.loadCPSCaseStatusesError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchCPSCaseStatuses.mockReturnValue(response$); + + m.expect(effects.fetchCPSCaseStatuses$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchFixedLists$', () => { + it( + 'should fetch the fixed lists from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadFixedLists(); + const successAction = ReferenceDataActions.loadFixedListsSuccess({ + fixedLists: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchFixedLists.mockReturnValue(response$); + + m.expect(effects.fetchFixedLists$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any further actions while fetching the fixed lists is in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadFixedLists(); + const successAction = ReferenceDataActions.loadFixedListsSuccess({ + fixedLists: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchFixedLists.mockReturnValue(response$); + + m.expect(effects.fetchFixedLists$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the fixed lists are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadFixedListsSuccess({ + fixedLists: [{ id: '*' } as FixedList] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchFixedLists$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the fixed lists fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadFixedLists(); + const errorAction = ReferenceDataActions.loadFixedListsError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchFixedLists.mockReturnValue(response$); + + m.expect(effects.fetchFixedLists$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchHearingTypes$', () => { + it( + 'should fetch the hearing types from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadHearingTypes(); + const successAction = ReferenceDataActions.loadHearingTypesSuccess({ + hearingTypes: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchHearingTypes.mockReturnValue(response$); + + m.expect(effects.fetchHearingTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the hearing types is in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadHearingTypes(); + const successAction = ReferenceDataActions.loadHearingTypesSuccess({ + hearingTypes: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchHearingTypes.mockReturnValue(response$); + + m.expect(effects.fetchHearingTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the hearing types are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadHearingTypesSuccess({ + hearingTypes: [] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchHearingTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the hearing types fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadHearingTypes(); + const errorAction = ReferenceDataActions.loadHearingTypesError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchHearingTypes.mockReturnValue(response$); + + m.expect(effects.fetchHearingTypes$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchOrganisationUnits$', () => { + it( + 'should fetch the court centres from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadOrganisationUnits(); + const successAction = ReferenceDataActions.loadOrganisationUnitsSuccess({ + organisationUnits: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchOrganisationUnits.mockReturnValue(response$); + + m.expect(effects.fetchOrganisationUnits$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the court centres is already in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadOrganisationUnits(); + const successAction = ReferenceDataActions.loadOrganisationUnitsSuccess({ + organisationUnits: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchOrganisationUnits.mockReturnValue(response$); + + m.expect(effects.fetchOrganisationUnits$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the court centres are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadOrganisationUnitsSuccess({ + organisationUnits: [] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchOrganisationUnits$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the court centres fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadOrganisationUnits(); + const errorAction = ReferenceDataActions.loadOrganisationUnitsError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchOrganisationUnits.mockReturnValue(response$); + + m.expect(effects.fetchOrganisationUnits$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchPoliceForceList$', () => { + it( + 'should fetch the policeForceList from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadPoliceForceList(); + const successAction = ReferenceDataActions.loadPoliceForceListSuccess({ + policeForceList: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchPoliceForceList.mockReturnValue(response$); + + m.expect(effects.fetchPoliceForceList$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the policeForceList is already in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadPoliceForceList(); + const successAction = ReferenceDataActions.loadPoliceForceListSuccess({ + policeForceList: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchPoliceForceList.mockReturnValue(response$); + + m.expect(effects.fetchPoliceForceList$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the policeForceList are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadPoliceForceListSuccess({ + policeForceList: [] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchPoliceForceList$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the policeForceList fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadPoliceForceList(); + const errorAction = ReferenceDataActions.loadPoliceForceListError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchPoliceForceList.mockReturnValue(response$); + + m.expect(effects.fetchPoliceForceList$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchProsecutors$', () => { + it( + 'should fetch the prosecutors from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadProsecutors(); + const successAction = ReferenceDataActions.loadProsecutorsSuccess({ + prosecutors: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchProsecutors.mockReturnValue(response$); + + m.expect(effects.fetchProsecutors$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the prosecutors is already in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadOrganisationUnits(); + + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchProsecutors$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the prosecutors are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadOrganisationUnitsSuccess({ + organisationUnits: [] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchProsecutors$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the prosecutors fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadProsecutors(); + const errorAction = ReferenceDataActions.loadProsecutorsError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchProsecutors.mockReturnValue(response$); + + m.expect(effects.fetchProsecutors$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchPleaTypes$', () => { + it( + 'should fetch the plea types from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadPleaTypes(); + const successAction = ReferenceDataActions.loadPleaTypesSuccess({ + pleaStatusTypes: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchPleaTypes.mockReturnValue(response$); + + m.expect(effects.fetchPleaTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the plea types is already in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadOrganisationUnits(); + + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchPleaTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the plea types are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadOrganisationUnitsSuccess({ + organisationUnits: [] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchPleaTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the plea types fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadPleaTypes(); + const errorAction = ReferenceDataActions.loadPleaTypesError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchPleaTypes.mockReturnValue(response$); + + m.expect(effects.fetchPleaTypes$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchWitnessCareUnits$', () => { + it( + 'should fetch the witnessCareUnits from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadWitnessCareUnits(); + const successAction = ReferenceDataActions.loadWitnessCareUnitsSuccess({ + witnessCareUnits: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchWitnessCareUnits.mockReturnValue(response$); + + m.expect(effects.fetchWitnessCareUnits$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the witnessCareUnits is already in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadWitnessCareUnits(); + const successAction = ReferenceDataActions.loadWitnessCareUnitsSuccess({ + witnessCareUnits: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchWitnessCareUnits.mockReturnValue(response$); + + m.expect(effects.fetchWitnessCareUnits$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the witnessCareUnits are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadWitnessCareUnitsSuccess({ + witnessCareUnits: [] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchWitnessCareUnits$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the witnessCareUnits fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadWitnessCareUnits(); + const errorAction = ReferenceDataActions.loadWitnessCareUnitsError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchWitnessCareUnits.mockReturnValue(response$); + + m.expect(effects.fetchWitnessCareUnits$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchTrialTypes$', () => { + it( + 'should fetch the trial types from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadTrialTypes(); + const successAction = ReferenceDataActions.loadTrialTypesSuccess({ + trialTypes: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchTrialTypes.mockReturnValue(response$); + + m.expect(effects.fetchTrialTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the trial types is already in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadTrialTypes(); + const successAction = ReferenceDataActions.loadTrialTypesSuccess({ + trialTypes: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchTrialTypes.mockReturnValue(response$); + + m.expect(effects.fetchTrialTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the trial types are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadTrialTypesSuccess({ + trialTypes: [] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchTrialTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the trial types fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadTrialTypes(); + const errorAction = ReferenceDataActions.loadTrialTypesError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchTrialTypes.mockReturnValue(response$); + + m.expect(effects.fetchTrialTypes$).toBeObservable(expected$); + }) + ); + }); + + describe('fetchPoliceRanks$', () => { + it( + 'should fetch the police ranks from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadPoliceRanks(); + const successAction = ReferenceDataActions.loadPoliceRanksSuccess({ + policeRanks: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + fetchPoliceRanks.mockReturnValue(response$); + + m.expect(effects.fetchPoliceRanks$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the police ranks is already in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadPoliceRanks(); + const successAction = ReferenceDataActions.loadPoliceRanksSuccess({ + policeRanks: [] + }); + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + fetchPoliceRanks.mockReturnValue(response$); + + m.expect(effects.fetchPoliceRanks$).toBeObservable(expected$); + }) + ); + it( + 'should ignore any actions when the police ranks are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadPoliceRanksSuccess({ + policeRanks: [] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + m.expect(effects.fetchPoliceRanks$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the police ranks fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadPoliceRanks(); + const errorAction = ReferenceDataActions.loadPoliceRanksError({ error }); + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + fetchPoliceRanks.mockReturnValue(response$); + + m.expect(effects.fetchPoliceRanks$).toBeObservable(expected$); + }) + ); + }); + describe('fetchPublicHolidays$', () => { + it( + 'should fetch the public holidays from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadPublicHolidays(); + const successAction = ReferenceDataActions.loadPublicHolidaysSuccess({ + publicHolidays: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchPublicHolidays.mockReturnValue(response$); + + m.expect(effects.fetchPublicHolidays$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the public holidays is already in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadPublicHolidays(); + const successAction = ReferenceDataActions.loadPublicHolidaysSuccess({ + publicHolidays: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchPublicHolidays.mockReturnValue(response$); + + m.expect(effects.fetchPublicHolidays$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the public holidays are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadPublicHolidaysSuccess({ + publicHolidays: [] + }); + store.dispatch(loadAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchPublicHolidays$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the public holidays fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadPublicHolidays(); + const errorAction = ReferenceDataActions.loadPublicHolidaysError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchPublicHolidays.mockReturnValue(response$); + + m.expect(effects.fetchPublicHolidays$).toBeObservable(expected$); + }) + ); + }); + describe('fetchOrganisationsWithType$', () => { + it( + 'should fetch the organisations with org type from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadOrganisationsWithType({ + organisationType: OrganisationType.NPS + }); + const successAction = ReferenceDataActions.loadOrganisationsWithTypeSuccess({ + organisationsWithType: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchOrganisationsWithType.mockReturnValue(response$); + + m.expect(effects.fetchOrganisationsWithType$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the organisations with org type is already in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadOrganisationsWithType({ + organisationType: OrganisationType.NPS + }); + const successAction = ReferenceDataActions.loadOrganisationsWithTypeSuccess({ + organisationsWithType: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchOrganisationsWithType.mockReturnValue(response$); + + m.expect(effects.fetchOrganisationsWithType$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when the organisations with org type are already in the store', + marbles((m) => { + const loadAction = ReferenceDataActions.loadOrganisationsWithType({ + organisationType: OrganisationType.NPS + }); + const successAction = ReferenceDataActions.loadOrganisationsWithTypeSuccess({ + organisationsWithType: [] + }); + store.dispatch(successAction); + + actions$ = m.hot(' -a-', { a: loadAction }); + const expected$ = m.cold('---'); + + m.expect(effects.fetchOrganisationsWithType$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the organisations with org tyoe fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadOrganisationsWithType({ + organisationType: OrganisationType.NPS + }); + const errorAction = ReferenceDataActions.loadOrganisationsWithTypeError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchOrganisationsWithType.mockReturnValue(response$); + + m.expect(effects.fetchOrganisationsWithType$).toBeObservable(expected$); + }) + ); + }); + describe('fetchRotaBusinessTypes$', () => { + it( + 'should fetch the Rota business types from the server', + marbles((m) => { + const loadAction = ReferenceDataActions.loadRotaBusinessTypes(); + const successAction = ReferenceDataActions.loadRotaBusinessTypesSuccess({ + rotaBusinessTypes: [] + }); + + actions$ = m.hot(' -a----', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchRotaBusinessTypes.mockReturnValue(response$); + + m.expect(effects.fetchRotaBusinessTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should ignore any actions when fetching the Rota business types is already in progress', + marbles((m) => { + const loadAction = ReferenceDataActions.loadRotaBusinessTypes(); + const successAction = ReferenceDataActions.loadRotaBusinessTypesSuccess({ + rotaBusinessTypes: [] + }); + + actions$ = m.hot(' -aa---', { a: loadAction }); + const response$ = m.cold(' -(b|)', { b: [] }); + const expected$ = m.cold('--c---', { c: successAction }); + + fetchRotaBusinessTypes.mockReturnValue(response$); + + m.expect(effects.fetchRotaBusinessTypes$).toBeObservable(expected$); + }) + ); + + it( + 'should handle an error when fetching the Rota business types fails', + marbles((m) => { + const error = new HttpErrorResponse({ status: 500 }); + const loadAction = ReferenceDataActions.loadRotaBusinessTypes(); + const errorAction = ReferenceDataActions.loadRotaBusinessTypesError({ error }); + + actions$ = m.hot(' -a-', { a: loadAction }); + const response$ = m.cold(' -#', undefined, error); + const expected$ = m.cold('--b', { b: errorAction }); + + fetchRotaBusinessTypes.mockReturnValue(response$); + + m.expect(effects.fetchRotaBusinessTypes$).toBeObservable(expected$); + }) + ); + }); +}); diff --git a/projects/reference-data/src/effects/reference-data.effects.ts b/projects/reference-data/src/effects/reference-data.effects.ts new file mode 100644 index 0000000..7562bc6 --- /dev/null +++ b/projects/reference-data/src/effects/reference-data.effects.ts @@ -0,0 +1,324 @@ +import { Injectable } from '@angular/core'; +import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { Store } from '@ngrx/store'; +import { of } from 'rxjs'; +import { catchError, exhaustMap, filter, map, withLatestFrom } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { + getApplicationTypes, + getAssignPriorities, + getPublicHolidays, + getBookingTypes, + getClusters, + getCPSAreas, + getCPSBusinessUnits, + getCPSCaseStatuses, + getFixedLists, + getHearingTypes, + getOrganisationUnits, + getPleaStatusTypes, + getPoliceForceList, + getPoliceRanks, + getProsecutors, + getTrialTypes, + getWitnessCareUnits, + ReferenceDataState, + getOrganisationsWithType, + getRotaBusinessTypes +} from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; +import { OrganisationType } from '../reference-data.interfaces'; + +@Injectable() +export class ReferenceDataEffects { + fetchApplicationTypes$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadApplicationTypes), + withLatestFrom(this.store), + filter(([, state]) => !getApplicationTypes(state)), + exhaustMap(() => + this.referenceDataService.fetchApplicationTypes().pipe( + map((applicationTypes) => + ReferenceDataActions.loadApplicationTypesSuccess({ applicationTypes }) + ), + catchError((error) => of(ReferenceDataActions.loadApplicationTypesError({ error }))) + ) + ) + ) + ); + + fetchAssignPriorities$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadAssignPriorities), + withLatestFrom(this.store), + filter(([, state]) => !getAssignPriorities(state)), + exhaustMap(() => + this.referenceDataService.fetchAssignPriorities().pipe( + map((assignPriorities) => + ReferenceDataActions.loadAssignPrioritiesSuccess({ assignPriorities }) + ), + catchError((error) => of(ReferenceDataActions.loadAssignPrioritiesError({ error }))) + ) + ) + ) + ); + + fetchBookingTypes$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadBookingTypes), + withLatestFrom(this.store), + filter(([, state]) => !getBookingTypes(state)), + exhaustMap(() => + this.referenceDataService.fetchBookingTypes().pipe( + map((bookingTypes) => ReferenceDataActions.loadBookingTypesSuccess({ bookingTypes })), + catchError((error) => of(ReferenceDataActions.loadBookingTypesError({ error }))) + ) + ) + ) + ); + + fetchClusters$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadClusters), + withLatestFrom(this.store), + filter(([, state]) => !getClusters(state)), + exhaustMap(() => + this.referenceDataService.fetchClusters().pipe( + map((clusters) => ReferenceDataActions.loadClustersSuccess({ clusters })), + catchError((error) => of(ReferenceDataActions.loadClustersError({ error }))) + ) + ) + ) + ); + + fetchCPSAreas$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadCPSAreas), + withLatestFrom(this.store), + filter(([, state]) => !getCPSAreas(state)), + exhaustMap(() => + this.referenceDataService.fetchCPSAreas().pipe( + map((cpsAreas) => ReferenceDataActions.loadCPSAreasSuccess({ cpsAreas })), + catchError((error) => of(ReferenceDataActions.loadCPSAreasError({ error }))) + ) + ) + ) + ); + + fetchCPSBusinessUnits$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadCPSBusinessUnits), + withLatestFrom(this.store), + filter(([, state]) => !getCPSBusinessUnits(state)), + exhaustMap(() => + this.referenceDataService.fetchCPSBusinessUnits().pipe( + map((cpsBusinessUnits) => + ReferenceDataActions.loadCPSBusinessUnitsSuccess({ cpsBusinessUnits }) + ), + catchError((error) => of(ReferenceDataActions.loadCPSBusinessUnitsError({ error }))) + ) + ) + ) + ); + + fetchCPSCaseStatuses$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadCPSCaseStatuses), + withLatestFrom(this.store), + filter(([, state]) => !getCPSCaseStatuses(state)), + exhaustMap(() => + this.referenceDataService.fetchCPSCaseStatuses().pipe( + map((cpsCaseStatuses) => + ReferenceDataActions.loadCPSCaseStatusesSuccess({ cpsCaseStatuses }) + ), + catchError((error) => of(ReferenceDataActions.loadCPSCaseStatusesError({ error }))) + ) + ) + ) + ); + + fetchFixedLists$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadFixedLists), + withLatestFrom(this.store), + filter(([, state]) => getFixedLists(state).length === 0), + exhaustMap(() => + this.referenceDataService.fetchFixedLists().pipe( + map((fixedLists) => ReferenceDataActions.loadFixedListsSuccess({ fixedLists })), + catchError((error) => of(ReferenceDataActions.loadFixedListsError({ error }))) + ) + ) + ) + ); + + fetchOrganisationUnits$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadOrganisationUnits), + withLatestFrom(this.store), + filter(([, state]) => !getOrganisationUnits(state)), + exhaustMap(() => + this.referenceDataService.fetchOrganisationUnits().pipe( + map((organisationUnits) => + ReferenceDataActions.loadOrganisationUnitsSuccess({ organisationUnits }) + ), + catchError((error) => of(ReferenceDataActions.loadOrganisationUnitsError({ error }))) + ) + ) + ) + ); + + fetchHearingTypes$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadHearingTypes), + withLatestFrom(this.store), + filter(([, state]) => !getHearingTypes(state)), + exhaustMap(() => + this.referenceDataService.fetchHearingTypes().pipe( + map((hearingTypes) => ReferenceDataActions.loadHearingTypesSuccess({ hearingTypes })), + catchError((error) => of(ReferenceDataActions.loadHearingTypesError({ error }))) + ) + ) + ) + ); + + fetchPoliceForceList$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadPoliceForceList), + withLatestFrom(this.store), + filter(([, state]) => !getPoliceForceList(state)), + exhaustMap(() => + this.referenceDataService.fetchPoliceForceList().pipe( + map((policeForceList) => + ReferenceDataActions.loadPoliceForceListSuccess({ policeForceList }) + ), + catchError((error) => of(ReferenceDataActions.loadPoliceForceListError({ error }))) + ) + ) + ) + ); + + fetchProsecutors$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadProsecutors), + withLatestFrom(this.store), + filter(([, state]) => !getProsecutors(state)), + exhaustMap(() => + this.referenceDataService.fetchProsecutors().pipe( + map((prosecutors) => ReferenceDataActions.loadProsecutorsSuccess({ prosecutors })), + catchError((error) => of(ReferenceDataActions.loadProsecutorsError({ error }))) + ) + ) + ) + ); + + fetchPleaTypes$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadPleaTypes), + withLatestFrom(this.store), + filter(([, state]) => getPleaStatusTypes(state).length === 0), + exhaustMap(() => + this.referenceDataService.fetchPleaTypes().pipe( + map((pleaStatusTypes) => ReferenceDataActions.loadPleaTypesSuccess({ pleaStatusTypes })), + catchError((error) => of(ReferenceDataActions.loadPleaTypesError({ error }))) + ) + ) + ) + ); + + fetchWitnessCareUnits$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadWitnessCareUnits), + withLatestFrom(this.store), + filter(([, state]) => !getWitnessCareUnits(state)), + exhaustMap(() => + this.referenceDataService.fetchWitnessCareUnits().pipe( + map((witnessCareUnits) => + ReferenceDataActions.loadWitnessCareUnitsSuccess({ witnessCareUnits }) + ), + catchError((error) => of(ReferenceDataActions.loadWitnessCareUnitsError({ error }))) + ) + ) + ) + ); + + fetchTrialTypes$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadTrialTypes), + withLatestFrom(this.store), + filter(([, state]) => getTrialTypes(state).length === 0), + exhaustMap(() => + this.referenceDataService.fetchTrialTypes().pipe( + map((trialTypes) => ReferenceDataActions.loadTrialTypesSuccess({ trialTypes })), + catchError((error) => of(ReferenceDataActions.loadTrialTypesError({ error }))) + ) + ) + ) + ); + + fetchPoliceRanks$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadPoliceRanks), + withLatestFrom(this.store), + filter(([, state]) => getPoliceRanks(state).length === 0), + exhaustMap(() => + this.referenceDataService.fetchPoliceRanks().pipe( + map((policeRanks) => ReferenceDataActions.loadPoliceRanksSuccess({ policeRanks })), + catchError((error) => of(ReferenceDataActions.loadPoliceRanksError({ error }))) + ) + ) + ) + ); + fetchPublicHolidays$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadPublicHolidays), + withLatestFrom(this.store), + filter(([, state]) => !getPublicHolidays(state)), + exhaustMap(() => + this.referenceDataService.fetchPublicHolidays().pipe( + map((publicHolidays) => + ReferenceDataActions.loadPublicHolidaysSuccess({ publicHolidays }) + ), + catchError((error) => of(ReferenceDataActions.loadPublicHolidaysError({ error }))) + ) + ) + ) + ); + + fetchOrganisationsWithType$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadOrganisationsWithType), + withLatestFrom(this.store), + filter(([, state]) => !getOrganisationsWithType(state)), + exhaustMap(([{ organisationType }]) => + this.referenceDataService.fetchOrganisationsWithType(organisationType).pipe( + map((organisationsWithType) => + ReferenceDataActions.loadOrganisationsWithTypeSuccess({ organisationsWithType }) + ), + catchError((error) => of(ReferenceDataActions.loadOrganisationsWithTypeError({ error }))) + ) + ) + ) + ); + + fetchRotaBusinessTypes$ = createEffect(() => + this.actions$.pipe( + ofType(ReferenceDataActions.loadRotaBusinessTypes), + withLatestFrom(this.store), + filter(([, state]) => getRotaBusinessTypes(state).length === 0), + exhaustMap(() => + this.referenceDataService.fetchRotaBusinessTypes().pipe( + map((rotaBusinessTypes) => + ReferenceDataActions.loadRotaBusinessTypesSuccess({ rotaBusinessTypes }) + ), + catchError((error) => of(ReferenceDataActions.loadRotaBusinessTypesError({ error }))) + ) + ) + ) + ); + + constructor( + private referenceDataService: ReferenceDataService, + private actions$: Actions, + private store: Store + ) {} +} diff --git a/projects/reference-data/src/guards/__tests__/application-type.guard.spec.ts b/projects/reference-data/src/guards/__tests__/application-type.guard.spec.ts new file mode 100644 index 0000000..ecd22d5 --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/application-type.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { ApplicationTypesGuard } from '../application-type.guard'; + +describe('ApplicationTypesGuard', () => { + let guard: ApplicationTypesGuard; + let store: Store; + + let fetchApplicationTypes: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchApplicationTypes = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + ApplicationTypesGuard, + { + provide: ReferenceDataService, + useValue: { + fetchApplicationTypes + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(ApplicationTypesGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the application types exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadApplicationTypesSuccess({ applicationTypes: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching application types from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchApplicationTypes.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadApplicationTypesSuccess({ applicationTypes: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the application types', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchApplicationTypes.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/assign-priorities.guard.spec.ts b/projects/reference-data/src/guards/__tests__/assign-priorities.guard.spec.ts new file mode 100644 index 0000000..4163ca2 --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/assign-priorities.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { AssignPrioritiesGuard } from '../assingn-priorities.guard'; + +describe('AssignPrioritiesGuard', () => { + let guard: AssignPrioritiesGuard; + let store: Store; + + let fetchAssignPriorities: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchAssignPriorities = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + AssignPrioritiesGuard, + { + provide: ReferenceDataService, + useValue: { + fetchAssignPriorities + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(AssignPrioritiesGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the assign priorities exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadAssignPrioritiesSuccess({ assignPriorities: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching assign priorities from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchAssignPriorities.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadAssignPrioritiesSuccess({ assignPriorities: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the assign priorities', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchAssignPriorities.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/booking-types.guard.spec.ts b/projects/reference-data/src/guards/__tests__/booking-types.guard.spec.ts new file mode 100644 index 0000000..778acfe --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/booking-types.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { BookingTypesGuard } from '../booking-types.guard'; + +describe('BookingTypesGuard', () => { + let guard: BookingTypesGuard; + let store: Store; + + let fetchBookingTypes: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchBookingTypes = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + BookingTypesGuard, + { + provide: ReferenceDataService, + useValue: { + fetchBookingTypes + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(BookingTypesGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the booking types exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadBookingTypesSuccess({ bookingTypes: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching booking typess from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchBookingTypes.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadBookingTypesSuccess({ bookingTypes: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the booking types', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchBookingTypes.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/clusters.guard.spec.ts b/projects/reference-data/src/guards/__tests__/clusters.guard.spec.ts new file mode 100644 index 0000000..fa5118d --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/clusters.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { ClustersGuard } from '../clusters.guard'; + +describe('ClustersGuard', () => { + let guard: ClustersGuard; + let store: Store; + + let fetchClusters: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchClusters = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + ClustersGuard, + { + provide: ReferenceDataService, + useValue: { + fetchClusters + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(ClustersGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the clusters exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadClustersSuccess({ clusters: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching clusters from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchClusters.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadClustersSuccess({ clusters: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the clusters', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchClusters.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/court-centre-units.gard.spec.ts b/projects/reference-data/src/guards/__tests__/court-centre-units.gard.spec.ts new file mode 100644 index 0000000..62ab25d --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/court-centre-units.gard.spec.ts @@ -0,0 +1,122 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { createCourtCentreUnitsGuard } from '../court-centre-units.gard'; + +describe('createCourtCentreUnitsGuard', () => { + let store: Store; + + let fetchOrganisationUnits: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchOrganisationUnits = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + { + provide: ReferenceDataService, + useValue: { + fetchOrganisationUnits + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the organisation units exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadOrganisationUnitsSuccess({ organisationUnits: [] })); + + TestBed.runInInjectionContext(() => + createCourtCentreUnitsGuard()(snapshot, {} as RouterStateSnapshot) + ).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching with includeExpired=false when not found in the store', () => { + expect.assertions(3); + const snapshot = createSnapshot(); + + fetchOrganisationUnits.mockReturnValue(of([])); + + TestBed.runInInjectionContext(() => + createCourtCentreUnitsGuard()(snapshot, {} as RouterStateSnapshot) + ).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(fetchOrganisationUnits).toHaveBeenCalledWith(false); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadOrganisationUnitsSuccess({ organisationUnits: [] }) + ); + }); + }); + + it('should resolve to true after fetching with includeExpired=true when not found in the store', () => { + expect.assertions(3); + const snapshot = createSnapshot(); + + fetchOrganisationUnits.mockReturnValue(of([])); + + TestBed.runInInjectionContext(() => + createCourtCentreUnitsGuard(true)(snapshot, {} as RouterStateSnapshot) + ).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(fetchOrganisationUnits).toHaveBeenCalledWith(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadOrganisationUnitsSuccess({ organisationUnits: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the organisation units', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchOrganisationUnits.mockReturnValue(throwError(error)); + + TestBed.runInInjectionContext(() => + createCourtCentreUnitsGuard()(snapshot, {} as RouterStateSnapshot) + ).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/court-centres.guard.spec.ts b/projects/reference-data/src/guards/__tests__/court-centres.guard.spec.ts new file mode 100644 index 0000000..e159866 --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/court-centres.guard.spec.ts @@ -0,0 +1,102 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { OrganisationUnitsGuard } from '../court-centres.guard'; + +describe('OrganisationUnitsGuard', () => { + let guard: OrganisationUnitsGuard; + let store: Store; + + let fetchOrganisationUnits: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchOrganisationUnits = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + OrganisationUnitsGuard, + { + provide: ReferenceDataService, + useValue: { + fetchOrganisationUnits + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(OrganisationUnitsGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the court centres exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadOrganisationUnitsSuccess({ organisationUnits: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching court centres from the server when not found in the store', () => { + expect.assertions(3); + const snapshot = createSnapshot(); + + fetchOrganisationUnits.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(fetchOrganisationUnits).toHaveBeenCalledWith(false); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadOrganisationUnitsSuccess({ organisationUnits: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the court centres', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchOrganisationUnits.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/cps-areas.guard.spec.ts b/projects/reference-data/src/guards/__tests__/cps-areas.guard.spec.ts new file mode 100644 index 0000000..bdf9a44 --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/cps-areas.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { CPSAreasGuard } from '../cps-areas.guard'; + +describe('CPSAreasGuard', () => { + let guard: CPSAreasGuard; + let store: Store; + + let fetchCPSAreas: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchCPSAreas = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + CPSAreasGuard, + { + provide: ReferenceDataService, + useValue: { + fetchCPSAreas + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(CPSAreasGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the cps areas exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadCPSAreasSuccess({ cpsAreas: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching cps areas from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchCPSAreas.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadCPSAreasSuccess({ cpsAreas: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the cps areas', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchCPSAreas.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/cps-business-units.guard.spec.ts b/projects/reference-data/src/guards/__tests__/cps-business-units.guard.spec.ts new file mode 100644 index 0000000..64fa69f --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/cps-business-units.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { CPSBusinessUnitsGuard } from '../cps-business-units.guard'; + +describe('CPSBusinessUnitsGuard', () => { + let guard: CPSBusinessUnitsGuard; + let store: Store; + + let fetchCPSBusinessUnits: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchCPSBusinessUnits = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + CPSBusinessUnitsGuard, + { + provide: ReferenceDataService, + useValue: { + fetchCPSBusinessUnits + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(CPSBusinessUnitsGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the cps business units exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadCPSBusinessUnitsSuccess({ cpsBusinessUnits: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching cps business units from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchCPSBusinessUnits.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadCPSBusinessUnitsSuccess({ cpsBusinessUnits: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the cps business units', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchCPSBusinessUnits.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/cps-case-status.guard.spec.ts b/projects/reference-data/src/guards/__tests__/cps-case-status.guard.spec.ts new file mode 100644 index 0000000..81d81fb --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/cps-case-status.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { CPSCaseStatusGuard } from '../cps-case-status.guard'; + +describe('CPSCaseStatusGuard', () => { + let guard: CPSCaseStatusGuard; + let store: Store; + + let fetchCPSCaseStatuses: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchCPSCaseStatuses = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + CPSCaseStatusGuard, + { + provide: ReferenceDataService, + useValue: { + fetchCPSCaseStatuses + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(CPSCaseStatusGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the cps case statuses exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadCPSCaseStatusesSuccess({ cpsCaseStatuses: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching cps case statuses from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchCPSCaseStatuses.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadCPSCaseStatusesSuccess({ cpsCaseStatuses: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the cps case statuses', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchCPSCaseStatuses.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/hearing-type.guard.spec.ts b/projects/reference-data/src/guards/__tests__/hearing-type.guard.spec.ts new file mode 100644 index 0000000..92b120e --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/hearing-type.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { HearingTypesGuard } from '../hearing-type.guard'; + +describe('HearingTypesGuard', () => { + let guard: HearingTypesGuard; + let store: Store; + + let fetchHearingTypes: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchHearingTypes = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + HearingTypesGuard, + { + provide: ReferenceDataService, + useValue: { + fetchHearingTypes + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(HearingTypesGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the hearing types exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadHearingTypesSuccess({ hearingTypes: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching hearing types from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchHearingTypes.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadHearingTypesSuccess({ hearingTypes: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the hearing types', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchHearingTypes.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/judiciary-group-types.spec.ts b/projects/reference-data/src/guards/__tests__/judiciary-group-types.spec.ts new file mode 100644 index 0000000..5ca62cb --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/judiciary-group-types.spec.ts @@ -0,0 +1,103 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { JudiciaryGroupTypesGuard } from '../judiciary-group-types.guard'; + +describe('JudiciaryGroupTypesGuard', () => { + let guard: JudiciaryGroupTypesGuard; + let store: Store; + + let fetchJudiciaryGroupTypes: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchJudiciaryGroupTypes = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + JudiciaryGroupTypesGuard, + { + provide: ReferenceDataService, + useValue: { + fetchJudiciaryGroupTypes + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(JudiciaryGroupTypesGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the judiciary group types exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch( + ReferenceDataActions.loadJudiciaryGroupTypesSuccess({ judiciaryGroupTypes: [] }) + ); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching judiciary group types from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchJudiciaryGroupTypes.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadJudiciaryGroupTypesSuccess({ judiciaryGroupTypes: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the hearing types', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchJudiciaryGroupTypes.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/local-justice-areas.guard.spec.ts b/projects/reference-data/src/guards/__tests__/local-justice-areas.guard.spec.ts new file mode 100644 index 0000000..d649c96 --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/local-justice-areas.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { LocalJusticeAreasGuard } from '../local-justice-areas.guard'; + +describe('LocalJusticeAreasGuard', () => { + let guard: LocalJusticeAreasGuard; + let store: Store; + + let fetchLocalJusticAreas: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchLocalJusticAreas = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + LocalJusticeAreasGuard, + { + provide: ReferenceDataService, + useValue: { + fetchLocalJusticAreas + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(LocalJusticeAreasGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the localJusticeAreas exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadLocalJusticeAreasSuccess({ localJusticeAreas: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching localJusticeAreas from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchLocalJusticAreas.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadLocalJusticeAreasSuccess({ localJusticeAreas: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the localJusticeAreas', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchLocalJusticAreas.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/organisation-with-type.guard.spec.ts b/projects/reference-data/src/guards/__tests__/organisation-with-type.guard.spec.ts new file mode 100644 index 0000000..f1ced3c --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/organisation-with-type.guard.spec.ts @@ -0,0 +1,124 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { Observable, of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { MockStore, provideMockStore } from '@ngrx/store/testing'; +import { canActivateOrganisationsWithType } from '../organisation-with-type.guard'; +import { OrganisationType, OrganisationWithType } from '../../reference-data.interfaces'; + +const routerSnapshot = {} as RouterStateSnapshot; +const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + + snapshot.queryParams = { + orgType: OrganisationType.NPS + }; + return snapshot; +}; + +describe('OrganisationsWithOrgTypeGuard', () => { + let store: MockStore; + + let fetchOrganisationsWithType: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchOrganisationsWithType = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + providers: [ + provideMockStore({ initialState: {} }), + { + provide: ReferenceDataService, + useValue: { + fetchOrganisationsWithType + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + store = TestBed.inject(MockStore); + store.setState({ referenceData: {} } as ReferenceDataState); + jest.spyOn(store, 'dispatch'); + }); + + it('should resolve to true when the organisations for org type exist in the store', (done) => { + expect.assertions(2); + const snapshot = createSnapshot(); + + store.setState({ + referenceData: { + organisationsWithType: [{ orgType: OrganisationType.NPS } as OrganisationWithType] + } + }); + + const canActivate$ = TestBed.runInInjectionContext( + () => canActivateOrganisationsWithType(snapshot, routerSnapshot) as Observable + ); + + canActivate$.subscribe((didActivate) => { + expect(didActivate).toBe(true); + expect(store.dispatch).not.toHaveBeenCalledWith( + ReferenceDataActions.loadOrganisationsWithTypeSuccess({ + organisationsWithType: [{ orgType: OrganisationType.NPS } as OrganisationWithType] + }) + ); + done(); + }); + }); + + it('should resolve to true after fetching organisations with orgType from the server when not found in the store', (done) => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchOrganisationsWithType.mockReturnValue( + of([{ orgType: OrganisationType.NPS } as OrganisationWithType]) + ); + + const canActivate$ = TestBed.runInInjectionContext( + () => canActivateOrganisationsWithType(snapshot, routerSnapshot) as Observable + ); + + canActivate$.subscribe((didActivate) => { + expect(didActivate).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadOrganisationsWithTypeSuccess({ + organisationsWithType: [{ orgType: OrganisationType.NPS } as OrganisationWithType] + }) + ); + done(); + }); + }); + + it('should reject the activation when there is an error fetching the organisations with org type', (done) => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchOrganisationsWithType.mockReturnValue(throwError(error)); + + const canActivate$ = TestBed.runInInjectionContext( + () => canActivateOrganisationsWithType(snapshot, routerSnapshot) as Observable + ); + + canActivate$.subscribe((didActivate) => { + expect(didActivate).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + done(); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/plea-types.guard.spec.ts b/projects/reference-data/src/guards/__tests__/plea-types.guard.spec.ts new file mode 100644 index 0000000..8e48f11 --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/plea-types.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { PleaTypesGuard } from '../plea-types.guard'; + +describe('PleaTypesGuard', () => { + let guard: PleaTypesGuard; + let store: Store; + + let fetchPleaTypes: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchPleaTypes = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + PleaTypesGuard, + { + provide: ReferenceDataService, + useValue: { + fetchPleaTypes + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(PleaTypesGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the plea types exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadPleaTypesSuccess({ pleaStatusTypes: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching plea types from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchPleaTypes.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadPleaTypesSuccess({ pleaStatusTypes: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the plea types', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchPleaTypes.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/police-force.guard.spec.ts b/projects/reference-data/src/guards/__tests__/police-force.guard.spec.ts new file mode 100644 index 0000000..9d6a5e3 --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/police-force.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { PoliceForceListGuard } from '../police-force.guard'; + +describe('PoliceForceListGuard', () => { + let guard: PoliceForceListGuard; + let store: Store; + + let fetchPoliceForceList: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchPoliceForceList = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + PoliceForceListGuard, + { + provide: ReferenceDataService, + useValue: { + fetchPoliceForceList + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(PoliceForceListGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the policeForceList exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadPoliceForceListSuccess({ policeForceList: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching policeForceList from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchPoliceForceList.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadPoliceForceListSuccess({ policeForceList: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the policeForceList', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchPoliceForceList.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/police-ranks.guard.spec.ts b/projects/reference-data/src/guards/__tests__/police-ranks.guard.spec.ts new file mode 100644 index 0000000..11c60bd --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/police-ranks.guard.spec.ts @@ -0,0 +1,99 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { PoliceRanksGuard } from '../police-ranks.guard'; + +describe('PoliceRanksGuard', () => { + let guard: PoliceRanksGuard; + let store: Store; + + let fetchPoliceRanks: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchPoliceRanks = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + PoliceRanksGuard, + { + provide: ReferenceDataService, + useValue: { + fetchPoliceRanks + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.get(PoliceRanksGuard); + store = TestBed.get(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the policeRanks exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadPoliceRanksSuccess({ policeRanks: [] })); + + guard.canActivate(snapshot).subscribe(didResolve => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching policeRanks from the server when not found in the store', () => { + const snapshot = createSnapshot(); + + fetchPoliceRanks.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe(didResolve => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadPoliceRanksSuccess({ policeRanks: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the policeRanks', () => { + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchPoliceRanks.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe(didResolve => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/prosecutors.guard.spec.ts b/projects/reference-data/src/guards/__tests__/prosecutors.guard.spec.ts new file mode 100644 index 0000000..9bc82ea --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/prosecutors.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { ProsecutorsGuard } from '../prosecutors.guard'; + +describe('ProsecutorsGuard', () => { + let guard: ProsecutorsGuard; + let store: Store; + + let fetchProsecutors: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchProsecutors = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + ProsecutorsGuard, + { + provide: ReferenceDataService, + useValue: { + fetchProsecutors + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(ProsecutorsGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the prosecutors exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadProsecutorsSuccess({ prosecutors: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching prosecutors from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchProsecutors.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadProsecutorsSuccess({ prosecutors: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the prosecutors', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchProsecutors.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/public-holidays.guard.spec.ts b/projects/reference-data/src/guards/__tests__/public-holidays.guard.spec.ts new file mode 100644 index 0000000..b1b87bb --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/public-holidays.guard.spec.ts @@ -0,0 +1,102 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; + +import { PublicHolidaysGuard } from '../public-holidays.guard'; + +describe('PublicHolidaysGuard', () => { + let guard: PublicHolidaysGuard; + let store: Store; + + let fetchPublicHolidays: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchPublicHolidays = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + PublicHolidaysGuard, + { + provide: ReferenceDataService, + useValue: { + fetchPublicHolidays + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.get(PublicHolidaysGuard); + store = TestBed.get(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the public holidays exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadPublicHolidaysSuccess({ publicHolidays: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching public holidays from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchPublicHolidays.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadPublicHolidaysSuccess({ publicHolidays: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the public holidays', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchPublicHolidays.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/rota-business-types.guard.spec.ts b/projects/reference-data/src/guards/__tests__/rota-business-types.guard.spec.ts new file mode 100644 index 0000000..69b1273 --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/rota-business-types.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { RotaBusinessTypesGuard } from '../rota-business-types.guard'; + +describe('RotaBusinessTypesGuard', () => { + let guard: RotaBusinessTypesGuard; + let store: Store; + + let fetchRotaBusinessTypes: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchRotaBusinessTypes = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + RotaBusinessTypesGuard, + { + provide: ReferenceDataService, + useValue: { + fetchRotaBusinessTypes + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(RotaBusinessTypesGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the rota business types exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadRotaBusinessTypesSuccess({ rotaBusinessTypes: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching rota business types from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchRotaBusinessTypes.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadRotaBusinessTypesSuccess({ rotaBusinessTypes: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the rota business types', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchRotaBusinessTypes.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/special-requirements.guard.spec.ts b/projects/reference-data/src/guards/__tests__/special-requirements.guard.spec.ts new file mode 100644 index 0000000..35d5165 --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/special-requirements.guard.spec.ts @@ -0,0 +1,103 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { SpecialRequirementsGuard } from '../special-requirement.guard'; + +describe('SpecialRequirementsGuard', () => { + let guard: SpecialRequirementsGuard; + let store: Store; + + let fetchSpecialRequirements: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchSpecialRequirements = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + SpecialRequirementsGuard, + { + provide: ReferenceDataService, + useValue: { + fetchSpecialRequirements + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(SpecialRequirementsGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the special requirements exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch( + ReferenceDataActions.loadSpecialRequirementsSuccess({ specialRequirements: [] }) + ); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching special requirements from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchSpecialRequirements.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadSpecialRequirementsSuccess({ specialRequirements: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the special requirements', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchSpecialRequirements.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/trial-types.guard.spec.ts b/projects/reference-data/src/guards/__tests__/trial-types.guard.spec.ts new file mode 100644 index 0000000..3785296 --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/trial-types.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { TrialTypesGuard } from '../trial-types.guard'; + +describe('TrialTypesGuard', () => { + let guard: TrialTypesGuard; + let store: Store; + + let fetchTrialTypes: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchTrialTypes = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + TrialTypesGuard, + { + provide: ReferenceDataService, + useValue: { + fetchTrialTypes + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(TrialTypesGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the trial types exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadTrialTypesSuccess({ trialTypes: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching trial types from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchTrialTypes.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadTrialTypesSuccess({ trialTypes: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the trial types', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchTrialTypes.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/__tests__/witness-care-unit.guard.spec.ts b/projects/reference-data/src/guards/__tests__/witness-care-unit.guard.spec.ts new file mode 100644 index 0000000..60949a6 --- /dev/null +++ b/projects/reference-data/src/guards/__tests__/witness-care-unit.guard.spec.ts @@ -0,0 +1,101 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import { ReferenceDataActions } from '../../actions/index'; +import { referenceDataReducer, ReferenceDataState } from '../../reducers/index'; +import { ReferenceDataService } from '../../services/reference-data.service'; +import { WitnessCareUnitGuard } from '../witness-care-unit.guard'; + +describe('WitnessCareUnitGuard', () => { + let guard: WitnessCareUnitGuard; + let store: Store; + + let fetchWitnessCareUnits: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + fetchWitnessCareUnits = jest.fn(); + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: referenceDataReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + WitnessCareUnitGuard, + { + provide: ReferenceDataService, + useValue: { + fetchWitnessCareUnits + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(WitnessCareUnitGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = (referenceDataErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + referenceDataErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the witnessCareUnits exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + + store.dispatch(ReferenceDataActions.loadWitnessCareUnitsSuccess({ witnessCareUnits: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching witnessCareUnits from the server when not found in the store', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchWitnessCareUnits.mockReturnValue(of([])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + ReferenceDataActions.loadWitnessCareUnitsSuccess({ witnessCareUnits: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the witnessCareUnits', () => { + expect.assertions(2); + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchWitnessCareUnits.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/reference-data/src/guards/application-type.guard.ts b/projects/reference-data/src/guards/application-type.guard.ts new file mode 100644 index 0000000..89a8065 --- /dev/null +++ b/projects/reference-data/src/guards/application-type.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getApplicationTypes, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class ApplicationTypesGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasApplicationTypesInStore() { + return this.store.pipe( + map(getApplicationTypes), + map((applicationTypes) => !!applicationTypes), + take(1) + ); + } + + hasApplicationTypesInApi() { + return this.referenceData.fetchApplicationTypes().pipe( + tap((applicationTypes) => + this.store.dispatch(ReferenceDataActions.loadApplicationTypesSuccess({ applicationTypes })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasApplicationTypesInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasApplicationTypesInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/assingn-priorities.guard.ts b/projects/reference-data/src/guards/assingn-priorities.guard.ts new file mode 100644 index 0000000..6470586 --- /dev/null +++ b/projects/reference-data/src/guards/assingn-priorities.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getAssignPriorities, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class AssignPrioritiesGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasAssignPrioritiesInStore() { + return this.store.pipe( + map(getAssignPriorities), + map((assignPriorities) => !!assignPriorities), + take(1) + ); + } + + hasAssignPrioritiesInApi() { + return this.referenceData.fetchAssignPriorities().pipe( + tap((assignPriorities) => + this.store.dispatch(ReferenceDataActions.loadAssignPrioritiesSuccess({ assignPriorities })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasAssignPrioritiesInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasAssignPrioritiesInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/booking-types.guard.ts b/projects/reference-data/src/guards/booking-types.guard.ts new file mode 100644 index 0000000..679295a --- /dev/null +++ b/projects/reference-data/src/guards/booking-types.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getBookingTypes, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class BookingTypesGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasBookingTypesInStore() { + return this.store.pipe( + map(getBookingTypes), + map((bookingTypes) => !!bookingTypes), + take(1) + ); + } + + hasBookingTypesInApi() { + return this.referenceData.fetchBookingTypes().pipe( + tap((bookingTypes) => + this.store.dispatch(ReferenceDataActions.loadBookingTypesSuccess({ bookingTypes })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasBookingTypesInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasBookingTypesInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/clusters.guard.ts b/projects/reference-data/src/guards/clusters.guard.ts new file mode 100644 index 0000000..ee6138e --- /dev/null +++ b/projects/reference-data/src/guards/clusters.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getClusters, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class ClustersGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasClustersInStore() { + return this.store.pipe( + map(getClusters), + map((clusters) => !!clusters), + take(1) + ); + } + + hasClustersInApi() { + return this.referenceData.fetchClusters().pipe( + tap((clusters) => + this.store.dispatch(ReferenceDataActions.loadClustersSuccess({ clusters })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasClustersInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasClustersInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/court-centre-units.gard.ts b/projects/reference-data/src/guards/court-centre-units.gard.ts new file mode 100644 index 0000000..5a34072 --- /dev/null +++ b/projects/reference-data/src/guards/court-centre-units.gard.ts @@ -0,0 +1,52 @@ +import { inject } from '@angular/core'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getOrganisationUnits, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +export function createCourtCentreUnitsGuard(includeExpired = false) { + return (route: ActivatedRouteSnapshot, _state: RouterStateSnapshot): Observable => { + const referenceDataService = inject(ReferenceDataService); + const store = inject(Store); + const router = inject(Router); + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + + return hasOrganisationUnitsInStore(store).pipe( + switchMap((inStore) => + inStore ? of(true) : hasOrganisationUnitsInApi(store, referenceDataService, includeExpired) + ), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + }; +} + +const hasOrganisationUnitsInStore = (store: Store): Observable => + store.pipe( + map(getOrganisationUnits), + map((organisationUnits) => !!organisationUnits), + take(1) + ); + +const hasOrganisationUnitsInApi = ( + store: Store, + service: ReferenceDataService, + includeExpired: boolean +) => + service.fetchOrganisationUnits(includeExpired).pipe( + tap((organisationUnits) => + store.dispatch(ReferenceDataActions.loadOrganisationUnitsSuccess({ organisationUnits })) + ), + mapTo(true) + ); diff --git a/projects/reference-data/src/guards/court-centres.guard.ts b/projects/reference-data/src/guards/court-centres.guard.ts new file mode 100644 index 0000000..5f913eb --- /dev/null +++ b/projects/reference-data/src/guards/court-centres.guard.ts @@ -0,0 +1,56 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getOrganisationUnits, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +/** + * @deprecated Use {@link createCourtCentreUnitsGuard} from `court-centre-units.gard` instead. + */ +@Injectable() +export class OrganisationUnitsGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasOrganisationUnitsInStore() { + return this.store.pipe( + map(getOrganisationUnits), + map((organisationUnits) => !!organisationUnits), + take(1) + ); + } + + hasOrganisationUnitsInApi() { + return this.referenceData.fetchOrganisationUnits(false).pipe( + tap((organisationUnits) => + this.store.dispatch( + ReferenceDataActions.loadOrganisationUnitsSuccess({ organisationUnits }) + ) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasOrganisationUnitsInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasOrganisationUnitsInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/cps-areas.guard.ts b/projects/reference-data/src/guards/cps-areas.guard.ts new file mode 100644 index 0000000..d4e7595 --- /dev/null +++ b/projects/reference-data/src/guards/cps-areas.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getCPSAreas, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class CPSAreasGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasCPSAreasInStore() { + return this.store.pipe( + map(getCPSAreas), + map((cpsAreas) => !!cpsAreas), + take(1) + ); + } + + hasCPSAreasInInApi() { + return this.referenceData.fetchCPSAreas().pipe( + tap((cpsAreas) => + this.store.dispatch(ReferenceDataActions.loadCPSAreasSuccess({ cpsAreas })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasCPSAreasInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasCPSAreasInInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/cps-business-units.guard.ts b/projects/reference-data/src/guards/cps-business-units.guard.ts new file mode 100644 index 0000000..561bf10 --- /dev/null +++ b/projects/reference-data/src/guards/cps-business-units.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getCPSBusinessUnits, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class CPSBusinessUnitsGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasCPSBusinessUnitsInStore() { + return this.store.pipe( + map(getCPSBusinessUnits), + map((businessUnits) => !!businessUnits), + take(1) + ); + } + + hasCPSBusinessUnitsInApi() { + return this.referenceData.fetchCPSBusinessUnits().pipe( + tap((cpsBusinessUnits) => + this.store.dispatch(ReferenceDataActions.loadCPSBusinessUnitsSuccess({ cpsBusinessUnits })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasCPSBusinessUnitsInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasCPSBusinessUnitsInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/cps-case-status.guard.ts b/projects/reference-data/src/guards/cps-case-status.guard.ts new file mode 100644 index 0000000..8176e45 --- /dev/null +++ b/projects/reference-data/src/guards/cps-case-status.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getCPSCaseStatuses, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class CPSCaseStatusGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasCPSCaseStatusesInStore() { + return this.store.pipe( + map(getCPSCaseStatuses), + map((caseStatuses) => !!caseStatuses), + take(1) + ); + } + + hasCPSCaseStatusesInApi() { + return this.referenceData.fetchCPSCaseStatuses().pipe( + tap((cpsCaseStatuses) => + this.store.dispatch(ReferenceDataActions.loadCPSCaseStatusesSuccess({ cpsCaseStatuses })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasCPSCaseStatusesInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasCPSCaseStatusesInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/fixed-lists.guard.ts b/projects/reference-data/src/guards/fixed-lists.guard.ts new file mode 100644 index 0000000..f1329ef --- /dev/null +++ b/projects/reference-data/src/guards/fixed-lists.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { ReferenceDataState, getFixedLists } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class FixedListsGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasFixedListsInStore() { + return this.store.pipe( + map(getFixedLists), + map((fixedLists) => fixedLists.length !== 0), + take(1) + ); + } + + hasFixedListsInApi() { + return this.referenceData.fetchFixedLists().pipe( + tap((fixedLists) => + this.store.dispatch(ReferenceDataActions.loadFixedListsSuccess({ fixedLists })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasFixedListsInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasFixedListsInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/hearing-type.guard.ts b/projects/reference-data/src/guards/hearing-type.guard.ts new file mode 100644 index 0000000..7f26fbf --- /dev/null +++ b/projects/reference-data/src/guards/hearing-type.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getHearingTypes, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class HearingTypesGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasApplicationTypesInStore() { + return this.store.pipe( + map(getHearingTypes), + map((hearingTypes) => !!hearingTypes), + take(1) + ); + } + + hasApplicationTypesInApi() { + return this.referenceData.fetchHearingTypes().pipe( + tap((hearingTypes) => + this.store.dispatch(ReferenceDataActions.loadHearingTypesSuccess({ hearingTypes })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasApplicationTypesInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasApplicationTypesInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/judiciary-group-types.guard.ts b/projects/reference-data/src/guards/judiciary-group-types.guard.ts new file mode 100644 index 0000000..8ff4483 --- /dev/null +++ b/projects/reference-data/src/guards/judiciary-group-types.guard.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getJudiciaryGroupTypes, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class JudiciaryGroupTypesGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasJudiciaryGroupTypesInStore() { + return this.store.pipe( + map(getJudiciaryGroupTypes), + map((judiciaryGroupTypes) => !!judiciaryGroupTypes), + take(1) + ); + } + + hasJudiciaryGroupTypesInApi() { + return this.referenceData.fetchJudiciaryGroupTypes().pipe( + tap((judiciaryGroupTypes) => + this.store.dispatch( + ReferenceDataActions.loadJudiciaryGroupTypesSuccess({ judiciaryGroupTypes }) + ) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasJudiciaryGroupTypesInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasJudiciaryGroupTypesInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/local-justice-areas.guard.ts b/projects/reference-data/src/guards/local-justice-areas.guard.ts new file mode 100644 index 0000000..43520b6 --- /dev/null +++ b/projects/reference-data/src/guards/local-justice-areas.guard.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getLocalJusticeAreas, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class LocalJusticeAreasGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasLocalJusticeAreasInStore() { + return this.store.pipe( + map(getLocalJusticeAreas), + map((localJusticeAreas) => !!localJusticeAreas), + take(1) + ); + } + + hasLocalJusticeAreasInApi() { + return this.referenceData.fetchLocalJusticAreas().pipe( + tap((localJusticeAreas) => + this.store.dispatch( + ReferenceDataActions.loadLocalJusticeAreasSuccess({ localJusticeAreas }) + ) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasLocalJusticeAreasInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasLocalJusticeAreasInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/organisation-with-type.guard.ts b/projects/reference-data/src/guards/organisation-with-type.guard.ts new file mode 100644 index 0000000..6f7034e --- /dev/null +++ b/projects/reference-data/src/guards/organisation-with-type.guard.ts @@ -0,0 +1,62 @@ +import { inject } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivateFn, Router } from '@angular/router'; +import { Observable, of } from 'rxjs'; +import { select, Store } from '@ngrx/store'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataService } from '../services/reference-data.service'; +import { getOrganisationsWithType, ReferenceDataState } from '../reducers'; +import { OrganisationType } from '../reference-data.interfaces'; +import { ReferenceDataActions } from '../actions'; + +export const canActivateOrganisationsWithType: CanActivateFn = ( + route: ActivatedRouteSnapshot +): Observable => { + const orgType = route.queryParams.orgType || route.params.orgType; + const { referenceDataErrorRedirectTo = '/technical-error' } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + const referenceDataService = inject(ReferenceDataService); + const store = inject(Store); + const router = inject(Router); + return hasOrganisationsWithOrgTypeInStore(orgType, store).pipe( + switchMap((inStore) => + !!inStore ? of(true) : hasOrganisationsWithOrgTypeInApi(orgType, store, referenceDataService) + ), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); +}; + +const hasOrganisationsWithOrgTypeInStore = ( + organisationType: OrganisationType, + store: Store +): Observable => + store.pipe( + select(getOrganisationsWithType), + take(1), + map( + (organisationsWithType) => + !!organisationsWithType && + organisationsWithType.some(({ orgType }) => orgType === organisationType) + ) + ); + +const hasOrganisationsWithOrgTypeInApi = ( + orgType: OrganisationType, + store: Store, + service: ReferenceDataService +) => + service.fetchOrganisationsWithType(orgType).pipe( + tap((organisationsWithType) => + store.dispatch( + ReferenceDataActions.loadOrganisationsWithTypeSuccess({ organisationsWithType }) + ) + ), + mapTo(true) + ); diff --git a/projects/reference-data/src/guards/plea-types.guard.ts b/projects/reference-data/src/guards/plea-types.guard.ts new file mode 100644 index 0000000..d7ebc0c --- /dev/null +++ b/projects/reference-data/src/guards/plea-types.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getPleaStatusTypes, ReferenceDataState } from '../reducers'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class PleaTypesGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasPleaTypesInStore() { + return this.store.pipe( + map(getPleaStatusTypes), + map((pleaStatusTypes) => pleaStatusTypes.length > 0), + take(1) + ); + } + + hasPleaTypesInApi() { + return this.referenceData.fetchPleaTypes().pipe( + tap((pleaStatusTypes) => + this.store.dispatch(ReferenceDataActions.loadPleaTypesSuccess({ pleaStatusTypes })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasPleaTypesInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasPleaTypesInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/police-force.guard.ts b/projects/reference-data/src/guards/police-force.guard.ts new file mode 100644 index 0000000..23a62f1 --- /dev/null +++ b/projects/reference-data/src/guards/police-force.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getPoliceForceList, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class PoliceForceListGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasPoliceForceListInStore() { + return this.store.pipe( + map(getPoliceForceList), + map((policeForceList) => !!policeForceList), + take(1) + ); + } + + hasPoliceForceListInApi() { + return this.referenceData.fetchPoliceForceList().pipe( + tap((policeForceList) => + this.store.dispatch(ReferenceDataActions.loadPoliceForceListSuccess({ policeForceList })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasPoliceForceListInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasPoliceForceListInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/police-ranks.guard.ts b/projects/reference-data/src/guards/police-ranks.guard.ts new file mode 100644 index 0000000..a52b2e6 --- /dev/null +++ b/projects/reference-data/src/guards/police-ranks.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, mapTo, switchMap, tap, take, map } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions'; +import { getPoliceRanks, ReferenceDataState } from '../reducers'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class PoliceRanksGuard implements CanActivate { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasPoliceRanksInStore() { + return this.store.pipe( + map(getPoliceRanks), + map(policeRanks => !!policeRanks && !!policeRanks.length), + take(1) + ); + } + + hasPoliceRanksInApi() { + return this.referenceData.fetchPoliceRanks().pipe( + tap(policeRanks => + this.store.dispatch(ReferenceDataActions.loadPoliceRanksSuccess({ policeRanks })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasPoliceRanksInStore().pipe( + switchMap(hasInStore => (hasInStore ? of(true) : this.hasPoliceRanksInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/prosecutors.guard.ts b/projects/reference-data/src/guards/prosecutors.guard.ts new file mode 100644 index 0000000..b2dfe57 --- /dev/null +++ b/projects/reference-data/src/guards/prosecutors.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getProsecutors, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class ProsecutorsGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasProsecutorsInStore() { + return this.store.pipe( + map(getProsecutors), + map((prosecutors) => !!prosecutors), + take(1) + ); + } + + hasProsecutorsInApi() { + return this.referenceData.fetchProsecutors().pipe( + tap((prosecutors) => + this.store.dispatch(ReferenceDataActions.loadProsecutorsSuccess({ prosecutors })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasProsecutorsInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasProsecutorsInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/public-holidays.guard.ts b/projects/reference-data/src/guards/public-holidays.guard.ts new file mode 100644 index 0000000..f023a1c --- /dev/null +++ b/projects/reference-data/src/guards/public-holidays.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getPublicHolidays, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class PublicHolidaysGuard implements CanActivate { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasPublicHolidaysInStore() { + return this.store.pipe( + map(getPublicHolidays), + map((publicHolidays) => !!publicHolidays), + take(1) + ); + } + + hasPublicHolidaysInApi() { + return this.referenceData.fetchPublicHolidays().pipe( + tap((publicHolidays) => + this.store.dispatch(ReferenceDataActions.loadPublicHolidaysSuccess({ publicHolidays })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasPublicHolidaysInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasPublicHolidaysInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/rota-business-types.guard.ts b/projects/reference-data/src/guards/rota-business-types.guard.ts new file mode 100644 index 0000000..c08030a --- /dev/null +++ b/projects/reference-data/src/guards/rota-business-types.guard.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getRotaBusinessTypes, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class RotaBusinessTypesGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasRotaBusinessTypesInStore() { + return this.store.pipe( + map(getRotaBusinessTypes), + map((rotaBusinessTypes) => rotaBusinessTypes.length > 0), + take(1) + ); + } + + hasRotaBusinessTypesInApi() { + return this.referenceData.fetchRotaBusinessTypes().pipe( + tap((rotaBusinessTypes) => + this.store.dispatch( + ReferenceDataActions.loadRotaBusinessTypesSuccess({ rotaBusinessTypes }) + ) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasRotaBusinessTypesInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasRotaBusinessTypesInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/special-requirement.guard.ts b/projects/reference-data/src/guards/special-requirement.guard.ts new file mode 100644 index 0000000..db184a8 --- /dev/null +++ b/projects/reference-data/src/guards/special-requirement.guard.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getSpecialRequirements, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class SpecialRequirementsGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasSpecialRequirementsInStore() { + return this.store.pipe( + map(getSpecialRequirements), + map((specialRequirements) => !!specialRequirements), + take(1) + ); + } + + hasSpecialRequirementsInApi() { + return this.referenceData.fetchSpecialRequirements().pipe( + tap((specialRequirements) => + this.store.dispatch( + ReferenceDataActions.loadSpecialRequirementsSuccess({ specialRequirements }) + ) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasSpecialRequirementsInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasSpecialRequirementsInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/trial-types.guard.ts b/projects/reference-data/src/guards/trial-types.guard.ts new file mode 100644 index 0000000..23db633 --- /dev/null +++ b/projects/reference-data/src/guards/trial-types.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getTrialTypes, ReferenceDataState } from '../reducers'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class TrialTypesGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasTrialTypesInStore() { + return this.store.pipe( + map(getTrialTypes), + map((trialTypes) => trialTypes.length > 0), + take(1) + ); + } + + hasTrialTypesInApi() { + return this.referenceData.fetchTrialTypes().pipe( + tap((trialTypes) => + this.store.dispatch(ReferenceDataActions.loadTrialTypesSuccess({ trialTypes })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasTrialTypesInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasTrialTypesInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/guards/witness-care-unit.guard.ts b/projects/reference-data/src/guards/witness-care-unit.guard.ts new file mode 100644 index 0000000..a769dc2 --- /dev/null +++ b/projects/reference-data/src/guards/witness-care-unit.guard.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { ReferenceDataActions } from '../actions/index'; +import { getWitnessCareUnits, ReferenceDataState } from '../reducers/index'; +import { ReferenceDataService } from '../services/reference-data.service'; + +@Injectable() +export class WitnessCareUnitGuard { + constructor( + private referenceData: ReferenceDataService, + private router: Router, + private store: Store + ) {} + + hasWitnessCareUnitsInStore() { + return this.store.pipe( + map(getWitnessCareUnits), + map((witnessCareUnits) => !!witnessCareUnits), + take(1) + ); + } + + hasWitnessCareUnitsInApi() { + return this.referenceData.fetchWitnessCareUnits().pipe( + tap((witnessCareUnits) => + this.store.dispatch(ReferenceDataActions.loadWitnessCareUnitsSuccess({ witnessCareUnits })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { referenceDataErrorRedirectTo } = route.data as { + referenceDataErrorRedirectTo?: string; + }; + return this.hasWitnessCareUnitsInStore().pipe( + switchMap((hasInStore) => (hasInStore ? of(true) : this.hasWitnessCareUnitsInApi())), + tap({ + error: () => { + if (referenceDataErrorRedirectTo) { + this.router.navigateByUrl(referenceDataErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/reference-data/src/helpers/judiciary-type.helper.ts b/projects/reference-data/src/helpers/judiciary-type.helper.ts new file mode 100644 index 0000000..7872085 --- /dev/null +++ b/projects/reference-data/src/helpers/judiciary-type.helper.ts @@ -0,0 +1,193 @@ +/** + * Following enum used to assign judiciaries by its types. + */ +export enum JudiciaryTypesGroups { + CIRCUIT_JUDGE = 'CIRCUIT_JUDGE', + DISTRICT_JUDGE = 'DISTRICT_JUDGE', + DEPUTY_DISTRICT_JUDGE = 'DEPUTY_DISTRICT_JUDGE', + RECORDER = 'RECORDER', + MAGISTRATE = 'MAGISTRATE' +} + +/** + * Types of JudiciaryTypesGroups enum as + */ +export type JudiciaryTypeGroup = keyof typeof JudiciaryTypesGroups; + +/** + * Following type is to represent values of [judiciaryType] property on reference data fetch judiciaries endpoint + */ +export type JudiciaryTypePayload = + | '' + | 'Judge' + | 'District Judge' + | 'Deputy District Judge' + | 'Recorder' + | 'Magistrate'; + +/** + * Following type is represent all judiciary types on reference data + */ +export type RefDataJudiciaryType = + | 'Magistrate' + | 'Assistant Judge Advocate General' + | 'Deputy Circuit Judge' + | 'Judge Advocate General' + | 'Recorder' + | 'Circuit Judge' + | 'Circuit Judge, Central Criminal Court' + | 'Common Serjeant' + | 'Court of Appeal Judge' + | 'Court of Appeal Judge- Sitting in Retirement' + | 'Deputy High Court Judge' + | 'High Court Judge' + | 'High Court Judge- Sitting in Retirement' + | 'Lord Chief Justice' + | 'President of the Queen’s Bench Division' + | 'Recorder of London' + | 'Senior Circuit Judge' + | 'Specialist Circuit Judge' + | 'Senior Presiding Judge' + | 'Vice President of the QBD' + | 'Deputy Senior District Judge (Chief Magistrate)' + | 'District Judge (MC)' + | 'Senior District Judge (Chief Magistrate)' + | 'Deputy District Judge (MC)- Fee paid' + | 'Deputy District Judge (MC)- Sitting in Retirement' + | 'Deputy District Judge (MC) (Sitting in Retirement)' + | 'District Judge (MC) (sitting in retirement)' + | 'High Court Judge (also known as Puisne Judges)' + | 'Deputy District Judge (MC)' + | 'District Judge (MC) (sitting in retirement).' + | 'High Court Judge (sitting in retirement)' + | 'Lady Justice of Appeal' + | 'Lady Justice of Appeal (sitting in retirement)' + | 'Registrar of Criminal Appeals' + | 'President of the Queen’s Bench' + | 'Circuit Judge (sitting in retirement)' + | 'Lord Justice of Appeal' + | 'Lord Justice of Appeal (sitting in retirement)' + | 'President of the King’s Bench Division' + | 'Court of Appeal Judge (sitting in retirement)' + | 'Lady Chief Justice' + | 'Assistant Recorder' + | 'Assistant Judge Advocate General (SiR)' + | 'Deputy Judge Advocate General' + | 'Assistant Judge Advocate General (sitting In retirement)' + | 'Recorder (sitting in retirement)' + | 'Vice Judge Advocate General'; + +/** + * Gets the judiciary type group and converts it to understandable way of ref data service payload + * @param judiciaryTypeGroup group name to be converted + * @returns converted understandable endpoint string + */ +export const judiciaryTypeGroupToJudiciaryTypePayload = ( + judiciaryTypeGroup: JudiciaryTypeGroup +): JudiciaryTypePayload => { + if (!judiciaryTypeGroup) { + return ''; + } + + const judiciaryGroupMap: { [key in JudiciaryTypesGroups]: JudiciaryTypePayload } = { + CIRCUIT_JUDGE: 'Judge', + DISTRICT_JUDGE: 'District Judge', + DEPUTY_DISTRICT_JUDGE: 'Deputy District Judge', + RECORDER: 'Recorder', + MAGISTRATE: 'Magistrate' + }; + + return judiciaryGroupMap[judiciaryTypeGroup] || ''; +}; + +/** + * Gets the reference data judiciary type and converts it to judiciary type group + * @param refDataJudiciaryType ref data judiciary type + * @returns judiciaryTypeGroup where ref data judiciary type belongs to + */ +export const mapRefDataJudiciaryToJudiciaryType = ( + refDataJudiciaryType: RefDataJudiciaryType +): JudiciaryTypeGroup | null => { + const judiciaryMapping: { names: RefDataJudiciaryType[]; value: JudiciaryTypeGroup }[] = [ + { + names: ['Magistrate'], + value: 'MAGISTRATE' + }, + { + names: [ + 'Assistant Judge Advocate General', + 'Deputy Circuit Judge', + 'Judge Advocate General', + 'Recorder', + 'Assistant Recorder', + 'Assistant Judge Advocate General (SiR)', + 'Deputy Judge Advocate General', + 'Assistant Judge Advocate General (sitting In retirement)', + 'Recorder (sitting in retirement)', + 'Vice Judge Advocate General' + ], + value: 'RECORDER' + }, + { + names: [ + 'Circuit Judge', + 'Circuit Judge, Central Criminal Court', + 'Common Serjeant', + 'Court of Appeal Judge', + 'Court of Appeal Judge- Sitting in Retirement', + 'Deputy High Court Judge', + 'High Court Judge', + 'High Court Judge- Sitting in Retirement', + 'Lord Chief Justice', + 'President of the Queen’s Bench Division', + 'Recorder of London', + 'Senior Circuit Judge', + 'Specialist Circuit Judge', + 'Senior Presiding Judge', + 'Vice President of the QBD', + 'High Court Judge (also known as Puisne Judges)', + 'High Court Judge (sitting in retirement)', + 'Lady Justice of Appeal', + 'Lady Justice of Appeal (sitting in retirement)', + 'Registrar of Criminal Appeals', + 'President of the Queen’s Bench', + 'Circuit Judge (sitting in retirement)', + 'Lord Justice of Appeal', + 'Lord Justice of Appeal (sitting in retirement)', + 'President of the King’s Bench Division', + 'Court of Appeal Judge (sitting in retirement)', + 'Lady Chief Justice' + ], + value: 'CIRCUIT_JUDGE' + }, + { + names: [ + 'Deputy Senior District Judge (Chief Magistrate)', + 'District Judge (MC)', + 'Senior District Judge (Chief Magistrate)', + 'District Judge (MC) (sitting in retirement)', + 'District Judge (MC) (sitting in retirement).' + ], + value: 'DISTRICT_JUDGE' + }, + { + names: [ + 'Deputy District Judge (MC)', + 'Deputy District Judge (MC)- Fee paid', + 'Deputy District Judge (MC)- Sitting in Retirement', + 'Deputy District Judge (MC) (Sitting in Retirement)' + ], + value: 'DEPUTY_DISTRICT_JUDGE' + } + ]; + + const judiciary = judiciaryMapping.find((mapping) => + mapping.names.includes(refDataJudiciaryType) + ); + + if (!judiciary) { + return null; + } + + return judiciary.value; +}; diff --git a/projects/reference-data/src/index.ts b/projects/reference-data/src/index.ts new file mode 100644 index 0000000..4aaf8f9 --- /dev/null +++ b/projects/reference-data/src/index.ts @@ -0,0 +1 @@ +export * from './public_api'; diff --git a/projects/reference-data/src/mocks/application-type.mocks.ts b/projects/reference-data/src/mocks/application-type.mocks.ts new file mode 100644 index 0000000..85b9e89 --- /dev/null +++ b/projects/reference-data/src/mocks/application-type.mocks.ts @@ -0,0 +1,53 @@ +import { + BreachType, + CourtApplicationType, + LinkType, + OffenceActiveOrderType, + SummonsTemplateType +} from '../reference-data.interfaces'; + +export const applicationTypeMockOne: CourtApplicationType = { + id: '00380a1d-65a8-4dc1-bf08-b1421f51d30e', + code: 'CODE01', + type: 'Application Type 1', + categoryCode: '*', + linkType: LinkType.STANDALONE, + jurisdiction: '*', + hearingCode: 'APN', + appealFlag: false, + applicantAppellantFlag: false, + breachType: BreachType.NOT_APPLICABLE, + commrOfOathFlag: false, + courtExtractAvlFlag: false, + courtOfAppealFlag: false, + offenceActiveOrder: OffenceActiveOrderType.NOT_APPLICABLE, + pleaApplicableFlag: false, + prosecutorThirdPartyFlag: false, + summonsTemplateType: SummonsTemplateType.NOT_APPLICABLE, + spiOutApplicableFlag: false, + resentencingActivationCode: 'ACTCODEX', + prefix: 'prefix' +}; + +export const applicationTypeMockTwo: CourtApplicationType = { + id: '003806bd-bdc8-4908-ac63-bb7575f6a196', + code: 'CODE02', + type: 'Application Type 2', + categoryCode: '*', + linkType: LinkType.STANDALONE, + jurisdiction: '*', + hearingCode: 'REV', + appealFlag: false, + applicantAppellantFlag: false, + breachType: BreachType.NOT_APPLICABLE, + commrOfOathFlag: false, + courtExtractAvlFlag: false, + courtOfAppealFlag: false, + offenceActiveOrder: OffenceActiveOrderType.NOT_APPLICABLE, + pleaApplicableFlag: false, + prosecutorThirdPartyFlag: false, + summonsTemplateType: SummonsTemplateType.NOT_APPLICABLE, + spiOutApplicableFlag: false, + resentencingActivationCode: 'ACTCODEY', + prefix: 'prefix2' +}; diff --git a/projects/reference-data/src/mocks/hearing-type.mocks.ts b/projects/reference-data/src/mocks/hearing-type.mocks.ts new file mode 100644 index 0000000..0f6f447 --- /dev/null +++ b/projects/reference-data/src/mocks/hearing-type.mocks.ts @@ -0,0 +1,34 @@ +import { HearingType } from '../reference-data.interfaces'; + +export const hearingTypeMockOne: HearingType = { + id: '06b0c2bf-3f98-46ed-ab7e-56efaf9ecced', + seqId: 1, + hearingCode: 'PTP', + hearingDescription: 'Plea & Trial Preparation', + welshHearingDescription: 'Diffynnydd i fynychu i', + defaultDurationMin: 20, + validFrom: null, + validTo: null +}; + +export const hearingTypeMockTwo: HearingType = { + id: '9cc41e45-b594-4ba6-906e-1a4626b08fed', + seqId: 2, + hearingCode: 'FPTP', + hearingDescription: 'Further Plea & Trial Preparation', + welshHearingDescription: 'Diffynnydd i fynychu 2', + defaultDurationMin: 20, + validFrom: null, + validTo: null +}; + +export const defaultHearingTypePlaceHolder: HearingType = { + id: 'All', + hearingCode: 'All', + seqId: 0, + defaultDurationMin: 0, + welshHearingDescription: '', + hearingDescription: 'All hearing types', + magistratesFlag: true, + crownFlag: true +}; diff --git a/projects/reference-data/src/mocks/organisation-unit.mocks.ts b/projects/reference-data/src/mocks/organisation-unit.mocks.ts new file mode 100644 index 0000000..5aa6f16 --- /dev/null +++ b/projects/reference-data/src/mocks/organisation-unit.mocks.ts @@ -0,0 +1,13 @@ +import { OrganisationUnit } from '../reference-data.interfaces'; + +export const organisationUnitMockOne: OrganisationUnit = { + id: '4cc41e45-b594-5ba6-906e-1a4626b08fed', + oucodeL3Code: 'LH', + oucodeL3Name: 'Lark Hill' +}; + +export const organisationUnitMockTwo: OrganisationUnit = { + id: '3cc41e45-b594-4ba6-906e-1a4626b08fed', + oucodeL3Code: 'LCC', + oucodeL3Name: 'Liverpool Crown Court' +}; diff --git a/projects/reference-data/src/mocks/prosecutor.mocks.ts b/projects/reference-data/src/mocks/prosecutor.mocks.ts new file mode 100644 index 0000000..ac71d3d --- /dev/null +++ b/projects/reference-data/src/mocks/prosecutor.mocks.ts @@ -0,0 +1,19 @@ +import { Prosecutor } from '../reference-data.interfaces'; + +export const mockProsecutorOne: Prosecutor = { + id: '0534ee76-88f6-40e0-ba8f-53588e146675', + sequenceNumber: 1, + majorCreditorCode: 'TFL2', + shortName: 'TFL', + fullName: 'Transport for London', + nameWelsh: 'Transport for London', + oucode: 'GAFTL00', + spiInFlag: false, + spiOutFlag: true, + address: { + address1: '6th Floor Windsor House', + postcode: 'SW1H 0TL', + address2: '42-50 Victoria Street', + address3: 'London' + } +}; diff --git a/projects/reference-data/src/providers.ts b/projects/reference-data/src/providers.ts new file mode 100644 index 0000000..31a48a9 --- /dev/null +++ b/projects/reference-data/src/providers.ts @@ -0,0 +1,62 @@ +import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'; +import { ReferenceDataEffects } from './effects/reference-data.effects'; +import { ApplicationTypesGuard } from './guards/application-type.guard'; +import { AssignPrioritiesGuard } from './guards/assingn-priorities.guard'; +import { BookingTypesGuard } from './guards/booking-types.guard'; +import { ClustersGuard } from './guards/clusters.guard'; +import { CPSAreasGuard } from './guards/cps-areas.guard'; +import { CPSBusinessUnitsGuard } from './guards/cps-business-units.guard'; +import { CPSCaseStatusGuard } from './guards/cps-case-status.guard'; +import { FixedListsGuard } from './guards/fixed-lists.guard'; +import { HearingTypesGuard } from './guards/hearing-type.guard'; +import { JudiciaryGroupTypesGuard } from './guards/judiciary-group-types.guard'; +import { LocalJusticeAreasGuard } from './guards/local-justice-areas.guard'; +import { OrganisationUnitsGuard } from './guards/court-centres.guard'; +import { PleaTypesGuard } from './guards/plea-types.guard'; +import { PoliceForceListGuard } from './guards/police-force.guard'; +import { ProsecutorsGuard } from './guards/prosecutors.guard'; +import { RotaBusinessTypesGuard } from './guards/rota-business-types.guard'; +import { SpecialRequirementsGuard } from './guards/special-requirement.guard'; +import { WitnessCareUnitGuard } from './guards/witness-care-unit.guard'; +import { referenceDataReducer } from './reducers/index'; +import { ReferenceDataService } from './services/reference-data.service'; +import { TrialTypesGuard } from './guards/trial-types.guard'; +import { PoliceRanksGuard } from './public_api'; +import { PublicHolidaysGuard } from './guards/public-holidays.guard'; +import { provideState } from '@ngrx/store'; +import { provideEffects } from '@ngrx/effects'; + +export const provideReferenceDataStore = (): EnvironmentProviders => { + return makeEnvironmentProviders([ + provideState({ name: 'referenceData', reducer: referenceDataReducer }), + provideEffects(ReferenceDataEffects) + ]); +}; + +export const provideReferenceDataEnvironmentContext = (): EnvironmentProviders => { + return makeEnvironmentProviders([ + ReferenceDataService, + ApplicationTypesGuard, + AssignPrioritiesGuard, + BookingTypesGuard, + ClustersGuard, + CPSAreasGuard, + CPSBusinessUnitsGuard, + CPSCaseStatusGuard, + OrganisationUnitsGuard, + FixedListsGuard, + HearingTypesGuard, + JudiciaryGroupTypesGuard, + LocalJusticeAreasGuard, + PleaTypesGuard, + PoliceForceListGuard, + PoliceRanksGuard, + ProsecutorsGuard, + RotaBusinessTypesGuard, + SpecialRequirementsGuard, + WitnessCareUnitGuard, + TrialTypesGuard, + PublicHolidaysGuard, + provideReferenceDataStore() + ]); +}; diff --git a/projects/reference-data/src/public_api.ts b/projects/reference-data/src/public_api.ts new file mode 100644 index 0000000..51f56f7 --- /dev/null +++ b/projects/reference-data/src/public_api.ts @@ -0,0 +1,40 @@ +/* + * Public API Surface of reference-data + */ +export * from './actions/index'; +export * from './components'; +export * from './guards/application-type.guard'; +export * from './guards/assingn-priorities.guard'; +export * from './guards/booking-types.guard'; +export * from './guards/clusters.guard'; +export * from './guards/cps-areas.guard'; +export * from './guards/cps-business-units.guard'; +export * from './guards/cps-case-status.guard'; +export * from './guards/fixed-lists.guard'; +export * from './guards/court-centres.guard'; +export * from './guards/court-centre-units.gard'; +export * from './guards/hearing-type.guard'; +export * from './guards/local-justice-areas.guard'; +export * from './guards/plea-types.guard'; +export * from './guards/police-force.guard'; +export * from './guards/police-ranks.guard'; +export * from './guards/prosecutors.guard'; +export * from './guards/rota-business-types.guard'; +export * from './guards/special-requirement.guard'; +export * from './guards/witness-care-unit.guard'; +export * from './guards/judiciary-group-types.guard'; +export * from './guards/trial-types.guard'; +export * from './guards/public-holidays.guard'; +export * from './mocks/application-type.mocks'; +export * from './mocks/hearing-type.mocks'; +export * from './mocks/organisation-unit.mocks'; +export * from './mocks/prosecutor.mocks'; +export * from './helpers/judiciary-type.helper'; +export * from './reducers/index'; +export * from './services/reference-data.service'; +export * from './utils/judicial-member-name.pipe'; +export * from './utils/sort-select-options-Alphabetical'; +export * from './reference-data.interfaces'; +export * from './reference-data.module'; +export * from './guards/organisation-with-type.guard'; +export * from './providers'; diff --git a/projects/reference-data/src/reducers/__tests__/__snapshots__/index.reducer.spec.ts.snap b/projects/reference-data/src/reducers/__tests__/__snapshots__/index.reducer.spec.ts.snap new file mode 100644 index 0000000..bd69e34 --- /dev/null +++ b/projects/reference-data/src/reducers/__tests__/__snapshots__/index.reducer.spec.ts.snap @@ -0,0 +1,590 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`referenceDataReducer CPS Areas ReferenceDataActions.loadCPSAreas should install the cps areas key 1`] = ` +{ + "cpsAreas": null, +} +`; + +exports[`referenceDataReducer CPS Areas ReferenceDataActions.loadCPSAreas should not overwrite any existing cpsAreas 1`] = ` +{ + "cpsAreas": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer CPS Areas ReferenceDataActions.loadCPSAreasError should remove the cps areas key 1`] = `{}`; + +exports[`referenceDataReducer CPS Areas ReferenceDataActions.loadCPSAreasSuccess should add the cps areas to the state 1`] = ` +{ + "cpsAreas": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer CPS Business Units ReferenceDataActions.loadCPSBusinessUnits should install the cps business units key 1`] = ` +{ + "cPSBusinessUnits": null, +} +`; + +exports[`referenceDataReducer CPS Business Units ReferenceDataActions.loadCPSBusinessUnits should not overwrite any existing cpsBusinessUnits 1`] = ` +{ + "cPSBusinessUnits": [ + { + "id": "*", + }, + ], + "cpsBusinessUnits": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer CPS Business Units ReferenceDataActions.loadCPSBusinessUnitsError should remove the cps business units key 1`] = `{}`; + +exports[`referenceDataReducer CPS Business Units ReferenceDataActions.loadCPSBusinessUnitsSuccess should add the cps business units to the state 1`] = ` +{ + "cpsBusinessUnits": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer CPSCase Statuses ReferenceDataActions.loadCPSCaseStatuses should install the case statuses key 1`] = ` +{ + "cpsCaseStatuses": null, +} +`; + +exports[`referenceDataReducer CPSCase Statuses ReferenceDataActions.loadCPSCaseStatuses should not overwrite any existing cpsCaseStatuses 1`] = ` +{ + "cpsCaseStatuses": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer CPSCase Statuses ReferenceDataActions.loadCPSCaseStatusesError should remove the cps case statuses key 1`] = `{}`; + +exports[`referenceDataReducer CPSCase Statuses ReferenceDataActions.loadCPSCaseStatusesSuccess should add the cps case statuses to the state 1`] = ` +{ + "cpsCaseStatuses": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer Clusters HearingResultsActions.loadClustersError should remove the clusters key 1`] = `{}`; + +exports[`referenceDataReducer Clusters ReferenceDataActions.loadClusters should install the clusters key 1`] = ` +{ + "clusters": null, +} +`; + +exports[`referenceDataReducer Clusters ReferenceDataActions.loadClusters should not overwrite any existing clusters 1`] = ` +{ + "clusters": [ + { + "clusterCode": "code", + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer Clusters ReferenceDataActions.loadClustersSuccess should add the clusters to the state 1`] = ` +{ + "clusters": [ + { + "clusterCode": "code", + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer Local Justice Areas HearingResultsActions.loadLocalJusticeAreasError should remove the localJusticeAreas key 1`] = `{}`; + +exports[`referenceDataReducer Local Justice Areas HearingResultsActions.loadLocalJusticeAreasSuccess should add the localJusticeAreas to the state 1`] = ` +{ + "localJusticeAreas": [ + { + "clusterCode": "*", + }, + ], +} +`; + +exports[`referenceDataReducer Local Justice Areas ReferenceDataActions.loadLocalJusticeAreas should install the localJusticeAreas 1`] = ` +{ + "localJusticeAreas": null, +} +`; + +exports[`referenceDataReducer Local Justice Areas ReferenceDataActions.loadLocalJusticeAreas should not overwrite any existing localJusticeAreas 1`] = ` +{ + "localJusticeAreas": [ + { + "clusterCode": "*", + }, + ], +} +`; + +exports[`referenceDataReducer application types HearingResultsActions.loadApplicationTypesError should remove the application types key 1`] = `{}`; + +exports[`referenceDataReducer application types HearingResultsActions.loadApplicationTypesSuccess should add the application types to the state 1`] = ` +{ + "applicationTypes": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer application types ReferenceDataActions.loadApplicationTypes should install the application types key 1`] = ` +{ + "applicationTypes": null, +} +`; + +exports[`referenceDataReducer application types ReferenceDataActions.loadApplicationTypes should not overwrite any existing application types 1`] = ` +{ + "applicationTypes": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer assign priorities HearingResultsActions.loadAssignPrioritiesError should remove the assign priorities key 1`] = ` +{ + "applicationTypes": null, +} +`; + +exports[`referenceDataReducer assign priorities ReferenceDataActions.loadAssignPriorities should install the assign priorities key 1`] = ` +{ + "assignPriorities": null, +} +`; + +exports[`referenceDataReducer assign priorities ReferenceDataActions.loadAssignPriorities should not overwrite any existing assign priorities 1`] = ` +{ + "assignPriorities": [ + { + "id": "someid", + "priorityCode": "H", + "priorityValue": "High", + "seqNum": 1, + }, + ], +} +`; + +exports[`referenceDataReducer assign priorities ReferenceDataActions.loadAssignPrioritiesSuccess should add the assign priorities to the state 1`] = ` +{ + "assignPriorities": [ + { + "id": "someid", + "priorityCode": "H", + "priorityValue": "High", + "seqNum": 1, + }, + ], +} +`; + +exports[`referenceDataReducer booking types HearingResultsActions.loadBookingTypesError should remove the booking types key 1`] = ` +{ + "applicationTypes": null, +} +`; + +exports[`referenceDataReducer booking types ReferenceDataActions.loadBookingTypes should install the booking types key 1`] = ` +{ + "bookingTypes": null, +} +`; + +exports[`referenceDataReducer booking types ReferenceDataActions.loadBookingTypes should not overwrite any existing booking types 1`] = ` +{ + "bookingTypes": [ + { + "id": "someId", + "typeCode": "VL", + "typeValue": "Video Link", + }, + ], +} +`; + +exports[`referenceDataReducer booking types ReferenceDataActions.loadBookingTypesSuccess should add the booking types to the state 1`] = ` +{ + "bookingTypes": [ + { + "id": "someId", + "typeCode": "VL", + "typeValue": "Video Link", + }, + ], +} +`; + +exports[`referenceDataReducer court centres HearingResultsActions.loadOrganisationUnitsError should remove the court centres key 1`] = `{}`; + +exports[`referenceDataReducer court centres HearingResultsActions.loadOrganisationUnitsSuccess should add the court centres to the state 1`] = ` +{ + "organisationUnits": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer court centres ReferenceDataActions.loadOrganisationUnits should install the court centres key 1`] = ` +{ + "organisationUnits": null, +} +`; + +exports[`referenceDataReducer court centres ReferenceDataActions.loadOrganisationUnits should not overwrite any existing court centres 1`] = ` +{ + "organisationUnits": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer fixed lists HearingResultsActions.loadFixedListsError should remove the fixed lists key 1`] = ` +{ + "applicationTypes": null, +} +`; + +exports[`referenceDataReducer fixed lists HearingResultsActions.loadFixedListsSuccess should add the fixed lists to the state 1`] = ` +{ + "fixedLists": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer fixed lists ReferenceDataActions.loadFixedLists should install the fixed lists key 1`] = ` +{ + "fixedLists": null, +} +`; + +exports[`referenceDataReducer fixed lists ReferenceDataActions.loadFixedLists should not overwrite any existing fixed lists 1`] = ` +{ + "applicationTypes": [ + { + "id": "*", + }, + ], + "fixedLists": null, +} +`; + +exports[`referenceDataReducer hearing types HearingResultsActions.loadHearingTypesError should remove the hearing types key 1`] = `{}`; + +exports[`referenceDataReducer hearing types HearingResultsActions.loadHearingTypesSuccess should add the hearing types to the state 1`] = ` +{ + "hearingTypes": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer hearing types ReferenceDataActions.loadHearingTypes should install the hearing types key 1`] = ` +{ + "hearingTypes": null, +} +`; + +exports[`referenceDataReducer hearing types ReferenceDataActions.loadHearingTypes should not overwrite any existing hearing types 1`] = ` +{ + "hearingTypes": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer judiciary group types ReferenceDataActions.loadJudiciaryGroupTypes should install the judiciary group types key 1`] = ` +{ + "judiciaryGroupTypes": null, +} +`; + +exports[`referenceDataReducer judiciary group types ReferenceDataActions.loadJudiciaryGroupTypes should not overwrite any existing judiciary group types types 1`] = ` +{ + "judiciaryGroupTypes": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer judiciary group types ReferenceDataActions.loadJudiciaryGroupTypesError should remove a pending judiciary group types types key 1`] = `{}`; + +exports[`referenceDataReducer judiciary group types ReferenceDataActions.loadJudiciaryGroupTypesSuccess should add the judiciary group types types to the state 1`] = ` +{ + "judiciaryGroupTypes": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer plea types HearingResultsActions.loadPleaTypesError should remove a pending plea types key 1`] = `{}`; + +exports[`referenceDataReducer plea types HearingResultsActions.loadPleaTypesSuccess should add the plea types to the state 1`] = ` +{ + "pleaStatusTypes": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer plea types ReferenceDataActions.loadPleaTypes should install the plea types key 1`] = ` +{ + "pleaStatusTypes": null, +} +`; + +exports[`referenceDataReducer plea types ReferenceDataActions.loadPleaTypes should not overwrite any existing plea types 1`] = ` +{ + "pleaStatusTypes": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer policeForceList ReferenceDataActions.loadPoliceForceList should install the police force list 1`] = ` +{ + "policeForceList": null, +} +`; + +exports[`referenceDataReducer policeForceList ReferenceDataActions.loadPoliceForceList should not overwrite any existing police force list 1`] = ` +{ + "policeForceList": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer policeForceList ReferenceDataActions.loadPoliceForceListError should remove the policeForceList key 1`] = `{}`; + +exports[`referenceDataReducer policeForceList ReferenceDataActions.loadPoliceForceListSuccess should add the policeForceList to the state 1`] = ` +{ + "policeForceList": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer prosecutors HearingResultsActions.loadProsecutorsError should remove the prosecutors key 1`] = `{}`; + +exports[`referenceDataReducer prosecutors HearingResultsActions.loadProsecutorsSuccess should add the prosecutors to the state 1`] = ` +{ + "prosecutors": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer prosecutors ReferenceDataActions.loadProsecutors should install the prosecutors 1`] = ` +{ + "prosecutors": null, +} +`; + +exports[`referenceDataReducer prosecutors ReferenceDataActions.loadProsecutors should not overwrite any existing prosecutors 1`] = ` +{ + "prosecutors": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer rota business types HearingResultsActions.loadRotaBusinessTypesError should remove a pending rota business types key 1`] = `{}`; + +exports[`referenceDataReducer rota business types HearingResultsActions.loadRotaBusinessTypesSuccess should add the rota business types to the state 1`] = ` +{ + "rotaBusinessTypes": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer rota business types ReferenceDataActions.loadRotaBusinessTypes should install the prosecutors 1`] = ` +{ + "rotaBusinessTypes": null, +} +`; + +exports[`referenceDataReducer rota business types ReferenceDataActions.loadRotaBusinessTypes should not overwrite any existing rota business types 1`] = ` +{ + "rotaBusinessTypes": [ + { + "id": "*", + }, + ], +} +`; + +exports[`referenceDataReducer selectors Judiciary Group Types getJudiciaryGroupTypes should select an empty array when no judiciary group types 1`] = `undefined`; + +exports[`referenceDataReducer selectors Judiciary Group Types getJudiciaryGroupTypes should select judiciary group types 1`] = ` +[ + { + "id": "*", + }, +] +`; + +exports[`referenceDataReducer selectors Plea Types getPleaTypes should select an empty array when no plea types exist 1`] = `[]`; + +exports[`referenceDataReducer selectors Plea Types getPleaTypes should select the plea types 1`] = ` +[ + { + "id": "*", + }, +] +`; + +exports[`referenceDataReducer selectors Trial Types getTrialTypes should select an empty array when no trial types exist 1`] = `[]`; + +exports[`referenceDataReducer selectors Trial Types getTrialTypes should select the trial types 1`] = ` +[ + { + "id": "*", + }, +] +`; + +exports[`referenceDataReducer selectors Witness care units getWitnessCareUnits should select an empty array when no witness care units 1`] = `undefined`; + +exports[`referenceDataReducer selectors Witness care units getWitnessCareUnits should select witness care units 1`] = ` +[ + { + "id": "*", + }, +] +`; + +exports[`referenceDataReducer selectors application types getApplicationTypes should select the application types 1`] = ` +[ + { + "id": "*", + }, +] +`; + +exports[`referenceDataReducer selectors court centres getOrganisationUnits should select the court centres 1`] = ` +[ + { + "id": "*", + }, +] +`; + +exports[`referenceDataReducer selectors hearing types getHearingTypes should select the hearing types 1`] = ` +[ + { + "id": "*", + }, +] +`; + +exports[`referenceDataReducer selectors prosecutors getProsecutors should select the prosecutors 1`] = ` +[ + { + "id": "*", + }, +] +`; + +exports[`referenceDataReducer selectors special requirements HearingResultsActions.loadSpecialRequirementsError should remove the special requirements key 1`] = ` +{ + "applicationTypes": null, +} +`; + +exports[`referenceDataReducer selectors special requirements ReferenceDataActions.loadBookingTypesSuccess should add the special requirements to the state 1`] = ` +{ + "specialRequirements": [ + { + "id": "someId", + "requirementCode": "AOC", + "requirementValue": "Availability of a Cell", + }, + ], +} +`; + +exports[`referenceDataReducer selectors special requirements ReferenceDataActions.loadSpecialRequirements should install the special requirements key 1`] = ` +{ + "specialRequirements": null, +} +`; + +exports[`referenceDataReducer selectors special requirements ReferenceDataActions.loadSpecialRequirements should not overwrite any special requirements types 1`] = ` +{ + "bookingTypes": [ + { + "id": "someId", + "typeCode": "VL", + "typeValue": "Video Link", + }, + ], + "specialRequirements": null, +} +`; + +exports[`referenceDataReducer undefined action should return the default state 1`] = `{}`; diff --git a/projects/reference-data/src/reducers/__tests__/index.reducer.spec.ts b/projects/reference-data/src/reducers/__tests__/index.reducer.spec.ts new file mode 100644 index 0000000..67864ba --- /dev/null +++ b/projects/reference-data/src/reducers/__tests__/index.reducer.spec.ts @@ -0,0 +1,1176 @@ +import { ReferenceDataActions } from '../../actions'; +import { + Cluster, + CourtApplicationType, + CPSArea, + CPSBusinessUnit, + CPSCaseStatus, + FixedList, + HearingType, + JudiciaryGroupType, + LocalJusticeArea, + OrganisationUnit, + PleaType, + PoliceForce, + Prosecutor, + RotaBusinessType, + RotaBusinessTypeCode, + TrialType, + WitnessCareUnit +} from '../../reference-data.interfaces'; +import * as fromReferenceData from '../index'; + +describe('referenceDataReducer', () => { + describe('undefined action', () => { + it('should return the default state', () => { + const result = fromReferenceData.referenceDataReducer(undefined, {} as any); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('application types', () => { + describe('ReferenceDataActions.loadApplicationTypes', () => { + it('should install the application types key', () => { + const action = ReferenceDataActions.loadApplicationTypes(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing application types', () => { + const action = ReferenceDataActions.loadApplicationTypes(); + const result = fromReferenceData.referenceDataReducer( + { applicationTypes: [{ id: '*' }] as CourtApplicationType[] }, + action + ); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadApplicationTypesSuccess', () => { + it('should add the application types to the state', () => { + const action = ReferenceDataActions.loadApplicationTypesSuccess({ + applicationTypes: [{ id: '*' }] as CourtApplicationType[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadApplicationTypesError', () => { + it('should remove the application types key', () => { + const action = ReferenceDataActions.loadApplicationTypesError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ applicationTypes: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('assign priorities', () => { + describe('ReferenceDataActions.loadAssignPriorities', () => { + it('should install the assign priorities key', () => { + const action = ReferenceDataActions.loadAssignPriorities(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing assign priorities', () => { + const action = ReferenceDataActions.loadAssignPriorities(); + const result = fromReferenceData.referenceDataReducer( + { + assignPriorities: [ + { id: 'someid', priorityCode: 'H', priorityValue: 'High', seqNum: 1 } + ] + }, + action + ); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadAssignPrioritiesSuccess', () => { + it('should add the assign priorities to the state', () => { + const action = ReferenceDataActions.loadAssignPrioritiesSuccess({ + assignPriorities: [{ id: 'someid', priorityCode: 'H', priorityValue: 'High', seqNum: 1 }] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadAssignPrioritiesError', () => { + it('should remove the assign priorities key', () => { + const action = ReferenceDataActions.loadAssignPrioritiesError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ applicationTypes: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('booking types', () => { + describe('ReferenceDataActions.loadBookingTypes', () => { + it('should install the booking types key', () => { + const action = ReferenceDataActions.loadBookingTypes(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing booking types', () => { + const action = ReferenceDataActions.loadBookingTypes(); + const result = fromReferenceData.referenceDataReducer( + { bookingTypes: [{ id: 'someId', typeCode: 'VL', typeValue: 'Video Link' }] }, + action + ); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadBookingTypesSuccess', () => { + it('should add the booking types to the state', () => { + const action = ReferenceDataActions.loadBookingTypesSuccess({ + bookingTypes: [{ id: 'someId', typeCode: 'VL', typeValue: 'Video Link' }] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadBookingTypesError', () => { + it('should remove the booking types key', () => { + const action = ReferenceDataActions.loadBookingTypesError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ applicationTypes: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('Clusters', () => { + describe('ReferenceDataActions.loadClusters', () => { + it('should install the clusters key', () => { + const action = ReferenceDataActions.loadClusters(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing clusters', () => { + const action = ReferenceDataActions.loadClusters(); + const result = fromReferenceData.referenceDataReducer( + { clusters: [{ id: '*', clusterCode: 'code' }] as Cluster[] }, + action + ); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadClustersSuccess', () => { + it('should add the clusters to the state', () => { + const action = ReferenceDataActions.loadClustersSuccess({ + clusters: [{ id: '*', clusterCode: 'code' }] as Cluster[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadClustersError', () => { + it('should remove the clusters key', () => { + const action = ReferenceDataActions.loadClustersError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ clusters: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('CPS Areas', () => { + describe('ReferenceDataActions.loadCPSAreas', () => { + it('should install the cps areas key', () => { + const action = ReferenceDataActions.loadCPSAreas(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing cpsAreas', () => { + const action = ReferenceDataActions.loadCPSAreas(); + const result = fromReferenceData.referenceDataReducer( + { cpsAreas: [{ id: '*' }] as CPSArea[] }, + action + ); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadCPSAreasSuccess', () => { + it('should add the cps areas to the state', () => { + const action = ReferenceDataActions.loadCPSAreasSuccess({ + cpsAreas: [{ id: '*' }] as CPSArea[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadCPSAreasError', () => { + it('should remove the cps areas key', () => { + const action = ReferenceDataActions.loadCPSAreasError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ cpsAreas: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('CPS Business Units', () => { + describe('ReferenceDataActions.loadCPSBusinessUnits', () => { + it('should install the cps business units key', () => { + const action = ReferenceDataActions.loadCPSBusinessUnits(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing cpsBusinessUnits', () => { + const action = ReferenceDataActions.loadCPSBusinessUnits(); + const result = fromReferenceData.referenceDataReducer( + { cpsBusinessUnits: [{ id: '*' }] as CPSBusinessUnit[] }, + action + ); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadCPSBusinessUnitsSuccess', () => { + it('should add the cps business units to the state', () => { + const action = ReferenceDataActions.loadCPSBusinessUnitsSuccess({ + cpsBusinessUnits: [{ id: '*' }] as CPSBusinessUnit[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadCPSBusinessUnitsError', () => { + it('should remove the cps business units key', () => { + const action = ReferenceDataActions.loadCPSBusinessUnitsError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ cpsBusinessUnits: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('fixed lists', () => { + describe('ReferenceDataActions.loadFixedLists', () => { + it('should install the fixed lists key', () => { + const action = ReferenceDataActions.loadFixedLists(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing fixed lists', () => { + const action = ReferenceDataActions.loadFixedLists(); + const result = fromReferenceData.referenceDataReducer( + { applicationTypes: [{ id: '*' }] as CourtApplicationType[] }, + action + ); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadFixedListsSuccess', () => { + it('should add the fixed lists to the state', () => { + const action = ReferenceDataActions.loadFixedListsSuccess({ + fixedLists: [{ id: '*' }] as FixedList[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadFixedListsError', () => { + it('should remove the fixed lists key', () => { + const action = ReferenceDataActions.loadFixedListsError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ applicationTypes: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('CPSCase Statuses', () => { + describe('ReferenceDataActions.loadCPSCaseStatuses', () => { + it('should install the case statuses key', () => { + const action = ReferenceDataActions.loadCPSCaseStatuses(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing cpsCaseStatuses', () => { + const action = ReferenceDataActions.loadCPSCaseStatuses(); + const result = fromReferenceData.referenceDataReducer( + { cpsCaseStatuses: [{ id: '*' }] as CPSCaseStatus[] }, + action + ); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadCPSCaseStatusesSuccess', () => { + it('should add the cps case statuses to the state', () => { + const action = ReferenceDataActions.loadCPSCaseStatusesSuccess({ + cpsCaseStatuses: [{ id: '*' }] as CPSCaseStatus[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadCPSCaseStatusesError', () => { + it('should remove the cps case statuses key', () => { + const action = ReferenceDataActions.loadCPSCaseStatusesError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ cpsCaseStatuses: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('hearing types', () => { + describe('ReferenceDataActions.loadHearingTypes', () => { + it('should install the hearing types key', () => { + const action = ReferenceDataActions.loadHearingTypes(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing hearing types', () => { + const action = ReferenceDataActions.loadHearingTypes(); + const result = fromReferenceData.referenceDataReducer( + { hearingTypes: [{ id: '*' }] as HearingType[] }, + action + ); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadHearingTypesSuccess', () => { + it('should add the hearing types to the state', () => { + const action = ReferenceDataActions.loadHearingTypesSuccess({ + hearingTypes: [{ id: '*' }] as HearingType[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadHearingTypesError', () => { + it('should remove the hearing types key', () => { + const action = ReferenceDataActions.loadHearingTypesError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ hearingTypes: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('court centres', () => { + describe('ReferenceDataActions.loadOrganisationUnits', () => { + it('should install the court centres key', () => { + const action = ReferenceDataActions.loadOrganisationUnits(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing court centres', () => { + const action = ReferenceDataActions.loadOrganisationUnits(); + const result = fromReferenceData.referenceDataReducer( + { organisationUnits: [{ id: '*' }] as OrganisationUnit[] }, + action + ); + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadOrganisationUnitsSuccess', () => { + it('should add the court centres to the state', () => { + const action = ReferenceDataActions.loadOrganisationUnitsSuccess({ + organisationUnits: [{ id: '*' }] as OrganisationUnit[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadOrganisationUnitsError', () => { + it('should remove the court centres key', () => { + const action = ReferenceDataActions.loadOrganisationUnitsError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ organisationUnits: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('Local Justice Areas', () => { + describe('ReferenceDataActions.loadLocalJusticeAreas', () => { + it('should install the localJusticeAreas', () => { + const action = ReferenceDataActions.loadLocalJusticeAreas(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing localJusticeAreas', () => { + const action = ReferenceDataActions.loadLocalJusticeAreas(); + const result = fromReferenceData.referenceDataReducer( + { localJusticeAreas: [{ clusterCode: '*' }] as LocalJusticeArea[] }, + action + ); + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadLocalJusticeAreasSuccess', () => { + it('should add the localJusticeAreas to the state', () => { + const action = ReferenceDataActions.loadLocalJusticeAreasSuccess({ + localJusticeAreas: [{ clusterCode: '*' }] as LocalJusticeArea[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadLocalJusticeAreasError', () => { + it('should remove the localJusticeAreas key', () => { + const action = ReferenceDataActions.loadLocalJusticeAreasError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ localJusticeAreas: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('policeForceList', () => { + describe('ReferenceDataActions.loadPoliceForceList', () => { + it('should install the police force list', () => { + const action = ReferenceDataActions.loadPoliceForceList(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing police force list', () => { + const action = ReferenceDataActions.loadPoliceForceList(); + const result = fromReferenceData.referenceDataReducer( + { policeForceList: [{ id: '*' }] as PoliceForce[] }, + action + ); + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadPoliceForceListSuccess', () => { + it('should add the policeForceList to the state', () => { + const action = ReferenceDataActions.loadPoliceForceListSuccess({ + policeForceList: [{ id: '*' }] as PoliceForce[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadPoliceForceListError', () => { + it('should remove the policeForceList key', () => { + const action = ReferenceDataActions.loadPoliceForceListError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ policeForceList: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('prosecutors', () => { + describe('ReferenceDataActions.loadProsecutors', () => { + it('should install the prosecutors', () => { + const action = ReferenceDataActions.loadProsecutors(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing prosecutors', () => { + const action = ReferenceDataActions.loadProsecutors(); + const result = fromReferenceData.referenceDataReducer( + { prosecutors: [{ id: '*' }] as Prosecutor[] }, + action + ); + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadProsecutorsSuccess', () => { + it('should add the prosecutors to the state', () => { + const action = ReferenceDataActions.loadProsecutorsSuccess({ + prosecutors: [{ id: '*' }] as Prosecutor[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadProsecutorsError', () => { + it('should remove the prosecutors key', () => { + const action = ReferenceDataActions.loadProsecutorsError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ prosecutors: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('rota business types', () => { + describe('ReferenceDataActions.loadRotaBusinessTypes', () => { + it('should install the prosecutors', () => { + const action = ReferenceDataActions.loadRotaBusinessTypes(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing rota business types', () => { + const action = ReferenceDataActions.loadRotaBusinessTypes(); + const result = fromReferenceData.referenceDataReducer( + { rotaBusinessTypes: [{ id: '*' }] as RotaBusinessType[] }, + action + ); + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadRotaBusinessTypesSuccess', () => { + it('should add the rota business types to the state', () => { + const action = ReferenceDataActions.loadRotaBusinessTypesSuccess({ + rotaBusinessTypes: [{ id: '*' }] as RotaBusinessType[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadRotaBusinessTypesError', () => { + it('should remove a pending rota business types key', () => { + const action = ReferenceDataActions.loadRotaBusinessTypesError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ rotaBusinessTypes: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('plea types', () => { + describe('ReferenceDataActions.loadPleaTypes', () => { + it('should install the plea types key', () => { + const action = ReferenceDataActions.loadPleaTypes(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing plea types', () => { + const action = ReferenceDataActions.loadPleaTypes(); + const result = fromReferenceData.referenceDataReducer( + { pleaStatusTypes: [{ id: '*' }] as PleaType[] }, + action + ); + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadPleaTypesSuccess', () => { + it('should add the plea types to the state', () => { + const action = ReferenceDataActions.loadPleaTypesSuccess({ + pleaStatusTypes: [{ id: '*' }] as PleaType[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadPleaTypesError', () => { + it('should remove a pending plea types key', () => { + const action = ReferenceDataActions.loadPleaTypesError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ pleaStatusTypes: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('judiciary group types', () => { + describe('ReferenceDataActions.loadJudiciaryGroupTypes', () => { + it('should install the judiciary group types key', () => { + const action = ReferenceDataActions.loadJudiciaryGroupTypes(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any existing judiciary group types types', () => { + const action = ReferenceDataActions.loadJudiciaryGroupTypes(); + const result = fromReferenceData.referenceDataReducer( + { judiciaryGroupTypes: [{ id: '*' }] as JudiciaryGroupType[] }, + action + ); + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadJudiciaryGroupTypesSuccess', () => { + it('should add the judiciary group types types to the state', () => { + const action = ReferenceDataActions.loadJudiciaryGroupTypesSuccess({ + judiciaryGroupTypes: [{ id: '*' }] as JudiciaryGroupType[] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadJudiciaryGroupTypesError', () => { + it('should remove a pending judiciary group types types key', () => { + const action = ReferenceDataActions.loadJudiciaryGroupTypesError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer( + { judiciaryGroupTypes: null }, + action + ); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('selectors', () => { + describe('application types', () => { + describe('getApplicationTypes', () => { + it('should select the application types', () => { + expect( + fromReferenceData.getApplicationTypes({ + referenceData: { + applicationTypes: [{ id: '*' }] as CourtApplicationType[] + } + }) + ).toMatchSnapshot(); + }); + }); + + describe('getApplicationTypesFetching', () => { + it('should select the fetching state of the application types', () => { + expect( + fromReferenceData.getApplicationTypesFetching({ + referenceData: { applicationTypes: null } + }) + ).toEqual(true); + expect( + fromReferenceData.getApplicationTypesFetching({ + referenceData: { applicationTypes: [] } + }) + ).toEqual(false); + expect( + fromReferenceData.getApplicationTypesFetching({ + referenceData: {} + }) + ).toEqual(false); + }); + }); + }); + + describe('hearing types', () => { + describe('getHearingTypes', () => { + it('should select the hearing types', () => { + expect( + fromReferenceData.getHearingTypes({ + referenceData: { + hearingTypes: [{ id: '*' }] as HearingType[] + } + }) + ).toMatchSnapshot(); + }); + }); + + describe('getHearingTypesFetching', () => { + it('should select the fetching state of the hearing types', () => { + expect( + fromReferenceData.getHearingTypesFetching({ + referenceData: { hearingTypes: null } + }) + ).toEqual(true); + expect( + fromReferenceData.getHearingTypesFetching({ + referenceData: { hearingTypes: [] } + }) + ).toEqual(false); + expect( + fromReferenceData.getHearingTypesFetching({ + referenceData: {} + }) + ).toEqual(false); + }); + }); + }); + + describe('court centres', () => { + describe('getOrganisationUnits', () => { + it('should select the court centres', () => { + expect( + fromReferenceData.getOrganisationUnits({ + referenceData: { + organisationUnits: [{ id: '*' }] as OrganisationUnit[] + } + }) + ).toMatchSnapshot(); + }); + }); + + describe('getOrganisationUnitsFetching', () => { + it('should select the fetching state of the court centres', () => { + expect( + fromReferenceData.getOrganisationUnitsFetching({ + referenceData: { organisationUnits: null } + }) + ).toEqual(true); + expect( + fromReferenceData.getOrganisationUnitsFetching({ + referenceData: { organisationUnits: [] } + }) + ).toEqual(false); + expect( + fromReferenceData.getOrganisationUnitsFetching({ + referenceData: {} + }) + ).toEqual(false); + }); + }); + }); + + describe('prosecutors', () => { + describe('getProsecutors', () => { + it('should select the prosecutors', () => { + expect( + fromReferenceData.getProsecutors({ + referenceData: { + prosecutors: [{ id: '*' }] as Prosecutor[] + } + }) + ).toMatchSnapshot(); + }); + }); + + describe('getProsecutorsFetching', () => { + it('should select the fetching state of the prosecutors', () => { + expect( + fromReferenceData.getProsecutorsFetching({ + referenceData: { prosecutors: null } + }) + ).toEqual(true); + expect( + fromReferenceData.getProsecutorsFetching({ + referenceData: { prosecutors: [] } + }) + ).toEqual(false); + expect( + fromReferenceData.getProsecutorsFetching({ + referenceData: {} + }) + ).toEqual(false); + }); + }); + }); + + describe('rota business Types', () => { + const magistratesType: RotaBusinessType = { + id: '1', + seqNum: 1, + typeCode: 'GEN' as RotaBusinessTypeCode, + typeDescription: 'General', + slot: true, + duration: false, + jurisdiction: 'MAGISTRATES' + }; + + const crownType: RotaBusinessType = { + id: '2', + seqNum: 2, + typeCode: 'LGT' as RotaBusinessTypeCode, + typeDescription: 'Long Trial (5 days plus)', + slot: false, + duration: true, + jurisdiction: 'CROWN' + }; + + describe('getRotaBusinessTypes', () => { + it('should select only rota business types with MAGISTRATES jurisdiction', () => { + const result = fromReferenceData.getRotaBusinessTypes({ + referenceData: { + rotaBusinessTypes: [magistratesType] + } + }); + + expect(result).toEqual([magistratesType]); + }); + + it('should select an empty array when no rota business types exist', () => { + expect( + fromReferenceData.getRotaBusinessTypes({ + referenceData: {} + }) + ).toEqual([]); + }); + + it('should select an empty array when no crown rota business types exist', () => { + expect( + fromReferenceData.getRotaBusinessTypesByJurisdiction('CROWN')({ + referenceData: {} + }) + ).toEqual([]); + }); + }); + + describe('getRotaBusinessTypesByJurisdiction', () => { + it('should return all rota business types when jurisdiction is ALL', () => { + const result = fromReferenceData.getRotaBusinessTypesByJurisdiction('ALL')({ + referenceData: { + rotaBusinessTypes: [magistratesType, crownType] + } + }); + + expect(result).toEqual([magistratesType, crownType]); + }); + + it('should filter by MAGISTRATES jurisdiction', () => { + const result = fromReferenceData.getRotaBusinessTypesByJurisdiction('MAGISTRATES')({ + referenceData: { + rotaBusinessTypes: [magistratesType, crownType] + } + }); + + expect(result).toEqual([magistratesType]); + }); + + it('should filter by CROWN jurisdiction', () => { + const result = fromReferenceData.getRotaBusinessTypesByJurisdiction('CROWN')({ + referenceData: { + rotaBusinessTypes: [magistratesType, crownType] + } + }); + + expect(result).toEqual([crownType]); + }); + + it('should select only rota business types with CROWN jurisdiction', () => { + const result = fromReferenceData.getRotaBusinessTypesByJurisdiction('CROWN')({ + referenceData: { + rotaBusinessTypes: [crownType] + } + }); + + expect(result).toEqual([crownType]); + }); + + it('should select an empty array when no rota business types exist', () => { + expect( + fromReferenceData.getRotaBusinessTypesByJurisdiction('ALL')({ + referenceData: {} + }) + ).toEqual([]); + }); + }); + + describe('getRotaBusinessTypesFetching', () => { + it('should select the fetching state of the rota business types', () => { + expect( + fromReferenceData.getRotaBusinessTypesFetching({ + referenceData: { rotaBusinessTypes: null } + }) + ).toEqual(true); + expect( + fromReferenceData.getRotaBusinessTypesFetching({ + referenceData: { rotaBusinessTypes: [] } + }) + ).toEqual(false); + expect( + fromReferenceData.getRotaBusinessTypesFetching({ + referenceData: {} + }) + ).toEqual(true); + }); + }); + }); + + describe('Plea Types', () => { + describe('getPleaTypes', () => { + it('should select the plea types', () => { + expect( + fromReferenceData.getPleaStatusTypes({ + referenceData: { + pleaStatusTypes: [{ id: '*' }] as PleaType[] + } + }) + ).toMatchSnapshot(); + }); + + it('should select an empty array when no plea types exist', () => { + expect( + fromReferenceData.getPleaStatusTypes({ + referenceData: {} + }) + ).toMatchSnapshot(); + }); + }); + + describe('getPleaTypesFetching', () => { + it('should select the fetching state of the plea types', () => { + expect( + fromReferenceData.getPleaStatusTypesFetching({ + referenceData: { pleaStatusTypes: null } + }) + ).toEqual(true); + expect( + fromReferenceData.getPleaStatusTypesFetching({ + referenceData: { pleaStatusTypes: [] } + }) + ).toEqual(false); + expect( + fromReferenceData.getPleaStatusTypesFetching({ + referenceData: {} + }) + ).toEqual(false); + }); + }); + }); + + describe('special requirements', () => { + describe('ReferenceDataActions.loadSpecialRequirements', () => { + it('should install the special requirements key', () => { + const action = ReferenceDataActions.loadSpecialRequirements(); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + + it('should not overwrite any special requirements types', () => { + const action = ReferenceDataActions.loadSpecialRequirements(); + const result = fromReferenceData.referenceDataReducer( + { bookingTypes: [{ id: 'someId', typeCode: 'VL', typeValue: 'Video Link' }] }, + action + ); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('ReferenceDataActions.loadBookingTypesSuccess', () => { + it('should add the special requirements to the state', () => { + const action = ReferenceDataActions.loadSpecialRequirementsSuccess({ + specialRequirements: [ + { id: 'someId', requirementCode: 'AOC', requirementValue: 'Availability of a Cell' } + ] + }); + const result = fromReferenceData.referenceDataReducer(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('HearingResultsActions.loadSpecialRequirementsError', () => { + it('should remove the special requirements key', () => { + const action = ReferenceDataActions.loadSpecialRequirementsError({ error: {} as any }); + const result = fromReferenceData.referenceDataReducer({ applicationTypes: null }, action); + + expect(result).toMatchSnapshot(); + }); + }); + }); + + describe('Witness care units', () => { + describe('getWitnessCareUnits', () => { + it('should select witness care units', () => { + expect( + fromReferenceData.getWitnessCareUnits({ + referenceData: { + witnessCareUnits: [{ id: '*' }] as WitnessCareUnit[] + } + }) + ).toMatchSnapshot(); + }); + + it('should select an empty array when no witness care units', () => { + expect( + fromReferenceData.getWitnessCareUnits({ + referenceData: {} + }) + ).toMatchSnapshot(); + }); + }); + + describe('getWitnessCareUnitsFetching', () => { + it('should select the fetching state of the plea types', () => { + expect( + fromReferenceData.getWitnessCareUnitsFetching({ + referenceData: { witnessCareUnits: null } + }) + ).toEqual(true); + expect( + fromReferenceData.getWitnessCareUnitsFetching({ + referenceData: { witnessCareUnits: [] } + }) + ).toEqual(false); + expect( + fromReferenceData.getWitnessCareUnitsFetching({ + referenceData: {} + }) + ).toEqual(false); + }); + }); + }); + + describe('Judiciary Group Types', () => { + describe('getJudiciaryGroupTypes', () => { + it('should select judiciary group types', () => { + expect( + fromReferenceData.getJudiciaryGroupTypes({ + referenceData: { + judiciaryGroupTypes: [{ id: '*' }] as JudiciaryGroupType[] + } + }) + ).toMatchSnapshot(); + }); + + it('should select an empty array when no judiciary group types', () => { + expect( + fromReferenceData.getJudiciaryGroupTypes({ + referenceData: {} + }) + ).toMatchSnapshot(); + }); + }); + + describe('getJudiciaryGroupTypesFetching', () => { + it('should select the fetching state of the judiciary group types', () => { + expect( + fromReferenceData.getJudiciaryGroupTypesFetching({ + referenceData: { judiciaryGroupTypes: null } + }) + ).toEqual(true); + expect( + fromReferenceData.getJudiciaryGroupTypesFetching({ + referenceData: { judiciaryGroupTypes: [] } + }) + ).toEqual(false); + expect( + fromReferenceData.getJudiciaryGroupTypesFetching({ + referenceData: {} + }) + ).toEqual(false); + }); + }); + }); + + describe('Trial Types', () => { + describe('getTrialTypes', () => { + it('should select the trial types', () => { + expect( + fromReferenceData.getTrialTypes({ + referenceData: { + trialTypes: [{ id: '*' }] as TrialType[] + } + }) + ).toMatchSnapshot(); + }); + + it('should select an empty array when no trial types exist', () => { + expect( + fromReferenceData.getTrialTypes({ + referenceData: {} + }) + ).toMatchSnapshot(); + }); + }); + + describe('getTrialTypesFetching', () => { + it('should select the fetching state of the trial types', () => { + expect( + fromReferenceData.getTrialTypesFetching({ + referenceData: { trialTypes: null } + }) + ).toEqual(true); + expect( + fromReferenceData.getTrialTypesFetching({ + referenceData: { trialTypes: [] } + }) + ).toEqual(false); + expect( + fromReferenceData.getTrialTypesFetching({ + referenceData: {} + }) + ).toEqual(false); + }); + }); + + describe('getPoliceRanksFetching', () => { + it('should select the fetching state of the trial types', () => { + expect( + fromReferenceData.getPoliceRanksFetching({ + referenceData: { policeRanks: null } + }) + ).toEqual(true); + expect( + fromReferenceData.getPoliceRanksFetching({ + referenceData: { policeRanks: [] } + }) + ).toEqual(false); + expect( + fromReferenceData.getPoliceRanksFetching({ + referenceData: {} + }) + ).toEqual(false); + }); + }); + }); + }); +}); diff --git a/projects/reference-data/src/reducers/index.ts b/projects/reference-data/src/reducers/index.ts new file mode 100644 index 0000000..9dd0169 --- /dev/null +++ b/projects/reference-data/src/reducers/index.ts @@ -0,0 +1,144 @@ +import { Action, createSelector, defaultMemoize, MemoizedSelector } from '@ngrx/store'; +import { + referenceData, + ReferenceDataState as ReferenceDataFeatureState +} from './reference-data.reducer'; +import { RotaBusinessTypeJurisdiction, RotaBusinessType } from '../reference-data.interfaces'; + +export interface ReferenceDataState { + referenceData: ReferenceDataFeatureState; +} + +export function referenceDataReducer(state: ReferenceDataFeatureState | undefined, action: Action) { + return referenceData(state, action); +} + +export const getAssignPriorities = (state: ReferenceDataState) => + state.referenceData.assignPriorities; + +export const getApplicationTypes = (state: ReferenceDataState) => + state.referenceData.applicationTypes; + +export const getApplicationTypesFetching = (state: ReferenceDataState) => + state.referenceData.applicationTypes === null; + +export const getBookingTypes = (state: ReferenceDataState) => state.referenceData.bookingTypes; + +export const getClusters = (state: ReferenceDataState) => state.referenceData.clusters; + +export const getClustersFetching = (state: ReferenceDataState) => + state.referenceData.clusters === null; + +export const getCPSAreas = (state: ReferenceDataState) => state.referenceData.cpsAreas; + +export const getCPSBusinessUnits = (state: ReferenceDataState) => + state.referenceData.cpsBusinessUnits; + +export const getCPSCaseStatuses = (state: ReferenceDataState) => + state.referenceData.cpsCaseStatuses; + +export const getFixedLists = (state: ReferenceDataState) => state.referenceData.fixedLists || []; + +export const getFixedListsFetching = (state: ReferenceDataState) => + state.referenceData.fixedLists === null; + +export const getHearingTypes = (state: ReferenceDataState) => state.referenceData.hearingTypes; + +export const getHearingTypesFetching = (state: ReferenceDataState) => + state.referenceData.hearingTypes === null; + +export const getLocalJusticeAreas = (state: ReferenceDataState) => + state.referenceData.localJusticeAreas; + +export const getOrganisationUnits = (state: ReferenceDataState) => + state.referenceData.organisationUnits; + +export const getOrganisationUnitsFetching = (state: ReferenceDataState) => + state.referenceData.organisationUnits === null; + +export const getPoliceForceList = (state: ReferenceDataState) => + state.referenceData.policeForceList; + +export const getPoliceForceFetching = (state: ReferenceDataState) => + state.referenceData.policeForceList === null; + +export const getProsecutors = (state: ReferenceDataState) => state.referenceData.prosecutors; + +export const getProsecutorsFetching = (state: ReferenceDataState) => + state.referenceData.prosecutors === null; + +export const getResultDefinitions = (state: ReferenceDataState) => + state.referenceData.resultDefinitions || []; + +export const getResultDefinitionsFetching = (state: ReferenceDataState) => + state.referenceData.resultDefinitions === null; + +export const getRotaBusinesTypesState = (state: ReferenceDataState) => + state.referenceData.rotaBusinessTypes; + +export const getRotaBusinessTypes = createSelector(getRotaBusinesTypesState, (rotaBusinessTypes) => + (rotaBusinessTypes || []).filter( + (rotaBusinessType) => rotaBusinessType.jurisdiction === 'MAGISTRATES' + ) +); + +export const getRotaBusinessTypesByJurisdiction = ( + jurisdiction: RotaBusinessTypeJurisdiction | 'ALL' +): MemoizedSelector => + defaultMemoize((jurisdiction: RotaBusinessTypeJurisdiction | 'ALL') => + createSelector( + getRotaBusinesTypesState, + (rotaBusinessTypes: RotaBusinessType[] | null | undefined) => { + if (jurisdiction === 'ALL') { + return rotaBusinessTypes || []; + } + return (rotaBusinessTypes || []).filter( + (rotaBusinessType) => rotaBusinessType.jurisdiction === jurisdiction + ); + } + ) + ).memoized(jurisdiction); + +export const getRotaBusinessTypesFetching = (state: ReferenceDataState) => + state.referenceData.rotaBusinessTypes === null || + state.referenceData.rotaBusinessTypes === undefined; + +export const getPleaStatusTypes = (state: ReferenceDataState) => + state.referenceData.pleaStatusTypes || []; + +export const getPleaStatusTypesFetching = (state: ReferenceDataState) => + state.referenceData.pleaStatusTypes === null; + +export const getSpecialRequirements = (state: ReferenceDataState) => + state.referenceData.specialRequirements; + +export const getWitnessCareUnits = (state: ReferenceDataState) => + state.referenceData.witnessCareUnits; + +export const getWitnessCareUnitsFetching = (state: ReferenceDataState) => + state.referenceData.witnessCareUnits === null; + +export const getJudiciaryGroupTypes = (state: ReferenceDataState) => + state.referenceData.judiciaryGroupTypes; + +export const getJudiciaryGroupTypesFetching = (state: ReferenceDataState) => + state.referenceData.judiciaryGroupTypes === null; + +export const getTrialTypes = (state: ReferenceDataState) => state.referenceData.trialTypes || []; + +export const getTrialTypesFetching = (state: ReferenceDataState) => + state.referenceData.trialTypes === null; + +export const getPoliceRanks = (state: ReferenceDataState) => state.referenceData.policeRanks || []; + +export const getPoliceRanksFetching = (state: ReferenceDataState) => + state.referenceData.policeRanks === null; +export const getPublicHolidays = (state: ReferenceDataState) => state.referenceData.publicHolidays; +export const getPublicHolidaysFetching = (state: ReferenceDataState) => + state.referenceData.publicHolidays === null; + +export const getOrganisationsWithType = (state: ReferenceDataState) => + state.referenceData.organisationsWithType; +export const getOrganisationsWithTypeNeedsFetching = (state: ReferenceDataState) => + state.referenceData.organisationsWithType === null || + state.referenceData.organisationsWithType === undefined; diff --git a/projects/reference-data/src/reducers/reference-data.reducer.ts b/projects/reference-data/src/reducers/reference-data.reducer.ts new file mode 100644 index 0000000..ccd38b6 --- /dev/null +++ b/projects/reference-data/src/reducers/reference-data.reducer.ts @@ -0,0 +1,514 @@ +import { createReducer, on } from '@ngrx/store'; +import { ReferenceDataActions } from '../actions/index'; +import { + Cluster, + CPSArea, + CPSBusinessUnit, + CPSCaseStatus, + CourtApplicationType, + FixedList, + HearingType, + JudiciaryGroupType, + LocalJusticeArea, + OrganisationUnit, + PleaType, + PoliceForce, + Prosecutor, + ResultDefinition, + RotaBusinessType, + WitnessCareUnit, + TrialType, + HearingPriority, + SpecialRequirement, + BookingType, + PoliceRank, + PublicHoliday, + OrganisationWithType +} from '../reference-data.interfaces'; + +export interface ReferenceDataState { + assignPriorities?: HearingPriority[] | null; + applicationTypes?: CourtApplicationType[] | null; + bookingTypes?: BookingType[] | null; + clusters?: Cluster[] | null; + cpsAreas?: CPSArea[] | null; + cpsBusinessUnits?: CPSBusinessUnit[] | null; + cpsCaseStatuses?: CPSCaseStatus[] | null; + fixedLists?: FixedList[] | null; + hearingTypes?: HearingType[] | null; + judiciaryGroupTypes?: JudiciaryGroupType[] | null; + localJusticeAreas?: LocalJusticeArea[] | null; + organisationUnits?: OrganisationUnit[] | null; + policeForceList?: PoliceForce[] | null; + prosecutors?: Prosecutor[] | null; + resultDefinitions?: ResultDefinition[] | null; + rotaBusinessTypes?: RotaBusinessType[] | null; + pleaStatusTypes?: PleaType[] | null; + specialRequirements?: SpecialRequirement[] | null; + witnessCareUnits?: WitnessCareUnit[] | null; + trialTypes?: TrialType[] | null; + policeRanks?: PoliceRank[] | null; + publicHolidays?: PublicHoliday[] | null; + organisationsWithType?: OrganisationWithType[] | null; +} + +const initialState: ReferenceDataState = {}; + +export const referenceData = createReducer( + initialState, + + // Application types + + on(ReferenceDataActions.loadApplicationTypes, (state) => ({ + ...state, + applicationTypes: state.applicationTypes || null + })), + on(ReferenceDataActions.loadApplicationTypesSuccess, (state, { applicationTypes }) => ({ + ...state, + applicationTypes + })), + on(ReferenceDataActions.loadApplicationTypesError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'applicationTypes' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Assign Priorities + + on(ReferenceDataActions.loadAssignPriorities, (state) => ({ + ...state, + assignPriorities: state.assignPriorities || null + })), + on(ReferenceDataActions.loadAssignPrioritiesSuccess, (state, { assignPriorities }) => ({ + ...state, + assignPriorities + })), + on(ReferenceDataActions.loadAssignPrioritiesError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'assignPriorities' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Booking Types + + on(ReferenceDataActions.loadBookingTypes, (state) => ({ + ...state, + bookingTypes: state.bookingTypes || null + })), + on(ReferenceDataActions.loadBookingTypesSuccess, (state, { bookingTypes }) => ({ + ...state, + bookingTypes + })), + on(ReferenceDataActions.loadBookingTypesError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'bookingTypes' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Clusters + + on(ReferenceDataActions.loadClusters, (state) => ({ + ...state, + clusters: state.clusters || null + })), + on(ReferenceDataActions.loadClustersSuccess, (state, { clusters }) => ({ + ...state, + clusters + })), + on(ReferenceDataActions.loadClustersError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'clusters' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // CPS Areas + + on(ReferenceDataActions.loadCPSAreas, (state) => ({ + ...state, + cpsAreas: state.cpsAreas || null + })), + on(ReferenceDataActions.loadCPSAreasSuccess, (state, { cpsAreas }) => ({ + ...state, + cpsAreas + })), + on(ReferenceDataActions.loadCPSAreasError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'cpsAreas' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + // CPS Business Units + + on(ReferenceDataActions.loadCPSBusinessUnits, (state) => ({ + ...state, + cPSBusinessUnits: state.cpsBusinessUnits || null + })), + on(ReferenceDataActions.loadCPSBusinessUnitsSuccess, (state, { cpsBusinessUnits }) => ({ + ...state, + cpsBusinessUnits + })), + on(ReferenceDataActions.loadCPSBusinessUnitsError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'cpsBusinessUnits' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // CPS Case Statuses + + on(ReferenceDataActions.loadCPSCaseStatuses, (state) => ({ + ...state, + cpsCaseStatuses: state.cpsCaseStatuses || null + })), + on(ReferenceDataActions.loadCPSCaseStatusesSuccess, (state, { cpsCaseStatuses }) => ({ + ...state, + cpsCaseStatuses + })), + on(ReferenceDataActions.loadCPSCaseStatusesError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'cpsCaseStatuses' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Fixed lists + + on(ReferenceDataActions.loadFixedLists, (state) => ({ + ...state, + fixedLists: state.fixedLists || null + })), + on(ReferenceDataActions.loadFixedListsSuccess, (state, { fixedLists }) => ({ + ...state, + fixedLists + })), + on(ReferenceDataActions.loadFixedListsError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'fixedLists' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Hearing types + + on(ReferenceDataActions.loadHearingTypes, (state) => ({ + ...state, + hearingTypes: state.hearingTypes || null + })), + on(ReferenceDataActions.loadHearingTypesSuccess, (state, { hearingTypes }) => ({ + ...state, + hearingTypes + })), + on(ReferenceDataActions.loadHearingTypesError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'hearingTypes' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Local Justice Areas + + on(ReferenceDataActions.loadLocalJusticeAreas, (state) => ({ + ...state, + localJusticeAreas: state.localJusticeAreas || null + })), + on(ReferenceDataActions.loadLocalJusticeAreasSuccess, (state, { localJusticeAreas }) => ({ + ...state, + localJusticeAreas + })), + on(ReferenceDataActions.loadLocalJusticeAreasError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'localJusticeAreas' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Organisation units + + on(ReferenceDataActions.loadOrganisationUnits, (state) => ({ + ...state, + organisationUnits: state.organisationUnits || null + })), + on(ReferenceDataActions.loadOrganisationUnitsSuccess, (state, { organisationUnits }) => ({ + ...state, + organisationUnits + })), + on(ReferenceDataActions.loadOrganisationUnitsError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'organisationUnits' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Plea types + + on(ReferenceDataActions.loadPleaTypes, (state) => ({ + ...state, + pleaStatusTypes: state.pleaStatusTypes || null + })), + on(ReferenceDataActions.loadPleaTypesSuccess, (state, { pleaStatusTypes }) => ({ + ...state, + pleaStatusTypes + })), + on(ReferenceDataActions.loadPleaTypesError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'pleaStatusTypes' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Police Force List + + on(ReferenceDataActions.loadPoliceForceList, (state) => ({ + ...state, + policeForceList: state.policeForceList || null + })), + on(ReferenceDataActions.loadPoliceForceListSuccess, (state, { policeForceList }) => ({ + ...state, + policeForceList + })), + on(ReferenceDataActions.loadPoliceForceListError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'policeForceList' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Prosecutors + + on(ReferenceDataActions.loadProsecutors, (state) => ({ + ...state, + prosecutors: state.prosecutors || null + })), + on(ReferenceDataActions.loadProsecutorsSuccess, (state, { prosecutors }) => ({ + ...state, + prosecutors + })), + on(ReferenceDataActions.loadProsecutorsError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'prosecutors' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Result definitions + + on(ReferenceDataActions.loadResultDefinitions, (state) => ({ + ...state, + resultDefinitions: state.resultDefinitions || null + })), + on(ReferenceDataActions.loadResultDefinitionsSuccess, (state, { resultDefinitions }) => ({ + ...state, + resultDefinitions + })), + on(ReferenceDataActions.loadResultDefinitionsError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'resultDefinitions' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Rota business types + + on(ReferenceDataActions.loadRotaBusinessTypes, (state) => ({ + ...state, + rotaBusinessTypes: state.rotaBusinessTypes || null + })), + on(ReferenceDataActions.loadRotaBusinessTypesSuccess, (state, { rotaBusinessTypes }) => ({ + ...state, + rotaBusinessTypes + })), + on(ReferenceDataActions.loadRotaBusinessTypesError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'rotaBusinessTypes' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Special requirements + + on(ReferenceDataActions.loadSpecialRequirements, (state) => ({ + ...state, + specialRequirements: state.specialRequirements || null + })), + on(ReferenceDataActions.loadSpecialRequirementsSuccess, (state, { specialRequirements }) => ({ + ...state, + specialRequirements + })), + on(ReferenceDataActions.loadSpecialRequirementsError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'specialRequirements' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Witness care units + + on(ReferenceDataActions.loadWitnessCareUnits, (state) => ({ + ...state, + witnessCareUnits: state.witnessCareUnits || null + })), + on(ReferenceDataActions.loadWitnessCareUnitsSuccess, (state, { witnessCareUnits }) => ({ + ...state, + witnessCareUnits + })), + on(ReferenceDataActions.loadWitnessCareUnitsError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'witnessCareUnits' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Judiciary Group Types + + on(ReferenceDataActions.loadJudiciaryGroupTypes, (state) => ({ + ...state, + judiciaryGroupTypes: state.judiciaryGroupTypes || null + })), + on(ReferenceDataActions.loadJudiciaryGroupTypesSuccess, (state, { judiciaryGroupTypes }) => ({ + ...state, + judiciaryGroupTypes + })), + on(ReferenceDataActions.loadJudiciaryGroupTypesError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'judiciaryGroupTypes' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Trial types + + on(ReferenceDataActions.loadTrialTypes, (state) => ({ + ...state, + trialTypes: state.trialTypes || null + })), + on(ReferenceDataActions.loadTrialTypesSuccess, (state, { trialTypes }) => ({ + ...state, + trialTypes + })), + on(ReferenceDataActions.loadTrialTypesError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'trialTypes' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Police ranks + on(ReferenceDataActions.loadPoliceRanks, (state) => ({ + ...state, + policeRanks: state.policeRanks || null + })), + on(ReferenceDataActions.loadPoliceRanksSuccess, (state, { policeRanks }) => ({ + ...state, + policeRanks + })), + on(ReferenceDataActions.loadPoliceRanksError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'policeRanks' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + // Public holidays + on(ReferenceDataActions.loadPublicHolidays, (state) => ({ + ...state, + publicHolidays: state.publicHolidays || null + })), + on(ReferenceDataActions.loadPublicHolidaysSuccess, (state, { publicHolidays }) => ({ + ...state, + publicHolidays + })), + on(ReferenceDataActions.loadPublicHolidaysError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'publicHolidays' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ), + + // Organisation withg types + on(ReferenceDataActions.loadOrganisationsWithType, (state) => ({ + ...state, + organisationsWithType: state.organisationsWithType ?? null + })), + on(ReferenceDataActions.loadOrganisationsWithTypeSuccess, (state, { organisationsWithType }) => ({ + ...state, + organisationsWithType + })), + on(ReferenceDataActions.loadOrganisationsWithTypeError, (state) => + Object.keys(state).reduce( + (nextState, key) => + key !== 'organisationsWithType' || state[key as keyof ReferenceDataState] !== null + ? { ...nextState, [key]: state[key as keyof ReferenceDataState] } + : nextState, + {} + ) + ) +); diff --git a/projects/reference-data/src/reference-data.interfaces.ts b/projects/reference-data/src/reference-data.interfaces.ts new file mode 100644 index 0000000..283ce12 --- /dev/null +++ b/projects/reference-data/src/reference-data.interfaces.ts @@ -0,0 +1,573 @@ +import { UserGroupType } from '@cpp/users-groups'; +import { JudiciaryTypePayload, RefDataJudiciaryType } from './helpers/judiciary-type.helper'; + +export enum BreachType { + GENERIC_BREACH = 'GENERIC_BREACH', + COMMISSION_OF_NEW_OFFENCE_BREACH = 'COMMISSION_OF_NEW_OFFENCE_BREACH', + NOT_APPLICABLE = 'NOT_APPLICABLE' +} + +export enum SummonsTemplateType { + GENERIC_APPLICATION = 'GENERIC_APPLICATION', + BREACH = 'BREACH', + NOT_APPLICABLE = 'NOT_APPLICABLE', + FIRST_HEARING = 'FIRST_HEARING' +} + +export enum LinkType { + STANDALONE = 'STANDALONE', + LINKED = 'LINKED', + SJP = 'SJP', + FIRST_HEARING = 'FIRST_HEARING' +} + +export enum OffenceActiveOrderType { + OFFENCE = 'OFFENCE', + COURT_ORDER = 'COURT_ORDER', + NOT_APPLICABLE = 'NOT_APPLICABLE' +} + +export interface Cluster { + id: string; + clusterCode: string; + clusterName: string; +} + +export interface CPSCaseStatus { + id: string; + statusCode: string; + statusDescription: string; +} + +export interface CPSArea { + id: string; + areaName: string; + areaCode: number; +} + +export interface CPSBusinessUnit { + buType: string; + cmsAreaCode: number; + id: string; + oucode: string; + sensitiveFlag: boolean; + unitCode: number; + unitName: string; +} +export interface CourtApplicationType { + id: string; + code?: string; + type: string; + legislation?: string; + categoryCode: string; + linkType: LinkType; + jurisdiction: string; + appealFlag: boolean; + pssId?: string; + applicationWording?: string; + changeDate?: string; + summonsTemplateType: SummonsTemplateType; + validFrom?: string; + hearingCode: string; + applicantAppellantFlag: boolean; + pleaApplicableFlag: boolean; + offenceActiveOrder: OffenceActiveOrderType; + commrOfOathFlag: boolean; + breachType: BreachType; + courtOfAppealFlag: boolean; + courtExtractAvlFlag: boolean; + listingNotifTemplate?: string; + boxworkNotifTemplate?: string; + typeWelsh?: string; + legislationWelsh?: string; + prosecutorThirdPartyFlag: boolean; + spiOutApplicableFlag: boolean; + resentencingActivationCode: string; + prefix: string; + exParte?: boolean; + sowRef?: string; + lastModified?: string; + initialFeeApplicable?: boolean; + contestedFeeApplicable?: boolean; +} + +export interface CourtRoom { + id: string; + courtroomId: number; + venueName: string; + welshVenueName?: string; + courtroomName: string; + welshCourtroomName?: string; +} + +export interface FixedList { + id: string; + startDate: string; + endDate?: string; + cjsQualifier?: string; + elements: FixedListElement[]; + version: string; +} + +export interface FixedListElement { + code: string; + value: string; + welshValue?: string; +} + +export interface HearingType { + id: string; + seqId: number; + hearingCode: string; + hearingDescription: string; + welshHearingDescription: string; + defaultDurationMin: number; + validFrom?: string | null; + validTo?: string | null; + magistratesFlag?: boolean; + crownFlag?: boolean; + exhibitHearingCode?: string; + exhibitHearingDescription?: string; + strategicFlag?: boolean; + tacticalFlag?: boolean; + trialTypeFlag?: boolean; +} + +export interface LocalJusticeArea { + address?: { + address1?: string; + address2?: string; + address3?: string; + postcode?: string; + }; + clusterCode: string; + name?: string; + nationalCourtCode?: string; + region?: string; + shortName?: string; +} + +export interface OrganisationUnit { + id: string; + oucode?: string; + oucodeL3Code: string; + oucodeL3Name: string; + oucodeL2Code?: string; + oucodeL2Name?: string; + oucodeL1Code?: string; + oucodeL1Name?: string; + region?: string; + oucodeEffectiveFromDate?: string; + oucodeEffectiveToDate?: string; + lja?: string; + phone?: string; + fax?: string; + email?: string; + address1?: string; + address2?: string; + address3?: string; + address4?: string; + address5?: string; + postcode?: string; + isWelsh?: string; + oucodeL3WelshName?: string; + welshAddress1?: string; + welshAddress2?: string; + welshAddress3?: string; + welshAddress4?: string; + welshAddress5?: string; + defaultStartTime?: string; + defaultDurationHrs?: string; + courtrooms?: CourtRoom[]; +} + +export interface JudiciaryGroupType { + id: string; + judiciaryGroup: string; + judiciaryTypeDescription: string; +} + +export interface PleaType { + id: string; + sequence: number; + pleaTypeCode: string; + pleaTypeDescription: string; + pleaTypeGuiltyFlag: 'Yes' | 'No'; + pleaTypeCivilFlag: 'Yes' | 'No'; + pleaStatusCode: string; + pleaTypeUIFlag: boolean; + pleaValue: string; + jurisdiction: 'MAGISTRATES' | 'CROWN' | 'EITHER'; +} + +export interface PoliceForce { + id: string; + blockedModeFlag?: boolean; + channel?: string; + oucodeL2Code?: string; + policeForceCode: string; + policeForceName: string; + validForSpiOut: boolean; + validFrom: string; + validTo: string; +} + +export enum ProsecutionOrganisationType { + LOCAL_AUTHORITIES = 'Local Authorities', + TRAVEL_AND_TRANSPORT = 'Travel & Transport', + GOV_BODIES = 'Government Bodies', + NON_GOV_BODIES = 'Non-Government Bodies' +} +export interface Prosecutor { + id: string; + sequenceNumber: number; + majorCreditorCode?: string; + shortName: string; + nameWelsh?: string; + fullName: string; + address?: { + address1?: string; + address2?: string; + address3?: string; + address4?: string; + address5?: string; + postcode?: string; + }; + validFrom?: string; + validTo?: string; + oucode?: string; + spiInFlag?: boolean; + spiOutFlag?: boolean; + policeFlag?: boolean; + contactEmailAddress?: string; + standard?: boolean; + prosecutorCategory?: ProsecutionOrganisationType; + cpsFlag?: boolean; +} + +export enum ResultDefinitionAdjournment { + scheduled = 'S', + unscheduled = 'U', + noAdjournment = 'A' +} + +export enum ResultDefinitionPostHearingCustodyStatus { + ConditionalBail = 'B', + UnconditionalBail = 'U', + CustodyOrRemandedIntoCustody = 'C', + NotApplicable = 'A', + RemandedIntoCareOfLocalAuthority = 'L', + ConditionalBailWithPreReleaseConditions = 'P', + RemandedIntoSecureAccommodation = 'S', + RearrestedAfterReleaseOnBail = 'R' +} + +export enum ResultDefinitionLevel { + case = 'C', + defendant = 'D', + offenceLevel = 'O' +} + +export enum ResultDefinitionCategory { + ancillary = 'A', + final = 'F', + interim = 'I' +} + +export enum ResultDefinitionJurisdiction { + all = 'B', + crownCourt = 'CC', + magistrates = 'M' +} + +export interface WordGroup { + wordGroup: string[]; +} + +export interface ResultDefinition { + adjournment: 'Y' | 'N'; + category: ResultDefinitionCategory; + cjsCode: string; + convicted: 'Y' | 'N'; + d20: 'Y' | 'N'; + endDate?: string; + financial: 'Y' | 'N'; + id: string; + isAvailableForCourtExtract: boolean; + isExcludedFromResults: boolean; + isLifeDuration: boolean; + isPublishedAsPrompt: boolean; + jurisdiction: unknown; + label: string; + lCode: string; + level: ResultDefinitionLevel; + prompts: ResultPrompt[]; + rank: number; + shortCode: string; + startDate: string; + terminatesOffenceProceedings: boolean; + urgent: 'Y' | 'N'; + welshLabel?: string; + wordGroups: WordGroup[]; + version: string; +} + +export interface ResultPrompt { + id: string; + label: string; + resultPromptRule: 'optional' | 'mandatory'; + type: ResultPromptType; + sequence: number; + userGroups: UserGroupType[]; + financial: 'Y' | 'N'; + courtExtract: 'Y' | 'N'; + jurisdiction: ResultDefinitionJurisdiction; + min: number; + max: number; +} + +export enum ResultPromptType { + boolean = 'BOOLEAN', + date = 'DATE', + fixedList = 'FIXL', + integer = 'INT', + text = 'TEXT', + time = 'TIME' +} + +export enum RotaBusinessTypeCode { + applications = 'APP', + bailCase = 'BAIL', + breaches = 'BRE', + communityJustice = 'COM', + confiscation = 'CONF', + councilTax = 'CT', + crownCourt = 'CC', + custodyCase = 'CUST', + domesticViolenceBail = 'DVB', + domesticViolencePSR = 'DVP', + domesticViolenceTrials = 'DVT', + drugRehabReviews = 'DRR', + dvla = 'DVLA', + general = 'GEN', + guiltyAnticipatedPlea = 'GAP', + guiltyPleaOnLine = 'GPL', + notGuiltyAncitipatedPlea = 'NGAP', + psr = 'PSR', + remands = 'REM', + televisionLicensing = 'TVL', + terrorism = 'TER', + tfl = 'TFL', + traffic = 'TRF', + trial = 'TRI' +} + +export type RotaBusinessTypeJurisdiction = 'MAGISTRATES' | 'CROWN'; + +export interface RotaBusinessType { + id: string; + seqNum: number; + typeCode: RotaBusinessTypeCode; + typeDescription: string; + slot: boolean; + duration: boolean; + jurisdiction?: RotaBusinessTypeJurisdiction; +} + +export interface WitnessCareUnit { + id: string; + wcuName: string; + wcuCode: string; + policeForceCode?: string; +} + +export interface WordSynonymItem { + word: string; + synonym: string; +} + +export interface WordSynonym { + id: string; + version: string; + startDate: string; + endDate?: string; + synonymCollection: WordSynonymItem[]; +} + +export interface ReusableInfoDefinitions { + reusablePromptDefinitions: ReusablePromptDefinition[]; + reusableResultDefinitions: Array<{ shortCode: string }>; +} + +export interface ReusablePromptDefinition { + promptRef: string; + type: string; + cacheDataPath?: string; + cacheable: number; +} + +export interface TrialType { + id: string; + seqNo: number; + reasonCode: string; + trialType: string; + jurisdiction: string; + reasonShortDescription: string; + value?: string; + label?: string; + vacateTrial?: boolean; + type?: string; +} +export interface SelectedJudiciaryOptions { + judiciaryGroup?: JudiciaryTypePayload; + search?: string; + ids?: string; + limit?: number; + withSpecialism?: boolean; +} + +export interface JudicialMember { + id: string; + cpUserId?: string; + seqId: number; + emailAddress: string; + titlePrefix?: string; + titleJudicialPrefix?: string; + titleSuffix?: string; + titlePrefixWelsh?: string; + titleJudiciaryPrefixWelsh?: string; + titleSuffixWelsh?: string; + surname: string; + forenames: string; + judiciaryType: RefDataJudiciaryType; + requestedName?: string; + validFrom?: string; + validTo?: string; + ljaShortName?: string; +} + +export interface SpecialRequirement { + id: string; + requirementCode: string; + requirementValue: string; + requirementValueWelsh?: string; + validFrom?: string; + validTo?: string; +} + +export interface BookingType { + id: string; + typeCode: string; + typeValue: string; + typeValueWelsh?: string; + validFrom?: string; + validTo?: string; +} + +export interface HearingPriority { + id: string; + seqNum: number; + priorityCode: string; + priorityValue: string; + priorityValueWelsh?: string; + validFrom?: string; + validTo?: string; +} + +export interface PoliceRank { + id: string; + sequence: number; + rankCode: RankTypes; + rankDescription: string; +} + +export type RankTypes = + | 'ACC' + | 'ACOMM' + | 'CC' + | 'CDR' + | 'COMM' + | 'DAC' + | 'DCC' + | 'DCOMM' + | 'C/SUPT' + | 'D/C/SUPT' + | 'D/SUPT' + | 'SUPT' + | 'CI' + | 'DI' + | 'INSP' + | 'DS' + | 'PS' + | 'DC' + | 'PC'; +export interface PublicHoliday { + id: string; + division: string; + title: string; + date: string; +} + +export enum OrganisationType { + NPS = 'NPS', + NPSBREACH = 'NPS_Breach', + BULKSCAN = 'BULKSCAN' +} + +export interface OrganisationWithType { + id: string; + seqNum: number; + orgName: string; + orgType: OrganisationType; + startDate: string; + endDate: string; + address1?: string; + address2?: string; + address3?: string; + address4?: string; + address5?: string; + postcode?: string; + filtercode?: string; + phoneNo?: string; + emailAddress?: string; +} + +export type OrganisationWithTypeAddress = Pick< + OrganisationWithType, + 'address1' | 'address2' | 'address3' | 'address4' | 'address5' | 'postcode' +>; +export interface TerminalEntry { + Max: string; + Min: string; + OteId: string; + value: string; + OteNumber: string; + EntryFormat: string; + EntryPrompt: string; +} + +export interface Offence { + offenceId: string; + pssOffenceId: string; + cjsOffenceCode: string; + title: string; + titleWelsh?: string; + legislation: string; + offenceWording: string; + pnldOffenceWording: string; + endorsableFlag: boolean; + offenceType: string; + terminalEntry: TerminalEntry[]; + canBeBulk: boolean; + initialFeeApplicable: boolean; + contestedFeeApplicable: boolean; + exParte: boolean; + sowRef: string; + startDate: string; + changeDate: string; + custodialIndicator: string; + recordable: string; + pnldDateOfLastUpdate: string; + search: string; + details: Record; +} diff --git a/projects/reference-data/src/reference-data.module.ts b/projects/reference-data/src/reference-data.module.ts new file mode 100644 index 0000000..9a854dd --- /dev/null +++ b/projects/reference-data/src/reference-data.module.ts @@ -0,0 +1,128 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { EffectsModule } from '@ngrx/effects'; +import { StoreModule } from '@ngrx/store'; +import { ApplicationTypeAutosuggestComponent } from './components/application-type.autosuggest'; +import { AssignPrioritySelectComponent } from './components/assign-priority.select'; +import { BookingTypesSelectComponent } from './components/booking-type.select'; +import { ClusterAutosuggestComponent } from './components/cluster.autosuggest'; +import { CPSAreaSelectComponent } from './components/cps-area.select'; +import { CPSBusinessUnitSelectComponent } from './components/cps-business-unit.select'; +import { CPSCaseStatusSelectComponent } from './components/cps-case-status.select'; +import { FixedListAutosuggestComponent } from './components/fixed-list.autosuggest'; +import { HearingTypeAutosuggestComponent } from './components/hearing-type.autosuggest'; +import { HearingTypeSelectComponent } from './components/hearing-type.select'; +import { OrganisationUnitAutosuggestComponent } from './components/organisation-unit.autosuggest'; +import { PoliceForceAutosuggestComponent } from './components/police-force.autosuggest'; +import { ProsecutorAutosuggestComponent } from './components/prosecutor.autosuggest'; +import { WitnessCareUnitSelectComponent } from './components/witness-care-unit.select'; +import { ReferenceDataEffects } from './effects/reference-data.effects'; +import { ApplicationTypesGuard } from './guards/application-type.guard'; +import { AssignPrioritiesGuard } from './guards/assingn-priorities.guard'; +import { BookingTypesGuard } from './guards/booking-types.guard'; +import { ClustersGuard } from './guards/clusters.guard'; +import { CPSAreasGuard } from './guards/cps-areas.guard'; +import { CPSBusinessUnitsGuard } from './guards/cps-business-units.guard'; +import { CPSCaseStatusGuard } from './guards/cps-case-status.guard'; +import { FixedListsGuard } from './guards/fixed-lists.guard'; +import { HearingTypesGuard } from './guards/hearing-type.guard'; +import { JudiciaryGroupTypesGuard } from './guards/judiciary-group-types.guard'; +import { LocalJusticeAreasGuard } from './guards/local-justice-areas.guard'; +import { OrganisationUnitsGuard } from './guards/court-centres.guard'; +import { PleaTypesGuard } from './guards/plea-types.guard'; +import { PoliceForceListGuard } from './guards/police-force.guard'; +import { ProsecutorsGuard } from './guards/prosecutors.guard'; +import { RotaBusinessTypesGuard } from './guards/rota-business-types.guard'; +import { SpecialRequirementsGuard } from './guards/special-requirement.guard'; +import { WitnessCareUnitGuard } from './guards/witness-care-unit.guard'; +import { referenceDataReducer } from './reducers/index'; +import { ReferenceDataService } from './services/reference-data.service'; +import { TrialTypesGuard } from './guards/trial-types.guard'; +import { JudicialMemberNamePipe } from './utils/judicial-member-name.pipe'; +import { SpecialRequirementCheckboxComponent } from './components/special-requirements.checkbox'; +import { + ApplicationTypeStandaloneAutosuggestComponent, + PoliceRanksGuard, + PoliceRanksSelectComponent +} from './public_api'; +import { PublicHolidaysGuard } from './guards/public-holidays.guard'; +import { OrganisationWithTypeAutosuggestComponent } from './components/organisation-with-type.autosuggest'; +import { RotaBusinessTypeSelectComponent } from './components/rota-business-types.select'; + +const COMPONENTS = [ + ApplicationTypeAutosuggestComponent, + ApplicationTypeStandaloneAutosuggestComponent, + AssignPrioritySelectComponent, + BookingTypesSelectComponent, + ClusterAutosuggestComponent, + CPSAreaSelectComponent, + CPSBusinessUnitSelectComponent, + CPSCaseStatusSelectComponent, + OrganisationUnitAutosuggestComponent, + FixedListAutosuggestComponent, + HearingTypeAutosuggestComponent, + HearingTypeSelectComponent, + PoliceForceAutosuggestComponent, + PoliceRanksSelectComponent, + ProsecutorAutosuggestComponent, + WitnessCareUnitSelectComponent, + SpecialRequirementCheckboxComponent, + JudicialMemberNamePipe, + OrganisationWithTypeAutosuggestComponent, + RotaBusinessTypeSelectComponent +]; + +/** + * @deprecated + * This will be removed in some release moving forward but is + * left here for Backward compatilibity. + * + * To use reference data, remove the module where used. + * In the app module or Bootstrap function (Standalone) or Route , + * provide refencedata context using the following as per preference + * @method provideReferenceDataEnvironmentContext + * - This will provide all guards, and services inclusive of the feature store. + * @method provideReferenceDataStore + * - You can provide just the feature store using this method in your module or route providers and import the guards you need on demand. + * + * + * PLEASE ENSURE THAT YOUR BOOTSTRAP OR APPMODULE USES THE PROVIDESTORE as the root prior to using any of the methods above mentioned. You can + * mix StoreModule.forRoot and provideStore if the application is still modular - Please refer to Ngrx docs for details + * + * Finally all reference data components are standalone and can be imported on demand in the modules or standalone components + * when needed. + */ +@NgModule({ + imports: [ + CommonModule, + EffectsModule.forFeature([ReferenceDataEffects]), + StoreModule.forFeature('referenceData', referenceDataReducer), + ...COMPONENTS + ], + providers: [ + ApplicationTypesGuard, + AssignPrioritiesGuard, + BookingTypesGuard, + ClustersGuard, + CPSAreasGuard, + CPSBusinessUnitsGuard, + CPSCaseStatusGuard, + OrganisationUnitsGuard, + FixedListsGuard, + HearingTypesGuard, + JudiciaryGroupTypesGuard, + LocalJusticeAreasGuard, + PleaTypesGuard, + PoliceForceListGuard, + PoliceRanksGuard, + ProsecutorsGuard, + ReferenceDataService, + RotaBusinessTypesGuard, + SpecialRequirementsGuard, + WitnessCareUnitGuard, + TrialTypesGuard, + PublicHolidaysGuard + ], + exports: [...COMPONENTS] +}) +export class ReferenceDataModule {} diff --git a/projects/reference-data/src/services/__tests__/reference-data.service.spec.ts b/projects/reference-data/src/services/__tests__/reference-data.service.spec.ts new file mode 100644 index 0000000..963f5c0 --- /dev/null +++ b/projects/reference-data/src/services/__tests__/reference-data.service.spec.ts @@ -0,0 +1,406 @@ +import { TestBed } from '@angular/core/testing'; +import { HttpParams } from '@angular/common/http'; +import { of } from 'rxjs'; +import { CppHttp, mapObjectToHttpParams } from '@cpp/core'; +import { ReferenceDataService } from '../reference-data.service'; + +describe('ReferenceDataService', () => { + let service: ReferenceDataService; + let http: CppHttp; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + ReferenceDataService, + { + provide: CppHttp, + useValue: { + query: jest.fn() + } + } + ] + }); + http = TestBed.inject(CppHttp); + service = TestBed.inject(ReferenceDataService); + }); + + describe('fetchApplicationTypes()', () => { + it('should fetch application types', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ courtApplicationTypes: [] })); + + service.fetchApplicationTypes().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/application-types', + requestType: 'application/vnd.referencedata.application-types+json' + }); + }); + }); + }); + + describe('fetchAssignPriorities()', () => { + it('should fetch assign priorities', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ hearingPriorities: [] })); + + service.fetchAssignPriorities().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/hearing-priorities', + requestType: 'application/vnd.referencedata.query.hearing-priorities+json' + }); + }); + }); + }); + + describe('fetchBookingTypes()', () => { + it('should fetch booking types', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ bookingTypes: [] })); + + service.fetchBookingTypes().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/booking-types', + requestType: 'application/vnd.referencedata.query.booking-types+json' + }); + }); + }); + }); + + describe('fetchClusters()', () => { + it('should fetch clusters', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ clusterInformation: [] })); + + service.fetchClusters().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/cluster-information', + requestType: 'application/vnd.referencedata.query.cluster-information+json' + }); + }); + }); + }); + + describe('fetchCPSAreas()', () => { + it('should fetch cps areas', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ cpsAreas: [] })); + + service.fetchCPSAreas().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/cps-areas', + requestType: 'application/vnd.referencedata.query.cps-area+json' + }); + }); + }); + }); + + describe('fetchCPSBusinessUnits()', () => { + it('should fetch cps business units', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ cpsBusinessUnits: [] })); + + service.fetchCPSBusinessUnits().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/cps-business-units', + requestType: 'application/vnd.referencedata.query.cps-business-unit+json' + }); + }); + }); + }); + + describe('fetchCPSCaseStatuses()', () => { + it('should fetch cps case statuses', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ cpsCaseStatuses: [] })); + + service.fetchCPSCaseStatuses().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/cps-case-statuses', + requestType: 'application/vnd.referencedata.query.cps-case-statuses+json' + }); + }); + }); + }); + + describe('fetchFixedLists()', () => { + it('should fetch fixed lists', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ fixedListCollection: [] })); + + service.fetchFixedLists().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/fixed-list', + requestType: 'application/vnd.referencedata.get-all-fixed-list+json' + }); + }); + }); + }); + + describe('fetchHearingTypes()', () => { + it('should fetch hearing types', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ hearingTypes: [] })); + + service.fetchHearingTypes().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/hearing-types', + requestType: 'application/vnd.referencedata.query.hearing-types+json' + }); + }); + }); + }); + + describe('fetchLocalJusticAreas()', () => { + it('should fetch local justice areas', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ localJusticeAreas: [] })); + + service.fetchLocalJusticAreas().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/local-justice-areas', + requestType: 'application/vnd.referencedata.query.local-justice-areas+json' + }); + }); + }); + }); + + describe('fetchOrganisationUnits()', () => { + it('should fetch organisation units', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ organisationunits: [] })); + + service.fetchOrganisationUnits().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/organisationunits', + requestType: 'application/vnd.referencedata.query.organisationunits+json' + }); + }); + }); + }); + + describe('fetchPoliceForceList()', () => { + it('should fetch Police Force List', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ policeForces: [] })); + + service.fetchPoliceForceList().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/police-forces', + requestType: 'application/vnd.referencedata.police-forces+json' + }); + }); + }); + }); + + describe('fetchProsecutors()', () => { + it('should fetch prosecutors', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ prosecutors: [] })); + + service.fetchProsecutors().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/prosecutors', + requestType: 'application/vnd.referencedata.query.prosecutors-with-nsp+json' + }); + }); + }); + }); + + describe('fetchResultDefinition()', () => { + it('should fetch a result definition', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ id: 'resultDefinitionId' })); + + service.fetchResultDefinition('resultDefinitionId').subscribe((result) => { + expect(result).toEqual({ id: 'resultDefinitionId' }); + expect(http.query).toHaveBeenCalledWith({ + url: `/referencedata-query-api/query/api/rest/referencedata/result-definitions/resultDefinitionId`, + requestType: 'application/vnd.referencedata.get-result-definition+json' + }); + }); + }); + }); + + describe('fetchResultDefinitions()', () => { + it('should fetch all result definitions', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ resultDefinitions: [] })); + + service.fetchResultDefinitions().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/result-definitions', + requestType: 'application/vnd.referencedata.get-all-result-definitions+json' + }); + }); + }); + }); + + describe('fetchRotaBusinessTypes()', () => { + it('should fetch all rota business types', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ rotaBusinessTypes: [] })); + + service.fetchRotaBusinessTypes().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/rota-business-types', + requestType: 'application/vnd.referencedata.query.rota-business-types+json' + }); + }); + }); + }); + + describe('fetchPleaTypes()', () => { + it('should fetch all plea types', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ pleaStatusTypes: [] })); + + service.fetchPleaTypes().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/plea-types', + requestType: 'application/vnd.referencedata.plea-types+json' + }); + }); + }); + }); + + describe('fetchSpecialRequirements()', () => { + it('should fetch special requirements', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ specialRequirements: [] })); + + service.fetchSpecialRequirements().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/special-requirements', + requestType: 'application/vnd.referencedata.query.special-requirements+json' + }); + }); + }); + }); + + describe('fetchWitnessCareUnits()', () => { + it('should fetch witness care units', () => { + (http.query as jest.Mock).mockReturnValue(of({ witnessCareUnits: [] })); + + service.fetchPleaTypes().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/witness-care-units', + requestType: + 'application/vnd.referencedata.query.witness-care-unit-with-police-force-code+json' + }); + }); + }); + }); + + describe('fetchJudicialMembers()', () => { + it('should fetch judicial members', () => { + (http.query as jest.Mock).mockReturnValue(of({ judiciaries: [] })); + + service.fetchJudicialMembers({}).subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/judiciaries', + requestType: 'application/vnd.reference-data.judiciaries+json' + }); + }); + }); + }); + + describe('searchApplicationTypes()', () => { + it('should search application types', () => { + expect.assertions(2); + + const params = { q: '*', limit: 10 }; + (http.query as jest.Mock).mockReturnValue(of({ courtApplicationTypes: [] })); + + service.searchApplicationTypes(params).subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/application-types', + requestType: 'application/vnd.referencedata.application-types+json', + params: mapObjectToHttpParams(params) + }); + }); + }); + }); + + describe('searchApplicationStandAloneTypes()', () => { + it('should stand alone search application types', (done) => { + expect.assertions(2); + + const params = { search: '*', limit: 10 }; + (http.query as jest.Mock).mockReturnValue(of({ courtApplicationTypes: [] })); + + service.searchApplicationStandAloneTypes(params).subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/referencedata-moj-offences', + requestType: 'application/vnd.referencedata.query.moj-offences+json', + params: mapObjectToHttpParams(params) + }); + done(); + }); + }); + }); + + describe('getPoliceRanks()', () => { + it('should get the police ranks ', () => { + (http.query as jest.Mock).mockReturnValue(of({ policeRanks: [] })); + service.fetchPoliceRanks().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/police-ranks', + requestType: 'application/vnd.referencedata.police-ranks+json' + }); + }); + }); + }); + describe('fetchPublicHolidays()', () => { + it('should fetch public holidays', () => { + (http.query as jest.Mock).mockReturnValue(of({ publicHolidays: [] })); + + service.fetchPublicHolidays().subscribe((result) => { + expect(result).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/referencedata-query-api/query/api/rest/referencedata/public-holidays', + requestType: 'application/vnd.referencedata.query.public-holidays+json' + }); + }); + }); + }); +}); diff --git a/projects/reference-data/src/services/reference-data.service.ts b/projects/reference-data/src/services/reference-data.service.ts new file mode 100644 index 0000000..0ea7071 --- /dev/null +++ b/projects/reference-data/src/services/reference-data.service.ts @@ -0,0 +1,336 @@ +import { HttpParams } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { CppHttp, mapObjectToHttpParams } from '@cpp/core'; +import { Observable, of } from 'rxjs'; +import { map, shareReplay, tap } from 'rxjs/operators'; +import { + Cluster, + CourtApplicationType, + CPSArea, + CPSBusinessUnit, + CPSCaseStatus, + FixedList, + HearingType, + JudicialMember, + JudiciaryGroupType, + LocalJusticeArea, + OrganisationUnit, + PleaType, + PoliceForce, + Prosecutor, + ResultDefinition, + ReusableInfoDefinitions, + RotaBusinessType, + RotaBusinessTypeJurisdiction, + TrialType, + SelectedJudiciaryOptions, + WitnessCareUnit, + SpecialRequirement, + HearingPriority, + BookingType, + PoliceRank, + PublicHoliday, + OrganisationType, + OrganisationWithType, + Offence +} from '../reference-data.interfaces'; +import { mapApplicationType } from '../utils/mapper'; + +@Injectable() +export class ReferenceDataService { + private resuableInfoDefinitionsCache: Record> = {}; + + constructor(private cppHttp: CppHttp) {} + + fetchApplicationTypes(): Observable { + return this.cppHttp + .query<{ courtApplicationTypes: CourtApplicationType[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/application-types', + requestType: 'application/vnd.referencedata.application-types+json' + }) + .pipe(map((data) => data.courtApplicationTypes)); + } + + fetchAssignPriorities(): Observable { + return this.cppHttp + .query<{ hearingPriorities: HearingPriority[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/hearing-priorities', + requestType: 'application/vnd.referencedata.query.hearing-priorities+json' + }) + .pipe(map((data) => (data.hearingPriorities || []).sort((a, b) => a.seqNum - b.seqNum))); + } + + fetchBookingTypes(): Observable { + return this.cppHttp + .query<{ bookingTypes: BookingType[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/booking-types', + requestType: 'application/vnd.referencedata.query.booking-types+json' + }) + .pipe(map((data) => data.bookingTypes)); + } + + fetchClusters(): Observable { + return this.cppHttp + .query<{ clusterInformation: Cluster[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/cluster-information', + requestType: 'application/vnd.referencedata.query.cluster-information+json' + }) + .pipe(map((data) => data.clusterInformation)); + } + + fetchCPSAreas(): Observable { + return this.cppHttp + .query<{ cpsAreas: CPSArea[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/cps-areas', + requestType: 'application/vnd.referencedata.query.cps-area+json' + }) + .pipe(map((data) => data.cpsAreas)); + } + + fetchCPSBusinessUnits(): Observable { + return this.cppHttp + .query<{ cpsBusinessUnits: CPSBusinessUnit[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/cps-business-units', + requestType: 'application/vnd.referencedata.query.cps-business-unit+json' + }) + .pipe(map((data) => data.cpsBusinessUnits)); + } + + fetchCPSCaseStatuses(): Observable { + return this.cppHttp + .query<{ cpsCaseStatuses: CPSCaseStatus[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/cps-case-statuses', + requestType: 'application/vnd.referencedata.query.cps-case-statuses+json' + }) + .pipe(map((data) => data.cpsCaseStatuses)); + } + + fetchFixedLists(): Observable { + return this.cppHttp + .query<{ fixedListCollection: FixedList[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/fixed-list', + requestType: 'application/vnd.referencedata.get-all-fixed-list+json' + }) + .pipe(map((data) => data.fixedListCollection)); + } + + fetchHearingTypes(): Observable { + return this.cppHttp + .query<{ hearingTypes: HearingType[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/hearing-types', + requestType: 'application/vnd.referencedata.query.hearing-types+json' + }) + .pipe(map((data) => data.hearingTypes)); + } + + fetchJudiciaryGroupTypes(): Observable { + return this.cppHttp + .query<{ judiciaryTypes: JudiciaryGroupType[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/judiciary-types', + requestType: 'application/vnd.referencedata.query.judiciary-types+json' + }) + .pipe(map((data) => data.judiciaryTypes)); + } + + fetchLocalJusticAreas(): Observable { + return this.cppHttp + .query<{ localJusticeAreas: LocalJusticeArea[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/local-justice-areas', + requestType: 'application/vnd.referencedata.query.local-justice-areas+json' + }) + .pipe(map((data) => data.localJusticeAreas)); + } + + /** + * Fetches the organisation units and related courtrooms. + */ + fetchOrganisationUnits(includeExpired = false): Observable { + return this.cppHttp + .query<{ organisationunits: OrganisationUnit[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/courtrooms', // The api call end point courtrooms fetches the organisation unit and courtrooms + requestType: includeExpired + ? 'application/vnd.referencedata.ou-courtrooms-all+json' + : 'application/vnd.referencedata.ou-courtrooms+json' + }) + .pipe(map((data) => data.organisationunits)); + } + + fetchPleaTypes(): Observable { + return this.cppHttp + .query<{ pleaStatusTypes: PleaType[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/plea-types', + requestType: 'application/vnd.referencedata.plea-types+json' + }) + .pipe(map((data) => data.pleaStatusTypes)); + } + + fetchPoliceForceList(): Observable { + return this.cppHttp + .query<{ policeForces: PoliceForce[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/police-forces', + requestType: 'application/vnd.referencedata.police-forces+json' + }) + .pipe(map((data) => data.policeForces)); + } + + fetchProsecutors(): Observable { + return this.cppHttp + .query<{ prosecutors: Prosecutor[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/prosecutors', + requestType: 'application/vnd.referencedata.query.prosecutors-with-nsp+json' + }) + .pipe(map((data) => data.prosecutors)); + } + + fetchResultDefinition(resultDefinitionId: string): Observable { + return this.cppHttp.query({ + url: `/referencedata-query-api/query/api/rest/referencedata/result-definitions/${resultDefinitionId}`, + requestType: 'application/vnd.referencedata.get-result-definition+json' + }); + } + + fetchResultDefinitions(): Observable { + return this.cppHttp + .query<{ resultDefinitions: ResultDefinition[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/result-definitions', + requestType: 'application/vnd.referencedata.get-all-result-definitions+json' + }) + .pipe(map((data) => data.resultDefinitions)); + } + + fetchResuableInfoDefinitions( + orderedDate: string, + options: Record = {} + ): Observable { + if (!this.resuableInfoDefinitionsCache[orderedDate]) { + this.resuableInfoDefinitionsCache[orderedDate] = this.cppHttp + .query<{ reusableInfoDefinitions: ReusableInfoDefinitions }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/reusable-info-definitions', + requestType: 'application/vnd.referencedata.query.get-reusable-info-definitions+json', + params: new HttpParams({ fromObject: { orderedDate } }), + ...options + }) + .pipe( + map((result) => result.reusableInfoDefinitions), + shareReplay(1), + tap({ + error: () => { + delete this.resuableInfoDefinitionsCache[orderedDate]; + } + }) + ); + } + return this.resuableInfoDefinitionsCache[orderedDate]; + } + + fetchRotaBusinessTypes( + params: { jurisdiction: RotaBusinessTypeJurisdiction | 'ALL' } = { jurisdiction: 'ALL' } + ): Observable { + return this.cppHttp + .query<{ rotaBusinessTypes: RotaBusinessType[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/rota-business-types', + requestType: 'application/vnd.referencedata.query.rota-business-types+json', + params: mapObjectToHttpParams(params) + }) + .pipe(map((data) => data.rotaBusinessTypes)); + } + + fetchSpecialRequirements(): Observable { + return this.cppHttp + .query<{ specialRequirements: SpecialRequirement[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/special-requirements', + requestType: 'application/vnd.referencedata.query.special-requirements+json' + }) + .pipe(map((data) => data.specialRequirements)); + } + + fetchWitnessCareUnits(): Observable { + return this.cppHttp + .query<{ witnessCareUnits: WitnessCareUnit[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/witness-care-units', + requestType: + 'application/vnd.referencedata.query.witness-care-unit-with-police-force-code+json' + }) + .pipe(map((data) => data.witnessCareUnits)); + } + + fetchJudicialMembers(options: SelectedJudiciaryOptions): Observable { + let params = new HttpParams(); + + Object.entries(options).forEach((option) => { + if (option[1]) { + params = params.set(option[0], String(option[1])); + } + }); + + return this.cppHttp + .query<{ judiciaries: JudicialMember[] }>({ + url: `/referencedata-query-api/query/api/rest/referencedata/judiciaries`, + requestType: 'application/vnd.reference-data.judiciaries+json', + params + }) + .pipe(map((res) => res.judiciaries)); + } + + fetchResultPromptWordSynonyms() {} + + fetchResultWordSynonyms() {} + + searchApplicationTypes(params: { q: string; limit: number }): Observable { + return this.cppHttp + .query<{ courtApplicationTypes: CourtApplicationType[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/application-types-search', + requestType: 'application/vnd.referencedata.application-types-search+json', + params: mapObjectToHttpParams(params) + }) + .pipe(map((data) => data.courtApplicationTypes)); + } + + searchApplicationStandAloneTypes(params: { + search: string; + limit: number; + }): Observable { + return this.cppHttp + .query<{ offences: Offence[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/referencedata-moj-offences', + requestType: 'application/vnd.referencedata.query.moj-offences+json', + params: mapObjectToHttpParams(params) + }) + .pipe(map((data) => mapApplicationType(data.offences))); + } + + fetchTrialTypes(): Observable { + return this.cppHttp + .query<{ crackedIneffectiveVacatedTrialTypes: TrialType[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/cracked-ineffective-vacated-trial-types', + requestType: 'application/vnd.referencedata.cracked-ineffective-vacated-trial-types+json' + }) + .pipe(map((data) => data.crackedIneffectiveVacatedTrialTypes)); + } + + fetchPoliceRanks(): Observable { + return this.cppHttp + .query<{ policeRanks: PoliceRank[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/police-ranks', + requestType: 'application/vnd.referencedata.police-ranks+json' + }) + .pipe(map((data) => data.policeRanks)); + } + fetchPublicHolidays(): Observable { + return this.cppHttp + .query<{ publicHolidays: PublicHoliday[] }>({ + url: '/referencedata-query-api/query/api/rest/referencedata/public-holidays', + requestType: 'application/vnd.referencedata.query.public-holidays+json' + }) + .pipe(map((data) => data.publicHolidays)); + } + + fetchOrganisationsWithType(orgType: OrganisationType): Observable { + return this.cppHttp + .query<{ organisationTypes: OrganisationWithType[] }>({ + url: `/referencedata-query-api/query/api/rest/referencedata/organisation?orgType=${orgType}`, + requestType: 'application/vnd.referencedata.query.organisation.byOrgType+json' + }) + .pipe(map((data) => data.organisationTypes)); + } +} diff --git a/projects/reference-data/src/utils/__tests__/judicial-member-name.pipe.spec.ts b/projects/reference-data/src/utils/__tests__/judicial-member-name.pipe.spec.ts new file mode 100644 index 0000000..8098e97 --- /dev/null +++ b/projects/reference-data/src/utils/__tests__/judicial-member-name.pipe.spec.ts @@ -0,0 +1,53 @@ +import { JudicialMemberNamePipe } from '../judicial-member-name.pipe'; + +describe('JudiciaryFullNamePipe', () => { + const pipe = new JudicialMemberNamePipe(); + + it('should display all the prefixes and sufixes for the judiciary', () => { + expect( + pipe.transform({ + titlePrefix: 'Mr.', + titleJudicialPrefix: 'HHJ', + titleSuffix: 'QC', + emailAddress: 'test@email', + id: '19ffac44-3533-410d-868e-81cf825844b6', + seqId: 1, + forenames: 'John', + surname: 'Smith', + judiciaryType: 'Circuit Judge' + }) + ).toEqual('Mr. HHJ SMITH QC'); + }); + + it('should display requestedName for DDJ and Recorders', () => { + expect( + pipe.transform({ + titlePrefix: 'Mr.', + titleJudicialPrefix: 'HHJ', + titleSuffix: '', + requestedName: 'DDJ John Smith QC', + emailAddress: 'test@email', + id: '19ffac44-3533-410d-868e-81cf825844b6', + seqId: 1, + forenames: 'John', + surname: 'Smith', + judiciaryType: 'Deputy District Judge (MC)- Fee paid' + }) + ).toEqual('DDJ John Smith QC'); + + expect( + pipe.transform({ + titlePrefix: 'Mr.', + titleJudicialPrefix: 'HHJ', + titleSuffix: '', + emailAddress: 'test@email', + requestedName: 'RECORDER John Smith QC', + id: '19ffac44-3533-410d-868e-81cf825844b6', + seqId: 1, + forenames: 'John', + surname: 'Smith', + judiciaryType: 'Recorder' + }) + ).toEqual('RECORDER John Smith QC'); + }); +}); diff --git a/projects/reference-data/src/utils/__tests__/mapper.spec.ts b/projects/reference-data/src/utils/__tests__/mapper.spec.ts new file mode 100644 index 0000000..e18a94d --- /dev/null +++ b/projects/reference-data/src/utils/__tests__/mapper.spec.ts @@ -0,0 +1,98 @@ +import { mapApplicationType } from '../mapper'; +import { + Offence, + CourtApplicationType, + LinkType, + SummonsTemplateType, + OffenceActiveOrderType, + BreachType +} from '../../reference-data.interfaces'; + +describe('mapApplicationType', () => { + it('should return an empty array when no offences are provided', () => { + const result = mapApplicationType([]); + expect(result).toEqual([]); + }); + + it('should map offences to CourtApplicationType correctly', () => { + const offences: Offence[] = [ + { + offenceId: '1', + title: 'Offence Title', + offenceType: 'Category Code', + cjsOffenceCode: 'CJS123', + legislation: 'Legislation', + startDate: '2023-01-01', + pssOffenceId: 'PSS123', + offenceWording: 'Offence Wording', + titleWelsh: 'Title Welsh', + changeDate: '2023-01-02' + } as Offence + ]; + + const expected: CourtApplicationType[] = [ + { + id: '1', + type: 'Offence Title', + typeWelsh: 'Title Welsh', + categoryCode: 'Category Code', + jurisdiction: 'MAGISTRATES', + linkType: LinkType.STANDALONE, + code: 'CJS123', + legislation: 'Legislation', + validFrom: '2023-01-01T00:00:00.000Z', + appealFlag: false, + summonsTemplateType: SummonsTemplateType.NOT_APPLICABLE, + hearingCode: 'APL', + applicantAppellantFlag: false, + pleaApplicableFlag: false, + offenceActiveOrder: OffenceActiveOrderType.NOT_APPLICABLE, + commrOfOathFlag: false, + breachType: BreachType.NOT_APPLICABLE, + courtOfAppealFlag: false, + courtExtractAvlFlag: true, + listingNotifTemplate: 'POSTAL_NOTIFICATION', + boxworkNotifTemplate: 'NOT_APPLICABLE', + prosecutorThirdPartyFlag: false, + spiOutApplicableFlag: true, + pssId: 'PSS123', + applicationWording: 'Offence Wording', + initialFeeApplicable: false, + contestedFeeApplicable: false, + exParte: false, + sowRef: 'APPS', + changeDate: '2023-01-02T00:00:00.000Z', + lastModified: '2023-01-02T00:00:00.000Z', + resentencingActivationCode: '', + prefix: '' + } + ]; + + const result = mapApplicationType(offences); + expect(result).toEqual(expected); + }); + + it('should handle offences with missing optional fields', () => { + const offences: Offence[] = [ + { + offenceId: '2', + title: 'Another Offence', + offenceType: 'Another Category', + cjsOffenceCode: undefined, + legislation: undefined, + startDate: undefined, + pssOffenceId: undefined, + offenceWording: undefined, + changeDate: undefined + } as any + ]; + + const result = mapApplicationType(offences); + expect(result[0].code).toBeUndefined(); + expect(result[0].legislation).toBeUndefined(); + expect(result[0].validFrom).toEqual(''); + expect(result[0].pssId).toBeUndefined(); + expect(result[0].applicationWording).toBeUndefined(); + expect(result[0].changeDate).toEqual(''); + }); +}); diff --git a/projects/reference-data/src/utils/__tests__/sort-select-options-Alphabetical.spec.ts b/projects/reference-data/src/utils/__tests__/sort-select-options-Alphabetical.spec.ts new file mode 100644 index 0000000..7e984b7 --- /dev/null +++ b/projects/reference-data/src/utils/__tests__/sort-select-options-Alphabetical.spec.ts @@ -0,0 +1,27 @@ +import { sortSelectOptionAlphabetical } from '../sort-select-options-Alphabetical'; + +describe('sortAlphabetical', () => { + it('should sort options alphabetically by label', () => { + const input = [ + { value: '2', label: 'Bexley Mags Court' }, + { value: '1', label: 'Acton Mags Court' }, + { value: '3', label: 'Cambridge Mags Court' } + ]; + + const sorted = [...input].sort(sortSelectOptionAlphabetical); + + expect(sorted).toEqual([ + { value: '1', label: 'Acton Mags Court' }, + { value: '2', label: 'Bexley Mags Court' }, + { value: '3', label: 'Cambridge Mags Court' } + ]); + }); + + it('should return 0 for equal labels', () => { + const result = sortSelectOptionAlphabetical( + { value: '1', label: 'Same' }, + { value: '2', label: 'same' } + ); + expect(result).toBe(0); + }); +}); diff --git a/projects/reference-data/src/utils/judicial-member-name.pipe.ts b/projects/reference-data/src/utils/judicial-member-name.pipe.ts new file mode 100644 index 0000000..91691ea --- /dev/null +++ b/projects/reference-data/src/utils/judicial-member-name.pipe.ts @@ -0,0 +1,45 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { mapRefDataJudiciaryToJudiciaryType } from '../helpers/judiciary-type.helper'; +import { JudicialMember } from '../reference-data.interfaces'; + +@Pipe({ + name: 'judicialMemberName', + standalone: true +}) +export class JudicialMemberNamePipe implements PipeTransform { + transform(judiciary: JudicialMember): string { + if (!judiciary) { + return ''; + } + + if ( + mapRefDataJudiciaryToJudiciaryType(judiciary.judiciaryType) === 'DEPUTY_DISTRICT_JUDGE' || + mapRefDataJudiciaryToJudiciaryType(judiciary.judiciaryType) === 'RECORDER' + ) { + return this.getNameForRecorderAndDDJ(judiciary); + } + + return this.getNameForAllJudiciaryTypes(judiciary); + } + + private getNameForRecorderAndDDJ(judiciary: JudicialMember): string { + return judiciary.requestedName || ''; + } + + private getNameForAllJudiciaryTypes(judiciary: JudicialMember): string { + let result = ''; + + if (judiciary.titlePrefix) { + result += judiciary.titlePrefix + ' '; + } + if (judiciary.titleJudicialPrefix) { + result += judiciary.titleJudicialPrefix + ' '; + } + result += judiciary.surname.toLocaleUpperCase(); + + if (judiciary.titleSuffix) { + result += ' ' + judiciary.titleSuffix; + } + return result; + } +} diff --git a/projects/reference-data/src/utils/mapper.ts b/projects/reference-data/src/utils/mapper.ts new file mode 100644 index 0000000..5bd3828 --- /dev/null +++ b/projects/reference-data/src/utils/mapper.ts @@ -0,0 +1,68 @@ +import { + BreachType, + CourtApplicationType, + LinkType, + Offence, + OffenceActiveOrderType, + SummonsTemplateType +} from '../reference-data.interfaces'; + +const formatDate = (dateStr: string): string => { + if (!dateStr) { + return ''; + } + + let normalized = dateStr.trim(); + + // If it's just a date (YYYY-MM-DD), add time + if (/^\d{4}-\d{2}-\d{2}$/.test(normalized)) { + normalized += 'T00:00:00'; + } + + // Add Z if not present + if (!/[Z+-]\d{0,2}:\d{0,2}$/.test(normalized)) { + normalized += 'Z'; + } + + return new Date(normalized).toISOString(); +}; + +export const mapApplicationType = (offences: Offence[] = []): CourtApplicationType[] => + offences.map( + (offence) => + ({ + id: offence.offenceId, + type: offence.title, + categoryCode: offence.offenceType, + jurisdiction: 'MAGISTRATES', + linkType: LinkType.STANDALONE, + code: offence.cjsOffenceCode, + legislation: offence.legislation, + validFrom: formatDate(offence.startDate), + appealFlag: false, + summonsTemplateType: SummonsTemplateType.NOT_APPLICABLE, + hearingCode: 'APL', + applicantAppellantFlag: false, + pleaApplicableFlag: false, + offenceActiveOrder: OffenceActiveOrderType.NOT_APPLICABLE, + commrOfOathFlag: false, + breachType: BreachType.NOT_APPLICABLE, + courtOfAppealFlag: false, + courtExtractAvlFlag: true, + listingNotifTemplate: 'POSTAL_NOTIFICATION', + boxworkNotifTemplate: 'NOT_APPLICABLE', + typeWelsh: offence.titleWelsh, + prosecutorThirdPartyFlag: false, + spiOutApplicableFlag: true, + pssId: offence.pssOffenceId, + applicationWording: offence.offenceWording, + initialFeeApplicable: false, + contestedFeeApplicable: false, + exParte: false, + sowRef: 'APPS', + changeDate: formatDate(offence.changeDate), + lastModified: formatDate(offence.changeDate), + resentencingActivationCode: '', + prefix: '' + } as CourtApplicationType) + ); diff --git a/projects/reference-data/src/utils/sort-select-options-Alphabetical.ts b/projects/reference-data/src/utils/sort-select-options-Alphabetical.ts new file mode 100644 index 0000000..c3a6b9c --- /dev/null +++ b/projects/reference-data/src/utils/sort-select-options-Alphabetical.ts @@ -0,0 +1,20 @@ +import { SelectOption } from '@cpp/pdk'; + +/** + * A comparator function to sort an array of select options alphabetically. + * This function expects objects that extend the SelectOption interface with a string label. + * It converts the label values to uppercase to ensure a case-insensitive comparison. + * + * @param a - The first select option to compare. + * @param b - The second select option to compare. + * @returns A negative number if `a.label` comes before `b.label`, a positive number if `a.label` comes after `b.label`, or 0 if they are equal. + */ +export const sortSelectOptionAlphabetical = >( + a: T, + b: T +): number => { + const aText = a.label.toUpperCase(); + const bText = b.label.toUpperCase(); + + return aText < bText ? -1 : aText > bText ? 1 : 0; +}; diff --git a/projects/reference-data/tsconfig.lib.json b/projects/reference-data/tsconfig.lib.json new file mode 100644 index 0000000..e457f81 --- /dev/null +++ b/projects/reference-data/tsconfig.lib.json @@ -0,0 +1,32 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "../../out-tsc/lib", + "declarationMap": true, + "module": "es2015", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "inlineSources": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "skipLibCheck": true, + "types": [], + "lib": ["dom", "es2018"], + "paths": { + "@cpp/core": ["../../dist/core"], + "@cpp/users-groups": ["../../dist/users-groups"] + } + }, + "angularCompilerOptions": { + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true, + "compilationMode": "partial" + }, + "exclude": ["**/*.spec.ts"] +} diff --git a/projects/reference-data/tsconfig.lib.prod.json b/projects/reference-data/tsconfig.lib.prod.json new file mode 100644 index 0000000..2a2faa8 --- /dev/null +++ b/projects/reference-data/tsconfig.lib.prod.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/projects/reference-data/tsconfig.spec.json b/projects/reference-data/tsconfig.spec.json new file mode 100644 index 0000000..16dce72 --- /dev/null +++ b/projects/reference-data/tsconfig.spec.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "allowJs": true, + "module": "commonjs", + "outDir": "../../out-tsc/spec", + "types": ["jest", "node"] + }, + "include": ["**/*.spec.ts", "**/*.d.ts"] +} diff --git a/projects/scheduling/.eslintrc.json b/projects/scheduling/.eslintrc.json new file mode 100644 index 0000000..8acac6c --- /dev/null +++ b/projects/scheduling/.eslintrc.json @@ -0,0 +1,23 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": [ + "projects/scheduling/tsconfig.lib.json", + "projects/scheduling/tsconfig.spec.json" + ] + }, + "rules": { + "@angular-eslint/no-output-on-prefix": "off", + "@angular-eslint/no-input-rename": "off" + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/projects/scheduling/ng-package.json b/projects/scheduling/ng-package.json new file mode 100644 index 0000000..7c0337e --- /dev/null +++ b/projects/scheduling/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/scheduling", + "lib": { + "entryFile": "src/public-api.ts" + } +} diff --git a/projects/scheduling/package.json b/projects/scheduling/package.json new file mode 100644 index 0000000..52172db --- /dev/null +++ b/projects/scheduling/package.json @@ -0,0 +1,16 @@ +{ + "name": "@cpp/scheduling", + "version": "0.0.0-PLACEHOLDER", + "peerDependencies": { + "@angular/common": "^19.0.0", + "@angular/core": "^19.0.0", + "@cpp/core": "^0.0.0-PLACEHOLDER", + "@cpp/pdk": "*", + "@cpp/reference-data": "^0.0.0-PLACEHOLDER" + }, + "peerDepenciesComment": "Do not modify placeholders in this file", + "dependencies": { + "tslib": "^2.3.0" + }, + "sideEffects": false +} diff --git a/projects/scheduling/src/actions/index.ts b/projects/scheduling/src/actions/index.ts new file mode 100644 index 0000000..9b9aa1a --- /dev/null +++ b/projects/scheduling/src/actions/index.ts @@ -0,0 +1,4 @@ +import * as SchedulingActions from './scheduling.actions'; +import * as ListingNotesActions from './listing-notes.actions'; + +export { SchedulingActions, ListingNotesActions }; diff --git a/projects/scheduling/src/actions/listing-notes.actions.ts b/projects/scheduling/src/actions/listing-notes.actions.ts new file mode 100644 index 0000000..b16e98e --- /dev/null +++ b/projects/scheduling/src/actions/listing-notes.actions.ts @@ -0,0 +1,45 @@ +import { createAction, props } from '@ngrx/store'; +import { ListingNote } from '../types'; + +export const loadListingNotes = createAction( + 'LOAD_LISTING_NOTES', + props<{ notes: ListingNote[] }>() +); + +export const createListingNote = createAction( + 'CREATE_LISTING_NOTE', + props<{ + note: { + hearingDate: string; + courtRoomId: string; + noteDescription: string; + }; + }>() +); + +export const createListingNoteSuccess = createAction( + 'CREATE_LISTING_NOTE_SUCCESS', + props<{ note: ListingNote }>() +); + +export const updateListingNote = createAction( + 'UPDATE_LISTING_NOTE', + props<{ noteId: string; noteDescription: string }>() +); + +export const updateListingNoteSuccess = createAction( + 'UPDATE_LISTING_NOTE_SUCCESS', + props<{ noteId: string; noteDescription: string }>() +); + +export const deleteListingNote = createAction('DELETE_LISTING_NOTE', props<{ noteId: string }>()); + +export const deleteListingNoteSuccess = createAction( + 'DELETE_LISTING_NOTE_SUCCESS', + props<{ noteId: string }>() +); + +export const showListingNoteSuccessMessage = createAction( + 'SHOW_LISTING_NOTE_SUCCESS_MESSAGE', + props<{ successMessage: string }>() +); diff --git a/projects/scheduling/src/actions/listing-notes.spec.ts b/projects/scheduling/src/actions/listing-notes.spec.ts new file mode 100644 index 0000000..48f1d67 --- /dev/null +++ b/projects/scheduling/src/actions/listing-notes.spec.ts @@ -0,0 +1,102 @@ +import { ListingNote } from '../types'; +import { + createListingNote, + createListingNoteSuccess, + deleteListingNote, + deleteListingNoteSuccess, + loadListingNotes, + updateListingNote, + updateListingNoteSuccess +} from './listing-notes.actions'; + +it('Should create a loadListingNotes action ', () => { + const notes = [ + { + id: 'listing-note-1', + courtRoomId: 'courtroom-id-1', + note: 'test', + date: '2020-09-16' + } as ListingNote + ]; + const action = loadListingNotes({ notes }); + + expect(action).toEqual({ + type: 'LOAD_LISTING_NOTES', + notes + }); +}); + +describe('Listing notes actions', () => { + it('Should create a createListingNote action ', () => { + const note = { + courtRoomId: 'courtroom-id-1', + noteDescription: 'test', + hearingDate: '2020-09-16' + }; + const action = createListingNote({ note }); + + expect(action).toEqual({ + type: 'CREATE_LISTING_NOTE', + note + }); + }); + + it('Should create a createListingNoteSuccess action ', () => { + const note = { + id: 'listing-note-1', + courtRoomId: 'courtroom-id-1', + note: 'test', + date: '2020-09-16' + } as ListingNote; + const action = createListingNoteSuccess({ note }); + + expect(action).toEqual({ + type: 'CREATE_LISTING_NOTE_SUCCESS', + note + }); + }); + + it('Should create a updateListingNote action ', () => { + const updateProperties = { + noteId: 'listing-note-1', + noteDescription: 'test' + }; + const action = updateListingNote(updateProperties); + + expect(action).toEqual({ + type: 'UPDATE_LISTING_NOTE', + ...updateProperties + }); + }); + + it('Should create a updateListingNoteSuccess action ', () => { + const updateProperties = { + noteId: 'listing-note-1', + noteDescription: 'test' + }; + const action = updateListingNoteSuccess(updateProperties); + + expect(action).toEqual({ + type: 'UPDATE_LISTING_NOTE_SUCCESS', + ...updateProperties + }); + }); + + it('Should create a deleteListingNote action ', () => { + const action = deleteListingNote({ noteId: 'listing-note-1' }); + + expect(action).toEqual({ + type: 'DELETE_LISTING_NOTE', + noteId: 'listing-note-1' + }); + }); + + it('Should create a deleteListingNoteSuccess action ', () => { + const action = deleteListingNoteSuccess({ noteId: 'listing-note-1' }); + + expect(action).toEqual({ + type: 'DELETE_LISTING_NOTE_SUCCESS', + noteId: 'listing-note-1' + }); + }); +}); diff --git a/projects/scheduling/src/actions/scheduling.actions.spec.ts b/projects/scheduling/src/actions/scheduling.actions.spec.ts new file mode 100644 index 0000000..ca05e6a --- /dev/null +++ b/projects/scheduling/src/actions/scheduling.actions.spec.ts @@ -0,0 +1,39 @@ +import { HearingSlot, SearchHearingSlotsParams } from '../types'; // adjust import if enums are elsewhere +import { loadHearingSlotsSuccess, resetHearingSlots } from './scheduling.actions'; + +describe('Scheduling slots actions', () => { + it('Should create a loadHearingSlotsSuccess action', () => { + const params: SearchHearingSlotsParams = { + sessionStartDate: '2025-04-10' + }; + + const hearingSlots: HearingSlot[] = [ + { + courtScheduleId: '1', + panel: 'ADULT', + sessionDate: '2025-04-10', + courtSession: 'AM', + slotBased: true + } as HearingSlot + ]; + + const totalResults = 1; + + const action = loadHearingSlotsSuccess({ params, hearingSlots, totalResults }); + + expect(action).toEqual({ + type: 'LOAD_SCHEDULING_SLOTS_SUCCESS', + params, + hearingSlots, + totalResults + }); + }); + + it('Should create a resetHearingSlots action', () => { + const action = resetHearingSlots(); + + expect(action).toEqual({ + type: 'RESET_SCHEDULING_SLOTS' + }); + }); +}); diff --git a/projects/scheduling/src/actions/scheduling.actions.ts b/projects/scheduling/src/actions/scheduling.actions.ts new file mode 100644 index 0000000..3c64715 --- /dev/null +++ b/projects/scheduling/src/actions/scheduling.actions.ts @@ -0,0 +1,13 @@ +import { createAction, props } from '@ngrx/store'; +import { HearingSlot, SearchHearingSlotsParams } from '../types'; + +export const loadHearingSlotsSuccess = createAction( + 'LOAD_SCHEDULING_SLOTS_SUCCESS', + props<{ + params: SearchHearingSlotsParams; + hearingSlots: HearingSlot[]; + totalResults: number; + }>() +); + +export const resetHearingSlots = createAction('RESET_SCHEDULING_SLOTS'); diff --git a/projects/scheduling/src/components/estimate-input/estimate-input.html b/projects/scheduling/src/components/estimate-input/estimate-input.html new file mode 100644 index 0000000..9d9aeca --- /dev/null +++ b/projects/scheduling/src/components/estimate-input/estimate-input.html @@ -0,0 +1,79 @@ +
+ @if (weeksEnabled()) { +
+ + + +
+ } @if (daysEnabled()) { +
+ + + +
+ } @if (hoursEnabled()) { +
+ + + +
+ } + +
+ + + +
+
diff --git a/projects/scheduling/src/components/estimate-input/estimate-input.scss b/projects/scheduling/src/components/estimate-input/estimate-input.scss new file mode 100644 index 0000000..a7d43f7 --- /dev/null +++ b/projects/scheduling/src/components/estimate-input/estimate-input.scss @@ -0,0 +1,12 @@ +// @import '../core/toolkit'; + +$module: 'estimate-input'; + +#{$module} { + .form-group { + float: left; + margin-right: 20px; + margin-bottom: 0; + clear: none; + } +} diff --git a/projects/scheduling/src/components/estimate-input/estimate-input.spec.ts b/projects/scheduling/src/components/estimate-input/estimate-input.spec.ts new file mode 100644 index 0000000..38a1412 --- /dev/null +++ b/projects/scheduling/src/components/estimate-input/estimate-input.spec.ts @@ -0,0 +1,552 @@ +import { Component, DebugElement, Type } from '@angular/core'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { FormControl, FormsModule, NgForm, ReactiveFormsModule } from '@angular/forms'; +import { By } from '@angular/platform-browser'; +import { CommonModule } from '@angular/common'; + +import { EstimateInput } from './estimate-input'; +import { PdkForm, PdkInput, PdkTextInput } from '@cpp/pdk'; + +function initTest(component: Type, ...directives: Type[]): ComponentFixture { + TestBed.configureTestingModule({ + declarations: [component, ...directives], + imports: [ + FormsModule, + ReactiveFormsModule, + CommonModule, + PdkForm, + PdkInput, + PdkTextInput, + EstimateInput + ], + teardown: { destroyAfterEach: false } + }); + return TestBed.createComponent(component); +} + +interface TestEstimateInput { + model: number; + focus?: () => void; + blur?: () => void; + daysPerWeek?: number; + hoursPerDay?: number; +} + +describe('estimate-input', () => { + let estimate: FormControl; + let form: NgForm; + let fixture: ComponentFixture; + let weeksInput: DebugElement; + let daysInput: DebugElement; + let hoursInput: DebugElement; + let minutesInput: DebugElement; + + const initTestWith = (C: Type) => + fakeAsync(() => { + fixture = initTest(C); + fixture.detectChanges(); + tick(); + form = fixture.debugElement.children[0].injector.get(NgForm); + estimate = form.control.get('estimate') as FormControl; + weeksInput = fixture.debugElement.query(By.css('[name=estimateWeeks]')); + daysInput = fixture.debugElement.query(By.css('[name=estimateDays]')); + hoursInput = fixture.debugElement.query(By.css('[name=estimateHours]')); + minutesInput = fixture.debugElement.query(By.css('[name=estimateMinutes]')); + }); + + const setTimeValues = (values: { + weeks?: string; + days?: string; + hours?: string; + minutes?: string; + }) => { + const { weeks, days, hours, minutes } = values; + + if (weeksInput) { + weeksInput.nativeElement.value = weeks || ''; + weeksInput.nativeElement.dispatchEvent(new Event('input')); + } + if (daysInput) { + daysInput.nativeElement.value = days || ''; + daysInput.nativeElement.dispatchEvent(new Event('input')); + } + if (hoursInput) { + hoursInput.nativeElement.value = hours || ''; + hoursInput.nativeElement.dispatchEvent(new Event('input')); + } + minutesInput.nativeElement.value = minutes || ''; + minutesInput.nativeElement.dispatchEvent(new Event('input')); + }; + + describe('when only minutes are used', () => { + @Component({ + selector: 'estimate-minutes-input', + template: ` +
+ + +
+ `, + standalone: false + }) + class EstimateMinutes { + model!: number; + } + + beforeEach(initTestWith(EstimateMinutes)); + + it('hides the weeks, days and hours inputs', () => { + expect(weeksInput).toBeFalsy(); + expect(daysInput).toBeFalsy(); + expect(hoursInput).toBeFalsy(); + }); + + it('sets the model value when a value is entered', () => { + setTimeValues({ minutes: '61' }); + expect(estimate.value).toEqual(61); + }); + + it('populates the estimate inputs when an external value is provided', fakeAsync(() => { + fixture.componentInstance.model = 61; + fixture.detectChanges(); + tick(); + expect(minutesInput.nativeElement.value).toEqual('61'); + })); + + it('attaches the `aria-describedby` attributes to the minutes input', () => { + expect(minutesInput.nativeElement.getAttribute('aria-describedby')).toEqual('identifier'); + }); + }); + + describe('when hours are enabled', () => { + @Component({ + selector: 'estimate-hours-minutes-input', + template: ` +
+ + +
+ `, + standalone: false + }) + class EstimateHoursMinutes { + model!: number; + } + + beforeEach(initTestWith(EstimateHoursMinutes)); + + it('hides the weeks and days inputs', () => { + expect(weeksInput).toBeFalsy(); + expect(daysInput).toBeFalsy(); + }); + + it('sets the model value when a value is entered', () => { + setTimeValues({ hours: '2', minutes: '59' }); + expect(estimate.value).toEqual(179); + }); + + it('populates the estimate inputs when an external value is provided', fakeAsync(() => { + fixture.componentInstance.model = 60 * 24 + 30; + fixture.detectChanges(); + tick(); + expect(hoursInput.nativeElement.value).toEqual('24'); + expect(minutesInput.nativeElement.value).toEqual('30'); + })); + + it('attaches the `aria-describedby` attributes to the hours input', () => { + expect(hoursInput.nativeElement.getAttribute('aria-describedby')).toEqual('identifier'); + expect(minutesInput.nativeElement.getAttribute('aria-describedby')).toBeFalsy(); + }); + }); + + describe('when days and hours are enabled', () => { + @Component({ + selector: 'estimate-days-hours-minutes-input', + template: ` +
+ + +
+ `, + standalone: false + }) + class EstimateDaysHoursMinutes { + model!: number; + } + + beforeEach(initTestWith(EstimateDaysHoursMinutes)); + + it('hides the weeks input', () => { + expect(weeksInput).toBeFalsy(); + }); + + it('sets the model value when a value is entered', () => { + setTimeValues({ days: '1', hours: '2', minutes: '59' }); + expect(estimate.value).toEqual(539); + }); + + it('populates the estimate inputs when an external value is provided', fakeAsync(() => { + fixture.componentInstance.model = 100 * 360 + 60 * 5 + 30; + fixture.detectChanges(); + tick(); + expect(daysInput.nativeElement.value).toEqual('100'); + expect(hoursInput.nativeElement.value).toEqual('5'); + expect(minutesInput.nativeElement.value).toEqual('30'); + })); + + it('attaches the `aria-describedby` attributes to the days input', () => { + expect(daysInput.nativeElement.getAttribute('aria-describedby')).toEqual('identifier'); + expect(hoursInput.nativeElement.getAttribute('aria-describedby')).toBeFalsy(); + expect(minutesInput.nativeElement.getAttribute('aria-describedby')).toBeFalsy(); + }); + }); + + describe('when weeks, days and hours are enabled', () => { + @Component({ + selector: 'estimate-weeks-days-hours-minutes-input', + template: ` +
+ + +
+ `, + standalone: false + }) + class EstimateWeeksDaysHoursMinutes { + model!: number; + } + + beforeEach(initTestWith(EstimateWeeksDaysHoursMinutes)); + + it('sets the model value when a value is entered', () => { + setTimeValues({ weeks: '6', days: '3', hours: '2', minutes: '59' }); + expect(estimate.value).toEqual(16379); + }); + + it('populates the estimate inputs when an external value is provided', fakeAsync(() => { + fixture.componentInstance.model = 100 * 2520 + 3 * 360 + 60 * 5 + 30; + fixture.detectChanges(); + tick(); + expect(weeksInput.nativeElement.value).toEqual('100'); + expect(daysInput.nativeElement.value).toEqual('3'); + expect(hoursInput.nativeElement.value).toEqual('5'); + expect(minutesInput.nativeElement.value).toEqual('30'); + })); + + it('attaches the `aria-describedby` attributes to the weeks input', () => { + expect(weeksInput.nativeElement.getAttribute('aria-describedby')).toEqual('identifier'); + expect(daysInput.nativeElement.getAttribute('aria-describedby')).toBeFalsy(); + expect(hoursInput.nativeElement.getAttribute('aria-describedby')).toBeFalsy(); + expect(minutesInput.nativeElement.getAttribute('aria-describedby')).toBeFalsy(); + }); + }); + + describe('when days are enabled', () => { + @Component({ + selector: 'estimate-days-minutes-input', + template: ` +
+ + +
+ `, + standalone: false + }) + class EstimateDaysMinutes { + model!: number; + } + + beforeEach(initTestWith(EstimateDaysMinutes)); + + it('populates the estimate inputs when an external value is provided', fakeAsync(() => { + fixture.componentInstance.model = 3 * 360 + 1000; + fixture.detectChanges(); + tick(); + expect(daysInput.nativeElement.value).toEqual('5'); + expect(minutesInput.nativeElement.value).toEqual('280'); + })); + }); + + describe('when weeks are enabled', () => { + @Component({ + selector: 'estimate-weeks-minutes-input', + template: ` +
+ + +
+ `, + standalone: false + }) + class EstimateWeeksMinutes { + model!: number; + } + + beforeEach(initTestWith(EstimateWeeksMinutes)); + + it('populates the estimate inputs when an external value is provided', fakeAsync(() => { + fixture.componentInstance.model = 1 * 2520 + 100; + fixture.detectChanges(); + tick(); + expect(weeksInput.nativeElement.value).toEqual('1'); + expect(minutesInput.nativeElement.value).toEqual('100'); + })); + }); + + describe('when weeks and hours are enabled', () => { + @Component({ + selector: 'estimate-weeks-hours-minutes-input', + template: ` +
+ + +
+ `, + standalone: false + }) + class EstimateWeeksHoursMinutes { + model!: number; + } + + beforeEach(initTestWith(EstimateWeeksHoursMinutes)); + + it('populates the estimate inputs when an external value is provided', fakeAsync(() => { + fixture.componentInstance.model = 1 * 2520 + 60 * 20 + 5; + fixture.detectChanges(); + tick(); + expect(weeksInput.nativeElement.value).toEqual('1'); + expect(hoursInput.nativeElement.value).toEqual('20'); + expect(minutesInput.nativeElement.value).toEqual('5'); + })); + }); + + describe('when weeks and days are enabled', () => { + @Component({ + selector: 'estimate-weeks-days-minutes-input', + template: ` +
+ + +
+ `, + standalone: false + }) + class EstimateWeeksDaysMinutes { + model!: number; + } + + beforeEach(initTestWith(EstimateWeeksDaysMinutes)); + + it('populates the estimate inputs when an external value is provided', fakeAsync(() => { + fixture.componentInstance.model = 1 * 2520 + 5 * 360 + 59; + fixture.detectChanges(); + tick(); + expect(weeksInput.nativeElement.value).toEqual('1'); + expect(daysInput.nativeElement.value).toEqual('5'); + expect(minutesInput.nativeElement.value).toEqual('59'); + })); + }); + + describe('when any input configuration is used', () => { + @Component({ + selector: 'estimate-any-input', + template: ` +
+ + +
+ `, + standalone: false + }) + class EstimateAny { + model!: number; + focus?: () => void; + blur?: () => void; + } + + beforeEach(initTestWith(EstimateAny)); + + it('sets a value of `undefined` when no input is provided', () => { + setTimeValues({}); + expect(estimate.value).toBeUndefined(); + }); + + it('emits `focus` and `blur` events', fakeAsync(() => { + const focus = jest.fn(); + const blur = jest.fn(); + + fixture.componentInstance.focus = focus; + fixture.componentInstance.blur = blur; + tick(); + fixture.detectChanges(); + + hoursInput.nativeElement.dispatchEvent(new Event('focus')); + expect(focus).toHaveBeenCalledTimes(1); + + hoursInput.nativeElement.dispatchEvent(new Event('blur')); + minutesInput.nativeElement.dispatchEvent(new Event('focus')); + tick(); + expect(blur).toHaveBeenCalledTimes(0); + expect(focus).toHaveBeenCalledTimes(1); + + minutesInput.nativeElement.dispatchEvent(new Event('blur')); + tick(); + hoursInput.nativeElement.dispatchEvent(new Event('focus')); + expect(blur).toHaveBeenCalledTimes(1); + expect(focus).toHaveBeenCalledTimes(2); + })); + + it('raises a `estimateFormat` error for non-numeric inputs', () => { + expect(form.valid).toBe(true); + setTimeValues({ minutes: 'x' }); + expect(form.control.hasError('estimateFormat', ['estimate'])).toBe(true); + setTimeValues({ hours: 'x' }); + expect(form.control.hasError('estimateFormat', ['estimate'])).toBe(true); + setTimeValues({ days: 'x' }); + expect(form.control.hasError('estimateFormat', ['estimate'])).toBe(true); + setTimeValues({ weeks: 'x' }); + expect(form.control.hasError('estimateFormat', ['estimate'])).toBe(true); + }); + + it('isolates the internal inputs from the outer form', () => { + expect(form.control.get('estimateWeeks')).toBeFalsy(); + expect(form.control.get('estimateDays')).toBeFalsy(); + expect(form.control.get('estimateHours')).toBeFalsy(); + expect(form.control.get('estimateMinutes')).toBeFalsy(); + }); + }); + + describe('when daysPerWeek and hoursPerDay inputs are provided', () => { + @Component({ + selector: 'estimate-days-hours-minutes-input', + template: ` +
+ + +
+ `, + standalone: false + }) + class EstimateDaysHoursMinutes { + model!: number; + } + + beforeEach(initTestWith(EstimateDaysHoursMinutes)); + + it('sets the model value when a value is entered', () => { + setTimeValues({ days: '2', hours: '0', minutes: '0' }); + expect(estimate.value).toEqual(720); + setTimeValues({ weeks: '1', days: '0', hours: '0', minutes: '0' }); + expect(estimate.value).toEqual(1800); + }); + }); + + describe('when minimum value validator is provided', () => { + let component: EstimateInput; + + @Component({ + selector: 'estimate-days-hours-minutes-input', + template: ` +
+ + +
+ `, + standalone: false + }) + class EstimateMinValue { + model!: number; + } + + beforeEach(initTestWith(EstimateMinValue)); + + beforeEach(() => { + component = fixture.debugElement.query(By.directive(EstimateInput)).componentInstance; + }); + + it('sets the model value when a value is entered greater than the minimum minutes', () => { + setTimeValues({ minutes: '15' }); + expect(form.control.controls['estimate'].errors).toBeNull(); + expect(estimate.value).toEqual(15); + }); + + it('sets the model value when a value equal to the minimum minutes', () => { + setTimeValues({ minutes: '10' }); + expect(form.control.controls['estimate'].errors).toBeNull(); + expect(estimate.value).toEqual(10); + }); + + it('raises a `minMinutesEstimate` error if the supplied value is less than the minimum', () => { + setTimeValues({ minutes: '9' }); + expect(form.control.hasError('minMinutesEstimate', ['estimate'])).toBe(true); + expect(estimate.value).toEqual(9); + }); + + it('error message uses `minute` when minimum value is 1', fakeAsync(() => { + component.minMinutesValue = 1; + tick(); + fixture.detectChanges(); + setTimeValues({ minutes: '0' }); + const errorMessages = component.errorMessages; + const minMinutesMessage = errorMessages.find((msg) => msg.rule === 'minMinutesEstimate'); + expect(minMinutesMessage?.message).toContain('1 minute'); + })); + + it('error message uses `minutes` when minimum value is 10', () => { + setTimeValues({ minutes: '9' }); + const errorMessages = component.errorMessages; + const minMinutesMessage = errorMessages.find((msg) => msg.rule === 'minMinutesEstimate'); + expect(minMinutesMessage?.message).toContain('10 minutes'); + }); + }); +}); diff --git a/projects/scheduling/src/components/estimate-input/estimate-input.ts b/projects/scheduling/src/components/estimate-input/estimate-input.ts new file mode 100644 index 0000000..929062e --- /dev/null +++ b/projects/scheduling/src/components/estimate-input/estimate-input.ts @@ -0,0 +1,344 @@ +import { map } from 'rxjs/operators'; +import { + Component, + ElementRef, + EventEmitter, + forwardRef, + Injector, + input, + Input, + OnChanges, + OnInit, + Output, + Signal, + SimpleChanges, + viewChild, + ViewEncapsulation +} from '@angular/core'; +import { + ControlValueAccessor, + NgControl, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + Validator, + ValidationErrors, + FormGroup, + FormControl, + FormsModule, + ReactiveFormsModule +} from '@angular/forms'; +import { coerceBooleanProperty, FormFieldControl, PdkForm, PdkInput, PdkTextInput } from '@cpp/pdk'; + +let i = 0; + +const minutesPerHour = 60; + +interface FormInterface { + weeks?: FormControl; + days?: FormControl; + hours?: FormControl; + minutes: FormControl; +} + +@Component({ + selector: 'estimate-input', + templateUrl: './estimate-input.html', + styleUrls: ['./estimate-input.scss'], + providers: [ + { + provide: FormFieldControl, + useExisting: EstimateInput + }, + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => EstimateInput), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => EstimateInput), + multi: true + } + ], + encapsulation: ViewEncapsulation.None, + imports: [PdkForm, PdkTextInput, PdkInput, FormsModule, ReactiveFormsModule] +}) +export class EstimateInput + implements ControlValueAccessor, FormFieldControl, Validator, OnInit, OnChanges +{ + // eslint-disable-next-line @angular-eslint/no-input-rename + @Input('aria-describedby') ariaDescribedBy!: string; + @Input() hoursPerDay!: number; + @Input() daysPerWeek!: number; + @Input() minMinutesValue!: number; + + weeksEnabled = input(null, { + transform: (value) => coerceBooleanProperty(value), + alias: 'weeks-enabled' + }); + daysEnabled = input(null, { + transform: (value) => coerceBooleanProperty(value), + alias: 'days-enabled' + }); + hoursEnabled = input(null, { + transform: (value) => coerceBooleanProperty(value), + alias: 'hours-enabled' + }); + + readonly weeksRef = viewChild>('weeksInput', { + read: ElementRef + }); + readonly daysRef = viewChild>('daysInput', { + read: ElementRef + }); + readonly hoursRef = viewChild>('hoursInput', { + read: ElementRef + }); + readonly minutesRef = viewChild.required>('minutesInput', { + read: ElementRef + }); + + id: string; + controlType = 'estimate'; + multi = true; + estimateInputs: FormGroup; + canBlur = false; + hasFocus = false; + + minutesPerDay!: number; + minutesPerWeek!: number; + + private propagateChange = (_: any) => {}; + + get errorMessages() { + const expected = this.minMinutesValue; + const suffix = expected === 1 ? 'minute' : 'minutes'; + + return [ + { + rule: 'estimateFormat', + message: `Time not recognised, use this format, for example 1 5 15` + }, + { + rule: 'minMinutesEstimate', + message: `Estimate is too low - you must enter at least ${expected} ${suffix}` + } + ]; + } + + @Output() blur = new EventEmitter(); + @Output() focus = new EventEmitter(); + + constructor(private injector: Injector, elementRef: ElementRef) { + i += 1; + this.id = `estimate-input-${i}`; + + // Initialize the form group with explicit generic types. + this.estimateInputs = new FormGroup({ + minutes: new FormControl('') + }); + + // Listen to inner control value changes and propagate the composite value. + this.estimateInputs.valueChanges + .pipe( + map(({ weeks, days, hours, minutes }) => { + if (weeks || days || hours || minutes) { + return ( + this.minutesPerWeek * Number(weeks || 0) + + this.minutesPerDay * Number(days || 0) + + minutesPerHour * Number(hours || 0) + + (Number(minutes) || 0) + ); + } + return undefined; + }) + ) + .subscribe((val) => this.propagateChange(val)); + } + + get ngControl(): NgControl { + return this.injector.get(NgControl); + } + + get controlRef() { + if (this.weeksEnabled() && this.weeksRef()) { + return this.weeksRef as Signal>; + } + if (this.daysEnabled() && this.daysRef()) { + return this.daysRef as Signal>; + } + if (this.hoursEnabled() && this.hoursRef()) { + return this.hoursRef as Signal>; + } + return this.minutesRef; + } + + ngOnInit() { + if (this.weeksEnabled()) { + this.estimateInputs.addControl('weeks', new FormControl('')); + } + if (this.daysEnabled()) { + this.estimateInputs.addControl('days', new FormControl('')); + } + if (this.hoursEnabled()) { + this.estimateInputs.addControl('hours', new FormControl('')); + } + // Calculate minutes per day and per week based on input values or defaults. + this.minutesPerDay = minutesPerHour * (this.hoursPerDay || 6); + this.minutesPerWeek = this.minutesPerDay * (this.daysPerWeek || 7); + } + + ngOnChanges(changes: SimpleChanges) { + if ( + changes.minutesPerDay && + changes.minutesPerDay.currentValue !== changes.minutesPerDay.previousValue + ) { + this.minutesPerDay = minutesPerHour * (changes.minutesPerDay.currentValue || 24); + } + if ( + changes.daysPerWeek && + changes.daysPerWeek.currentValue !== changes.daysPerWeek.previousValue + ) { + this.minutesPerWeek = this.minutesPerDay * (changes.daysPerWeek.currentValue || 7); + } + } + + getAriaDescribedbyFor(controlName: string): string | null { + if (controlName === 'weeks') { + return this.ariaDescribedBy; + } + if (controlName === 'days' && !this.weeksEnabled()) { + return this.ariaDescribedBy; + } + if (controlName === 'hours' && !this.weeksEnabled() && !this.daysEnabled()) { + return this.ariaDescribedBy; + } + if ( + controlName === 'minutes' && + !this.weeksEnabled() && + !this.daysEnabled() && + !this.hoursEnabled() + ) { + return this.ariaDescribedBy; + } + return null; + } + + getErrors(control: string) { + const controlRef = this.estimateInputs.get(control); + if (controlRef && controlRef.errors) { + return Object.keys(controlRef.errors).map((key) => ({ + rule: key, + message: '' + })); + } + return null; + } + + handleBlurInput($event: any) { + this.canBlur = true; + setTimeout(() => { + if (this.canBlur) { + this.blur.emit($event); + this.hasFocus = false; + } + }); + } + + handleFocusInput($event: any) { + if (!this.hasFocus) { + this.focus.emit($event); + this.hasFocus = true; + } + this.canBlur = false; + } + + registerOnChange = (fn: (_: any) => object) => { + this.propagateChange = fn.bind(this); + }; + + registerOnTouched() {} + + validate(c: FormControl): ValidationErrors | null { + // Treat an empty value as valid so that the input can be optional. + if (c.value === undefined) { + return null; + } + + const estimateFormat = this.validateFormat(); + if (estimateFormat && Object.keys(estimateFormat).length > 0) { + return { estimateFormat }; + } + const minMinutesEstimate = this.validateMinimumMinutes(c); + if (minMinutesEstimate) { + return minMinutesEstimate; + } + return null; + } + + validateMinimumMinutes(c: FormControl): { [k: string]: any } | null { + if (this.minMinutesValue && c.value < this.minMinutesValue) { + return { + minMinutesEstimate: { + expected: this.minMinutesValue, + actual: c.value + } + }; + } + return null; + } + + validateFormat(): { [k: string]: any } | null { + return ['weeks', 'days', 'hours', 'minutes'].reduce( + (errors: { [k: string]: any } = {}, controlName) => { + const control = this.estimateInputs.get(controlName); + if (control && !control.valid) { + errors[controlName] = control.errors; + } + return errors; + }, + {} + ); + } + + writeValue(totalMinutes: number) { + if (!totalMinutes) { + this.estimateInputs.patchValue({ + weeks: undefined, + days: undefined, + hours: undefined, + minutes: undefined + }); + return; + } + + let weeks: number | undefined; + let days: number | undefined; + let hours: number | undefined; + let minutes: number | undefined; + let remainingMinutes = totalMinutes; + + if (this.weeksEnabled()) { + weeks = Math.floor(remainingMinutes / this.minutesPerWeek) || undefined; + remainingMinutes = remainingMinutes % this.minutesPerWeek; + } + if (this.daysEnabled()) { + days = Math.floor(remainingMinutes / this.minutesPerDay) || undefined; + remainingMinutes = remainingMinutes % this.minutesPerDay; + } + if (this.hoursEnabled()) { + hours = Math.floor(remainingMinutes / minutesPerHour) || undefined; + remainingMinutes = remainingMinutes % minutesPerHour; + } + // eslint-disable-next-line prefer-const + minutes = remainingMinutes || undefined; + + // Convert numeric values to strings to match the FormControl types. + this.estimateInputs.patchValue({ + weeks: weeks !== undefined ? weeks.toString() : undefined, + days: days !== undefined ? days.toString() : undefined, + hours: hours !== undefined ? hours.toString() : undefined, + minutes: minutes !== undefined ? minutes.toString() : undefined + }); + } +} diff --git a/projects/scheduling/src/components/hearing-slots-row/__snapshots__/hearing-slots-row.component.spec.ts.snap b/projects/scheduling/src/components/hearing-slots-row/__snapshots__/hearing-slots-row.component.spec.ts.snap new file mode 100644 index 0000000..d6cd4aa --- /dev/null +++ b/projects/scheduling/src/components/hearing-slots-row/__snapshots__/hearing-slots-row.component.spec.ts.snap @@ -0,0 +1,101 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`HearingSlotsRowComponent should render 1`] = ` + + + 25-03-2025 + + + + + + + + +
+ + +
+ + +
+ + + + + AM + + +
    +
  1. + 0 +
  2. +
+
+ +
    +
  1. +
  2. +
+ + +`; diff --git a/projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.html b/projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.html new file mode 100644 index 0000000..5655885 --- /dev/null +++ b/projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.html @@ -0,0 +1,144 @@ +@let hearingSlotData = hearingSlot(); + + +@if (selectionMode !== 'readonly') { + + + +} + + + {{ hearingSlotData.sessionDate | date : 'dd-MM-yyyy' }} + + + + + + + + + + + + + + @if (selectionMode !== 'readonly') { + + + + } +
+ {{ hearingSlotData.courtHouseName }} +
+ {{ hearingSlotData.courtRoomName }} + +
+ {{ + hearingSlotData.businessType! | businessTypeDescription : rotaBusinessTypesByCode + }} + + + + +
+ + +
+ + + + + + + + @if (selectionMode === 'single') { + + Select hearing session + + } @if (selectionMode === 'multi') { + + Select hearing session + + } + + + +
    + @if (hearingSlotData.slotBased) { @for (option of getHearingSlotTimeOptions(hearingSlotData); + track option.label) { +
  1. + {{ option.label }}: {{ option.count }} +
  2. + } } @if (!hearingSlotData.slotBased && !hearingSlotData.allDaySplit) { +
  3. {{ hearingSlotData.totalBooked! | durationPipe }}
  4. + } @if (!hearingSlotData.slotBased && hearingSlotData.allDaySplit) { +
  5. + AM: +

    + {{ hearingSlotData.totalBookedForMorning! | durationPipe }} +

    +
  6. +
  7. + PM: +

    + {{ hearingSlotData.totalBookedForAfternoon! | durationPipe }} +

    +
  8. + } +
+
+ + +
    + @if (hearingSlotData.slotBased) { +
  1. + {{ hearingSlotData.availableSlots! > 0 ? hearingSlotData.availableSlots : 0 }} +
  2. + } @if (!hearingSlotData.slotBased && !hearingSlotData.allDaySplit) { +
  3. {{ hearingSlotData.availableDuration! > 0 ? hearingSlotData.availableDuration : 0 }}
  4. + } @if (hearingSlotData.allDaySplit) { +
  5. + AM: +

    + {{ + hearingSlotData.availableDurationForMorning! > 0 + ? (hearingSlotData.availableDurationForMorning! | durationPipe) + : 0 + }} +

    +
  6. +
  7. + PM: +

    + {{ + hearingSlotData.availableDurationForAfternoon! > 0 + ? (hearingSlotData.availableDurationForAfternoon! | durationPipe) + : 0 + }} +

    +
  8. + } +
+
+ + + @if ( selectionMode !== 'readonly') { + + + + + } @else { + {{ hearingSlotData.courtSession }} + } + diff --git a/projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.scss b/projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.scss new file mode 100644 index 0000000..01c1a80 --- /dev/null +++ b/projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.scss @@ -0,0 +1,32 @@ +table { + table-layout: fixed; +} +th { + vertical-align: bottom; +} +td { + vertical-align: top; +} +td > table td { + border-bottom: 0; +} +.width-100-px { + width: 100px; +} + +.width-130-px { + width: 130px; +} + +.width-180-px { + width: 180px; +} + +.width-210-px { + width: 210px; +} + +:host ::ng-deep label.govuk-label.govuk-checkboxes__label, +:host ::ng-deep label.govuk-radios__label.govuk-label { + display: contents; +} diff --git a/projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.spec.ts b/projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.spec.ts new file mode 100644 index 0000000..ac242a7 --- /dev/null +++ b/projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.spec.ts @@ -0,0 +1,88 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { HearingSlotsRowComponent } from './hearing-slots-row.component'; +import { DurationPipe } from '../../pipes/duration.pipe'; +import { HearingSlot } from '../../types'; +import * as utils from '../../utils'; +import { BusinessTypeDescriptionPipe } from '../../pipes/businessTypeDescription.pipe'; +import { + PdkSelectComponent, + PdkRadioButtonComponent, + PdkCheckboxComponent, + PdkTable, + PdkForm, + PdkCore +} from '@cpp/pdk'; + +jest.mock('../../utils', () => ({ + getHearingSlotTimeOptions: jest + .fn() + .mockReturnValue([{ value: '10:00', label: '10:00am to 11:00am', count: 1 }]) +})); + +describe('HearingSlotsRowComponent', () => { + let component: HearingSlotsRowComponent; + let fixture: ComponentFixture; + + const hearingSlot = { + courtSession: 'AM', + sessionDate: '2025-03-25', + slotStartTimes: [ + { + sessionStartTime: '2025-03-25T10:00:00.000Z', + sessionEndTime: '2025-03-25T11:00:00.000Z', + count: 1 + } + ], + allDaySplit: false + } as HearingSlot; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + HearingSlotsRowComponent, + DurationPipe, + BusinessTypeDescriptionPipe, + PdkSelectComponent, + PdkRadioButtonComponent, + PdkCheckboxComponent, + PdkTable, + PdkForm, + PdkCore + ] + }).compileComponents(); + + fixture = TestBed.createComponent(HearingSlotsRowComponent); + component = fixture.componentInstance; + fixture.componentRef.setInput('hearingSlot', hearingSlot); + fixture.detectChanges(); + }); + + it('should create the component', () => { + expect(component).toBeTruthy(); + }); + + it('should render', () => { + expect(fixture).toMatchSnapshot(); + }); + + it('should call getHearingSlotTimeOptions from utils', () => { + const result = component.getHearingSlotTimeOptions(hearingSlot); + expect(utils.getHearingSlotTimeOptions).toHaveBeenCalledWith(hearingSlot); + expect(result).toEqual([{ value: '10:00', label: '10:00am to 11:00am', count: 1 }]); + }); + + it('should emit selectedHearingSlotTimestamp with the correct payload when handleHearingSlotTimeChanged is called', () => { + jest.spyOn(component.selectedHearingSlotTimestamp, 'emit'); + + const mockHearingSlot = { courtScheduleId: '1' } as HearingSlot; + const mockHearingSlotTime = '2025-04-09T09:00:00.000Z'; + + const expected = { + [mockHearingSlot.courtScheduleId]: mockHearingSlotTime + }; + + component.handleHearingSlotTimeChanged(mockHearingSlot, mockHearingSlotTime); + + expect(component.selectedHearingSlotTimestamp.emit).toHaveBeenCalledWith(expected); + }); +}); diff --git a/projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.ts b/projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.ts new file mode 100644 index 0000000..8f27585 --- /dev/null +++ b/projects/scheduling/src/components/hearing-slots-row/hearing-slots-row.component.ts @@ -0,0 +1,65 @@ +import { Component, computed, EventEmitter, input, Input, Output } from '@angular/core'; +import { + PdkCheckboxComponent, + PdkCore, + PdkForm, + PdkTable, + PdkRadioButtonComponent, + PdkSelectComponent, + ValidationError +} from '@cpp/pdk'; +import { HearingSlot } from '../../types'; +import * as utils from '../../utils'; +import { RotaBusinessType } from '@cpp/reference-data'; +import { BusinessTypeDescriptionPipe } from '../../pipes/businessTypeDescription.pipe'; +import { DatePipe, NgTemplateOutlet } from '@angular/common'; +import { DurationPipe } from '../../pipes/duration.pipe'; +import { ListingNoteContainerComponent } from '../listing-notes/listing-note.container'; +import { FormsModule } from '@angular/forms'; + +@Component({ + selector: 'tr[hearing-slots-row]', + templateUrl: './hearing-slots-row.component.html', + styleUrls: ['./hearing-slots-row.component.scss'], + imports: [ + BusinessTypeDescriptionPipe, + DatePipe, + DurationPipe, + PdkSelectComponent, + PdkRadioButtonComponent, + PdkCheckboxComponent, + PdkTable, + PdkForm, + PdkCore, + NgTemplateOutlet, + ListingNoteContainerComponent, + FormsModule + ] +}) +export class HearingSlotsRowComponent { + hearingSlot = input.required(); + selectedHearingSlotTimestamps = input.required<{ [courtScheduleId: string]: string }>(); + @Input() selectionMode: 'readonly' | 'single' | 'multi' = 'readonly'; + @Input() rotaBusinessTypesByCode: Record = {}; + @Output() selectedHearingSlotTimestamp = new EventEmitter>(); + @Output() errors = new EventEmitter(); + + readonly selectedTimestampModel = computed(() => { + const hearingSlot = this.hearingSlot(); + const selectedHearingSlotTimestamps = this.selectedHearingSlotTimestamps(); + return ( + selectedHearingSlotTimestamps[hearingSlot.courtScheduleId] ?? + utils.getHearingSlotTimestamp(hearingSlot) + ); + }); + + getHearingSlotTimeOptions(hearingSlot: HearingSlot) { + return utils.getHearingSlotTimeOptions(hearingSlot); + } + + handleHearingSlotTimeChanged({ courtScheduleId }: HearingSlot, hearingSlotTime: string) { + this.selectedHearingSlotTimestamp.emit({ + [courtScheduleId]: hearingSlotTime + }); + } +} diff --git a/projects/scheduling/src/components/hearing-slots-table/__snapshots__/hearing-slots-table.component.spec.ts.snap b/projects/scheduling/src/components/hearing-slots-table/__snapshots__/hearing-slots-table.component.spec.ts.snap new file mode 100644 index 0000000..bf7420a --- /dev/null +++ b/projects/scheduling/src/components/hearing-slots-table/__snapshots__/hearing-slots-table.component.spec.ts.snap @@ -0,0 +1,356 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`HearingSlotsTableComponent should display hearing slots correctly 1`] = ` + + + + + + + + + + + + + + + + + + + +
+ Date + + Court Details + + Business + + Session + + Time/slots remaining + + Booked +
+ 25-03-2025 + + + + + + + + +
+ + +
+ + +
+ + + + + AM + + +
    +
  1. + 0 +
  2. +
+
+
+
    +
  1. +
  2. +
+
+
+`; + +exports[`HearingSlotsTableComponent should render 1`] = ` + + + + + + + + + + + + + + +
+ Date + + Court Details + + Business + + Session + + Time/slots remaining + + Booked +
+
+`; + +exports[`HearingSlotsTableComponent should render action header 1`] = ` + + + + + + + + + + + + + + + +
+ + Action + + + Date + + Court Details + + Business + + Session + + Time/slots remaining + + Booked +
+
+`; diff --git a/projects/scheduling/src/components/hearing-slots-table/hearing-slots-table.component.html b/projects/scheduling/src/components/hearing-slots-table/hearing-slots-table.component.html new file mode 100644 index 0000000..6c53409 --- /dev/null +++ b/projects/scheduling/src/components/hearing-slots-table/hearing-slots-table.component.html @@ -0,0 +1,32 @@ + + + + @if (selectionMode !== 'readonly') { + + } + + + + + + + + + + @for (hearingSlot of hearingSlots; track hearingSlot.courtScheduleId) { + + } + +
+ Action + DateCourt DetailsBusinessSessionTime/slots remainingBooked
diff --git a/projects/scheduling/src/components/hearing-slots-table/hearing-slots-table.component.spec.ts b/projects/scheduling/src/components/hearing-slots-table/hearing-slots-table.component.spec.ts new file mode 100644 index 0000000..8ffe407 --- /dev/null +++ b/projects/scheduling/src/components/hearing-slots-table/hearing-slots-table.component.spec.ts @@ -0,0 +1,64 @@ +import { HearingSlotsTableComponent } from './hearing-slots-table.component'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { BusinessTypeDescriptionPipe } from '../../pipes/businessTypeDescription.pipe'; +import { DurationPipe } from '../../pipes/duration.pipe'; +import { HearingSlot } from '../../types'; + +describe('HearingSlotsTableComponent', () => { + let component: HearingSlotsTableComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [HearingSlotsTableComponent, DurationPipe, BusinessTypeDescriptionPipe] + }).compileComponents(); + + fixture = TestBed.createComponent(HearingSlotsTableComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create the component', () => { + expect(component).toBeTruthy(); + }); + + it('should render', () => { + expect(fixture).toMatchSnapshot(); + }); + + it('should render action header', () => { + component.selectionMode = 'single'; + fixture.detectChanges(); + + expect(fixture).toMatchSnapshot(); + }); + + it('should display hearing slots correctly', () => { + component.hearingSlots = [ + { + courtSession: 'AM', + sessionDate: '2025-03-25', + slotStartTimes: [ + { + sessionStartTime: '2025-03-25T10:00:00.000Z', + sessionEndTime: '2025-03-25T11:00:00.000Z', + count: 1 + } + ], + allDaySplit: false + } as HearingSlot + ]; + fixture.detectChanges(); + + expect(fixture).toMatchSnapshot(); + }); + + it('should emit selected hearing slot timestamp', () => { + const mockTimestamp: Record = { 1: '2025-04-11T09:00:00' }; + jest.spyOn(component.selectedHearingSlotTimestamp, 'emit'); + + component.handleHearingSlotTimeChanged(mockTimestamp); + + expect(component.selectedHearingSlotTimestamp.emit).toHaveBeenCalledWith(mockTimestamp); + }); +}); diff --git a/projects/scheduling/src/components/hearing-slots-table/hearing-slots-table.component.ts b/projects/scheduling/src/components/hearing-slots-table/hearing-slots-table.component.ts new file mode 100644 index 0000000..c29dafd --- /dev/null +++ b/projects/scheduling/src/components/hearing-slots-table/hearing-slots-table.component.ts @@ -0,0 +1,29 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { + PdkMarginDirective, + PdkTable, + ValidationError, + PdkVisuallyHiddenDirective +} from '@cpp/pdk'; +import { HearingSlot } from '../../types'; +import { RotaBusinessType } from '@cpp/reference-data'; + +import { HearingSlotsRowComponent } from '../hearing-slots-row/hearing-slots-row.component'; + +@Component({ + selector: 'hearing-slots-table', + templateUrl: './hearing-slots-table.component.html', + imports: [PdkMarginDirective, PdkVisuallyHiddenDirective, PdkTable, HearingSlotsRowComponent] +}) +export class HearingSlotsTableComponent { + @Input() selectionMode: 'readonly' | 'single' | 'multi' = 'readonly'; + @Input() hearingSlots: HearingSlot[] = []; + @Input() rotaBusinessTypesByCode: Record = {}; + @Input() selectedHearingSlotTimestamps: { [courtScheduleId: string]: string } = {}; + @Output() selectedHearingSlotTimestamp = new EventEmitter>(); + @Output() errors = new EventEmitter(); + + handleHearingSlotTimeChanged(selectedHearingSlotTimestamp: Record) { + this.selectedHearingSlotTimestamp.emit(selectedHearingSlotTimestamp); + } +} diff --git a/projects/scheduling/src/components/listing-notes/__tests__/__snapshots__/delete-listing-note-confirmation.component.spec.ts.snap b/projects/scheduling/src/components/listing-notes/__tests__/__snapshots__/delete-listing-note-confirmation.component.spec.ts.snap new file mode 100644 index 0000000..f3461b2 --- /dev/null +++ b/projects/scheduling/src/components/listing-notes/__tests__/__snapshots__/delete-listing-note-confirmation.component.spec.ts.snap @@ -0,0 +1,49 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DeleteListingNoteConfirmationComponent should render the component 1`] = ` + +
+

+ Listing note: +

+ + +

+ Do you want to delete this listing note? +

+
+ + + Cancel + +
+
+
+`; diff --git a/projects/scheduling/src/components/listing-notes/__tests__/__snapshots__/listing-note.component.spec.ts.snap b/projects/scheduling/src/components/listing-notes/__tests__/__snapshots__/listing-note.component.spec.ts.snap new file mode 100644 index 0000000..b78b933 --- /dev/null +++ b/projects/scheduling/src/components/listing-notes/__tests__/__snapshots__/listing-note.component.spec.ts.snap @@ -0,0 +1,250 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ListingNoteComponent Existing note should be displayed as foldable note 1`] = ` + +
+
+ Listing note: +
+ +
+ + Lorem ipsum dolor sit amet, usu ne tota vivendo ullamcorper, + est ut quem minim omnium. Odio vero interpretaris ex duo, + iudico cetero vidisse has ex, ea has aeterno sententiae. + Consul primis liberavisse per ex, quaeque graecis per ut. + +
+
+
+
+`; + +exports[`ListingNoteComponent Existing note should be displayed in text area when in editmode 1`] = ` + +
+ + + + + +
+ + Cancel +
+
+ + diff --git a/projects/scheduling/src/components/listing-notes/listing-note.component.scss b/projects/scheduling/src/components/listing-notes/listing-note.component.scss new file mode 100644 index 0000000..43db6ae --- /dev/null +++ b/projects/scheduling/src/components/listing-notes/listing-note.component.scss @@ -0,0 +1,47 @@ +.note-form-actions { + display: flex; + align-items: baseline; + flex-direction: row; +} +.view-note { + display: flex; + align-items: baseline; + flex-direction: column; +} + +.view-note { + pdk-foldable-text { + min-width: 0; + align-self: stretch; + .pdk-foldable { + display: flex; + align-items: flex-end; + } + .pdk-foldable--expanded { + .pdk-foldable__content { + white-space: pre-wrap !important; + } + } + } +} + +pdk-context-panel > div { + display: flex !important; + padding: 10px !important; + margin-bottom: 10px; +} +.pdk-context-panel__icon--tick { + height: 20px !important; + width: 20px !important; + background-size: contain; + background-repeat: repeat; + margin-top: 2px; +} +.govuk-body-l { + font-weight: 600; + font-size: 21px; +} +.govuk-inset-text { + padding-left: 10px; + padding-top: 5px !important; +} diff --git a/projects/scheduling/src/components/listing-notes/listing-note.component.ts b/projects/scheduling/src/components/listing-notes/listing-note.component.ts new file mode 100644 index 0000000..85e2081 --- /dev/null +++ b/projects/scheduling/src/components/listing-notes/listing-note.component.ts @@ -0,0 +1,94 @@ +import { + Component, + Input, + Output, + EventEmitter, + ViewEncapsulation, + ElementRef, + ChangeDetectionStrategy, + AfterViewChecked, + ViewChild, + OnChanges, + SimpleChanges +} from '@angular/core'; +import { + PdkFoldableTextComponent, + PdkButton, + PdkCore, + PdkForm, + PdkInput, + PdkResizeDirective, + PdkTextInputDirective, + ValidationError +} from '@cpp/pdk'; +import { FormsModule, NgForm } from '@angular/forms'; +import { ListingNote } from '../../types'; +import { NgTemplateOutlet } from '@angular/common'; + +@Component({ + selector: 'listing-note', + templateUrl: './listing-note.component.html', + styleUrls: ['./listing-note.component.scss'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + FormsModule, + PdkButton, + PdkForm, + PdkResizeDirective, + PdkTextInputDirective, + PdkInput, + NgTemplateOutlet, + PdkCore, + PdkFoldableTextComponent + ] +}) +export class ListingNoteComponent implements OnChanges, AfterViewChecked { + @Input() listingNote!: ListingNote; + @Input() editMode = false; + @Output() onEdit = new EventEmitter(); + @Output() onSubmit = new EventEmitter<{ noteId?: string; noteDescription: string }>(); + @Output() onError = new EventEmitter(); + @Output() onCancel = new EventEmitter(); + @Output() onDelete = new EventEmitter(); + @Output() onClearBanner = new EventEmitter(); + @ViewChild('form') form!: NgForm; + + listingNoteLabel = 'Listing note'; + + get displayCreateNoteLink() { + return !this.editMode && Boolean(this.listingNote) === false; + } + + constructor(private element: ElementRef) {} + + ngOnChanges(changes: SimpleChanges): void { + this.onClearBanner.emit(); + } + + ngAfterViewChecked() { + if (this.form && this.form.valid && !this.form.dirty) { + this.scroll(); + } + } + + submit() { + const { note } = this.form.value; + const noteDescription = String(note).trim(); + const { id: noteId } = this.listingNote || { id: undefined }; + const noteData = noteId ? { noteId, noteDescription } : { noteDescription }; + this.onSubmit.emit(noteData); + } + + scroll() { + this.element.nativeElement.scrollIntoView({ behavior: 'auto', block: 'start' }); + } + + delete() { + this.onDelete.emit(); + } + + changeLabel() { + this.listingNoteLabel = 'Change listing note'; // Update the label + } +} diff --git a/projects/scheduling/src/components/listing-notes/listing-note.container.ts b/projects/scheduling/src/components/listing-notes/listing-note.container.ts new file mode 100644 index 0000000..396b60d --- /dev/null +++ b/projects/scheduling/src/components/listing-notes/listing-note.container.ts @@ -0,0 +1,144 @@ +import { + Component, + Input, + OnChanges, + ChangeDetectionStrategy, + EventEmitter, + Output, + OnInit +} from '@angular/core'; +import { Observable, BehaviorSubject } from 'rxjs'; +import { Store, select } from '@ngrx/store'; +import { + PdkContextPanelComponent, + PdkInsetTextComponent, + PdkMarginDirective, + PdkPaddingDirective, + ValidationError +} from '@cpp/pdk'; +import { ListingNote } from '../../types'; +import { SchedulingState } from '../../reducers'; +import { + getPublishStatusMessage, + getListingNoteByCourtRoomAndDate +} from '../../selectors/listing-notes'; +import { + createListingNote, + updateListingNote, + showListingNoteSuccessMessage, + deleteListingNote +} from '../../actions/listing-notes.actions'; +import { ListingNoteComponent } from './listing-note.component'; +import { DeleteListingNoteConfirmationComponent } from './delete-listing-note-confirmation.component'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'listing-note-container', + template: ` + + @if (displayStatusMessage$ | async; as displayStatusMessage) { + + {{ displayStatusMessage }} + + } @if ((showDeleteConfirmation$ | async) === false) { + + + } @if (listingNote$ | async; as listingNote) { @if (showDeleteConfirmation$ | async) { + + + } } + + `, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + PdkInsetTextComponent, + PdkContextPanelComponent, + PdkMarginDirective, + PdkPaddingDirective, + CommonModule, + ListingNoteComponent, + DeleteListingNoteConfirmationComponent + ] +}) +export class ListingNoteContainerComponent implements OnInit, OnChanges { + @Input() courtRoomId!: string; + @Input() listingNoteDate!: string; + @Output() onErrors = new EventEmitter(); + editMode = false; + listingNote$!: Observable; + showDeleteConfirmation$ = new BehaviorSubject(false); + displayStatusMessage$!: Observable; + + constructor(private store: Store) {} + + ngOnInit() { + this.displayStatusMessage$ = this.store.pipe(select(getPublishStatusMessage)); + } + + ngOnChanges() { + if (this.courtRoomId && this.listingNoteDate) { + this.listingNote$ = this.store.pipe( + select(getListingNoteByCourtRoomAndDate(this.courtRoomId, this.listingNoteDate)) + ); + } + this.editMode = false; + this.showDeleteConfirmation$.next(false); + } + + clearBanner() { + this.store.dispatch(showListingNoteSuccessMessage({ successMessage: '' })); + } + + submitNote(data: { noteId?: string; noteDescription: string }) { + const { noteId, noteDescription } = data; + if (noteId) { + this.store.dispatch(updateListingNote({ noteId, noteDescription })); + } else { + const note = { + noteDescription, + courtRoomId: this.courtRoomId, + hearingDate: this.listingNoteDate + }; + + this.store.dispatch(createListingNote({ note })); + } + + this.editMode = false; + } + + deleteNote(noteId: string) { + this.store.dispatch(deleteListingNote({ noteId })); + this.showDeleteConfirmation$.next(false); + } + + cancel() { + this.editMode = false; + this.onErrors.emit([]); + } + + showDeleteConfirmation() { + this.showDeleteConfirmation$.next(true); + } + + editNote() { + this.editMode = true; + } +} diff --git a/projects/scheduling/src/components/scheduling-filters/__snapshots__/scheduling-filters.component.spec.ts.snap b/projects/scheduling/src/components/scheduling-filters/__snapshots__/scheduling-filters.component.spec.ts.snap new file mode 100644 index 0000000..d3151c8 --- /dev/null +++ b/projects/scheduling/src/components/scheduling-filters/__snapshots__/scheduling-filters.component.spec.ts.snap @@ -0,0 +1,831 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SchedulingFiltersComponent should render 1`] = ` + +
+

+ Search for a hearing slot +

+
+ + + + + + + + + + + + + + + + + + + +
+
+ + + When autocomplete results are available, use the up and down arrows to review and Enter to select. Touch device users, explore options with swipe gestures. + + + +
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + +
+ + + + +
+ + Booking type + + +
+ +
+ + +
+
+ +
+ For example, PSR +
+
+ +
+ + +
+
+ +
+ For example, Trial +
+
+
+
+
+
+
+
+ + + + + + + + + + + + +
+ + + + + +
+ + Session type + + +
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+
+
+
+
+
+
+ + + +
+ + Panel + + +
+ +
+ + +
+
+ +
+ + +
+
+
+
+
+
+
+
+
+
+ + + + +
+ + Start date + +
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+ +
+
+
+
+
+
+
+
+
+ to +
+
+
+
+
+
+ + + +
+ + End date + + + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+`; diff --git a/projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.html b/projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.html new file mode 100644 index 0000000..9f0d230 --- /dev/null +++ b/projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.html @@ -0,0 +1,230 @@ +
+

Search for a hearing slot

+
+ + + + + + + + + + + + + + + + + + + + + + + + + Slot based + For example, PSR + Duration based + For example, Trial + @if (enableMultiDay && !formModel.isSlotBased) { + + + + Yes + No + @if (formModel.isMultiday === false) { + + + + + + + } + + + + } + + + + + + + + + + + + + + + + @if (formModel.isMultiday) { + All day + } + + + + + + + + + + + + + +
+ + +
to
+
+ @if (sessionStartDate.valid && sessionStartDate.value) { + + Selected day:  + {{ sessionStartDate.value | date : 'EEEE' }} + + } +
+
+ + + + + + @if ( sessionEndDate.value && !sessionEndDate.errors?.dateExists && + !sessionEndDate.errors?.dateFormat ) { + + Selected day:  + {{ sessionEndDate.value | date : 'EEEE' }} + + } + + +
+
+ + +
+
+
diff --git a/projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.scss b/projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.scss new file mode 100644 index 0000000..b7c4669 --- /dev/null +++ b/projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.scss @@ -0,0 +1,24 @@ +.scheduling-filters__form-actions { + display: flex; + align-items: center; +} +.scheduling-filters__start-date { + display: flex; + align-items: flex-end; +} +.scheduling-filters__start-date-conjunction { + padding-bottom: 7px; +} +scheduling-filters { + pdk-radio-group[name='bookingType'] pdk-radio-button { + margin-bottom: 0; + & .govuk-radios--small .govuk-radios__item .govuk-radios__label { + white-space: nowrap; + } + } + pdk-radio-group[name='courtSession'] { + & .govuk-radios--small .govuk-radios__item .govuk-radios__label { + white-space: nowrap; + } + } +} diff --git a/projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.spec.ts b/projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.spec.ts new file mode 100644 index 0000000..3063d68 --- /dev/null +++ b/projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.spec.ts @@ -0,0 +1,183 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { SchedulingFiltersComponent } from './scheduling-filters.component'; +import { CppHttp } from '@cpp/core'; +import { OrganisationUnit } from '@cpp/reference-data'; +import { SchedulingFilters } from '../../types'; +import { of } from 'rxjs'; +import { provideMockStore } from '@ngrx/store/testing'; + +describe('SchedulingFiltersComponent', () => { + let component: SchedulingFiltersComponent; + let fixture: ComponentFixture; + + const defaultFilters: SchedulingFilters = { + organisationUnit: { + id: 'c133d0de-c989-48b9-bd20-0431943e347e', + oucode: 'B01DU00', + lja: '2570', + oucodeL1Code: 'B', + oucodeL1Name: "Magistrates' Courts", + oucodeL3Name: "City of London Magistrates' Court", + oucodeL3WelshName: 'Llys Ynadon Dinas Llundain', + oucodeL3Code: 'DEFAULT_CODE', + address1: '1 Queen Victoria Street', + address2: 'London', + postcode: 'EC4N 4XY', + defaultStartTime: '10:00:00', + defaultDurationHrs: '07:00:00', + oucodeL2Code: '1', + oucodeL2Name: 'London', + region: 'London', + courtrooms: [] + }, + sessionStartDate: '2025-03-21', + sessionEndDate: '2025-05-01' + }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SchedulingFiltersComponent], + providers: [ + provideMockStore({ initialState: {} }), + { + provide: CppHttp, + useValue: { + query: jest.fn(() => of([])) + } + } + ] + }).compileComponents(); + + fixture = TestBed.createComponent(SchedulingFiltersComponent); + component = fixture.componentInstance; + component.defaultValues = defaultFilters; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should render', () => { + expect(fixture).toMatchSnapshot(); + }); + + it('should emit filtersSubmit with filtered form model on submit', () => { + jest.spyOn(component.filtersSubmit, 'emit'); + component.formModel = { ...defaultFilters, courtSession: 'AM' }; + component.handleFiltersSubmit(); + + expect(component.filtersSubmit.emit).toHaveBeenCalledWith({ + organisationUnit: component.formModel.organisationUnit, + sessionStartDate: component.formModel.sessionStartDate, + sessionEndDate: component.formModel.sessionEndDate, + courtSession: 'AM' + }); + }); + + it('should filter out undefined and placeholder values', () => { + const placeholderUnit = { + id: '', + oucodeL1Code: 'B', + oucodeL2Code: '1', + oucodeL3Name: 'All courts', + oucodeL3Code: 'All courts' + } as any; + + component.organisationUnitPlaceholder = placeholderUnit; + const rawFormModel = { + ...component.formModel, + organisationUnit: placeholderUnit + }; + + const filtered = component.filterFormModel(rawFormModel); + expect(filtered.availableDurationMins).toBeUndefined(); + expect(filtered.organisationUnit).toBeUndefined(); + }); + + it('should set organisation unit placeholder when operational unit changes', () => { + component.formModel.organisationUnit = undefined; + component.handleOperationalUnitChanged('LONDON'); + + expect(component.organisationUnitPlaceholder?.oucodeL2Code).toBe('LONDON'); + expect(component.formModel.organisationUnit!.oucodeL2Code).toBe('LONDON'); + }); + + it('should reset form model to initial values', () => { + component.formModel.courtSession = 'PM'; + component.handleResetForm(); + const expected = { + ...component.initialValues + }; + expect(component.formModel).toEqual(expected); + }); + + it('should generate operational unit options from input', () => { + const orgUnits = [component.initialValues.organisationUnit!]; + component.organisationUnits = orgUnits; + expect(component.operationalUnitOptions.length).toBeGreaterThan(0); + }); + + it('should call handleOperationalUnitChanged in ngOnChanges when formModel.oucodeL2Code is set', () => { + const spy = jest.spyOn(component, 'handleOperationalUnitChanged'); + + component.formModel = { oucodeL2Code: 'ABC' } as SchedulingFilters; + component.ngOnChanges(); + + expect(spy).toHaveBeenCalledWith('ABC'); + }); + + it('should return true when organisation unit is a magistrates court with matching oucodeL2Code', () => { + component.formModel.oucodeL2Code = 'LONDON'; + + const organisationUnit = { + oucodeL2Code: 'LONDON', + id: '123', + oucodeL1Code: 'B', + oucodeL3Name: 'London Court', + oucodeL3Code: 'LC' + } as OrganisationUnit; + + const result = component.filterByOperationalUnit(organisationUnit); + expect(result).toBe(true); + }); + + it('should update form model correctly for duration based booking when bookingTypeChange is set to false', () => { + component.formModel = { + ...defaultFilters, + isSlotBased: true, + isMultiday: undefined, + availableDurationMins: undefined, + courtSession: undefined + }; + component.bookingTypeChange(false); + + expect(component.formModel.isMultiday).toBe(false); + expect(component.formModel.availableDurationMins).toBeUndefined(); + expect(component.formModel.courtSession).toBeUndefined(); + }); + + it('should update court session for duration based booking when updateCourtSession is called with true', () => { + component.formModel = { + ...defaultFilters, + isMultiday: false, + availableDurationMins: undefined, + courtSession: undefined + }; + component.updateCourtSession(true); + expect(component.formModel.availableDurationMins).toEqual(360); + expect(component.formModel.courtSession).toEqual('AD'); + }); + + it('should update court session for duration based booking when updateCourtSession is called with false', () => { + component.formModel = { + ...defaultFilters, + isMultiday: true, + availableDurationMins: 360, + courtSession: 'AD' + }; + component.updateCourtSession(false); + expect(component.formModel.availableDurationMins).toBeUndefined(); + expect(component.formModel.courtSession).toBeUndefined(); + }); +}); diff --git a/projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.ts b/projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.ts new file mode 100644 index 0000000..f8d3fb5 --- /dev/null +++ b/projects/scheduling/src/components/scheduling-filters/scheduling-filters.component.ts @@ -0,0 +1,203 @@ +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnChanges, + Output, + ViewEncapsulation +} from '@angular/core'; +import { + PdkHintComponent, + PdkInsetTextComponent, + PdkButton, + PdkCore, + PdkDateInput, + PdkForm, + PdkGrid, + PdkRadio, + PdkTextInput, + PdkSelectComponent, + SelectOption, + ValidationError +} from '@cpp/pdk'; +import { SchedulingFilters } from '../../types/filters'; +import { + CppReferenceDataComponents, + OrganisationUnit, + RotaBusinessType +} from '@cpp/reference-data'; +import * as utils from '../../utils'; +import { DatePipe } from '@angular/common'; +import { EstimateInput } from '../estimate-input/estimate-input'; +import { FormsModule } from '@angular/forms'; + +const courtSessionOptions: SelectOption[] = [ + { value: undefined, label: 'Any' }, + { value: 'AM', label: 'AM' }, + { value: 'PM', label: 'PM' }, + { value: 'AD', label: 'All day' } +]; + +const panelOptions: SelectOption[] = [ + { value: 'ADULT', label: 'Adult' }, + { value: 'YOUTH', label: 'Youth' } +]; + +@Component({ + selector: 'scheduling-filters', + changeDetection: ChangeDetectionStrategy.OnPush, + templateUrl: `./scheduling-filters.component.html`, + styleUrls: ['./scheduling-filters.component.scss'], + encapsulation: ViewEncapsulation.None, + imports: [ + FormsModule, + PdkSelectComponent, + PdkInsetTextComponent, + PdkGrid, + PdkRadio, + PdkButton, + PdkCore, + CppReferenceDataComponents, + DatePipe, + EstimateInput, + PdkForm, + PdkHintComponent, + PdkTextInput, + PdkDateInput + ] +}) +export class SchedulingFiltersComponent implements OnChanges { + @Input() set defaultValues(defaultValues: SchedulingFilters) { + this.formModel = { ...defaultValues, isSlotBased: defaultValues?.isSlotBased ?? true }; + if (!this.initialValues) { + this.initialValues = { + sessionStartDate: defaultValues?.sessionStartDate, + sessionEndDate: defaultValues?.sessionEndDate, + organisationUnit: defaultValues?.organisationUnit, + oucodeL2Code: defaultValues?.oucodeL2Code, + isSlotBased: true + }; + } + } + @Input() set organisationUnits(organisationUnits: OrganisationUnit[]) { + this.operationalUnitOptions = utils.getOperationalUnitOptions(organisationUnits); + } + @Input() rotaBusinessTypes?: RotaBusinessType[]; + @Input() minimumDate?: string; + @Input() enableMultiDay = true; + @Output() errors = new EventEmitter(); + @Output() filtersSubmit = new EventEmitter(); + + formModel!: SchedulingFilters; + initialValues!: SchedulingFilters; + operationalUnitOptions: SelectOption[] = []; + organisationUnitPlaceholder?: OrganisationUnit; + courtSessionOptions: SelectOption[] = + courtSessionOptions; + panelOptions: SelectOption[] = panelOptions; + slotFilterFn = (rotaBusinessType: RotaBusinessType) => !rotaBusinessType.duration; + durationFilterFn = (rotaBusinessType: RotaBusinessType) => rotaBusinessType.duration; + protected readonly utils = utils; + constructor() {} + + ngOnChanges(): void { + if (this.formModel?.oucodeL2Code) { + this.handleOperationalUnitChanged(this.formModel.oucodeL2Code!); + } + } + + handleFiltersSubmit() { + const filteredFormModel = this.filterFormModel(this.formModel); + this.filtersSubmit.emit(filteredFormModel); + } + + filterFormModel(formModel: SchedulingFilters): SchedulingFilters { + return (Object.keys(formModel) as (keyof SchedulingFilters)[]).reduce((reducedParams, key) => { + if (key === 'isMultiday' || key === 'isSlotBased') { + return { ...reducedParams, [key]: formModel[key] }; + } + if ( + !formModel[key] || + (key === 'organisationUnit' && formModel[key] === this.organisationUnitPlaceholder) || + key === 'hearingType' || // Exclude hearingType as it's not part of the scheduling filters form + (key === 'availableDurationMins' && formModel.isSlotBased) // SJP will populate duration on a previous step instead of using duration input, as this will be disabled by enableMultiDay = false, so multi day is not allowed. + ) { + return reducedParams; + } + return { + ...reducedParams, + [key]: formModel[key] + }; + }, {}) as SchedulingFilters; + } + + filterByOperationalUnit = (organisationUnit: OrganisationUnit): boolean => + utils.isMagistratesCourt(organisationUnit) && + (!this.formModel?.oucodeL2Code || + this.formModel.oucodeL2Code === organisationUnit.oucodeL2Code); + + handleOperationalUnitChanged(oucodeL2Code?: string): void { + const orgUnitplaceholder = { + id: '', + oucodeL1Code: 'B', + oucodeL2Code, + oucodeL3Name: 'All courts', + oucodeL3Code: 'All courts' + } as OrganisationUnit; + + this.organisationUnitPlaceholder = orgUnitplaceholder; + + if ( + !this.formModel.organisationUnit || + this.formModel.organisationUnit.oucodeL2Code !== oucodeL2Code + ) { + this.formModel.organisationUnit = orgUnitplaceholder; + } + + if (!oucodeL2Code) { + if (this.formModel.organisationUnit === this.organisationUnitPlaceholder) { + this.formModel.organisationUnit = undefined; + } + this.organisationUnitPlaceholder = undefined; + } + } + + handleCourtChanged(): void { + this.formModel.courtRoomId = undefined; + } + + bookingTypeChange(isSlotBased: boolean): void { + if (isSlotBased) { + if (this.enableMultiDay) { + this.formModel.availableDurationMins = undefined; + } + this.formModel.isMultiday = undefined; + this.formModel.courtSession = undefined; + } else { + this.formModel.isMultiday = false; + + if (this.enableMultiDay) { + this.updateCourtSession(false); + } + } + this.formModel.businessType = undefined; + } + + updateCourtSession(isMultiday: boolean): void { + if (isMultiday) { + this.formModel.availableDurationMins = 360; + this.formModel.courtSession = 'AD'; + } else { + this.formModel.availableDurationMins = undefined; + this.formModel.courtSession = undefined; + } + } + + handleResetForm() { + this.formModel = { + ...this.initialValues + }; + this.handleOperationalUnitChanged(this.initialValues.organisationUnit?.oucodeL2Code); + } +} diff --git a/projects/scheduling/src/components/scheduling-slots/__snapshots__/scheduling-slots.component.spec.ts.snap b/projects/scheduling/src/components/scheduling-slots/__snapshots__/scheduling-slots.component.spec.ts.snap new file mode 100644 index 0000000..a16b578 --- /dev/null +++ b/projects/scheduling/src/components/scheduling-slots/__snapshots__/scheduling-slots.component.spec.ts.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SchedulingSlotsComponent should render 1`] = ` + + +`; diff --git a/projects/scheduling/src/components/scheduling-slots/scheduling-slots.component.html b/projects/scheduling/src/components/scheduling-slots/scheduling-slots.component.html new file mode 100644 index 0000000..6c3f28c --- /dev/null +++ b/projects/scheduling/src/components/scheduling-slots/scheduling-slots.component.html @@ -0,0 +1,97 @@ +@if (totalResults > 0) { +
+
+ @switch (selectionMode) { @case ('single') { + + + + } @case ('multi') { + + + + } @default { + + } } @if (totalResults > pageSize) { + + + } @if (formConfig) { + + @if (isFieldEnabled('hearingType')) { + + + + + + + + + } @if (isFieldEnabled('sendNotificationToParties')) { + + + + Yes + No + + + + } + + } +
+ @if (selectionMode !== 'readonly') { + + } +
+ +
+} diff --git a/projects/scheduling/src/components/scheduling-slots/scheduling-slots.component.spec.ts b/projects/scheduling/src/components/scheduling-slots/scheduling-slots.component.spec.ts new file mode 100644 index 0000000..bb54161 --- /dev/null +++ b/projects/scheduling/src/components/scheduling-slots/scheduling-slots.component.spec.ts @@ -0,0 +1,292 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { SchedulingSlotsComponent } from './scheduling-slots.component'; +import { DatePipe } from '@angular/common'; +import { ValidationError } from '@cpp/pdk'; +import { HearingType, RotaBusinessType } from '@cpp/reference-data'; +import { HearingSlot, HearingSlotAllocation } from '../../types'; + +describe('SchedulingSlotsComponent', () => { + let component: SchedulingSlotsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SchedulingSlotsComponent, DatePipe] + }).compileComponents(); + + fixture = TestBed.createComponent(SchedulingSlotsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create the component', () => { + expect(component).toBeTruthy(); + }); + + it('should render', () => { + expect(fixture).toMatchSnapshot(); + }); + + it('should set rotaBusinessTypes correctly and generate a mapping', () => { + const businessTypes: RotaBusinessType[] = [ + { typeCode: 'TRL', typeDescription: 'Trial' }, + { typeCode: 'TFL', typeDescription: 'Tfl' } + ] as unknown as RotaBusinessType[]; + + component.rotaBusinessTypes = businessTypes; + expect(component.rotaBusinessTypesByCode).toEqual({ + TRL: businessTypes[0], + TFL: businessTypes[1] + }); + }); + + it('should set hearingTypes correctly and generate hearingTypesOptions', () => { + component.hearingTypes = [{ id: '1', hearingDescription: 'Trial' }] as unknown as HearingType[]; + expect(component.hearingTypesOptions).toEqual([ + { + value: '1', + label: 'Trial' + } + ]); + }); + + it('should emit pageChange event when triggered', () => { + jest.spyOn(component.pageChange, 'emit'); + component.pageChange.emit(2); + expect(component.pageChange.emit).toHaveBeenCalledWith(2); + }); + + it('should emit errors event when triggered', () => { + jest.spyOn(component.errors, 'emit'); + const errors: ValidationError[] = [{ message: 'Error message', id: 'id' }]; + component.errors.emit(errors); + expect(component.errors.emit).toHaveBeenCalledWith(errors); + }); + + describe('handleSubmitAllocations', () => { + const hearingType = { id: '1', hearingDescription: 'Trial' } as HearingType; + + beforeEach(() => { + jest.spyOn(component.hearingSlotAllocations, 'emit'); + component.allocations = [ + { + hearingSlot: { courtScheduleId: '1', slotBased: true } as HearingSlot, + hearingSlotTime: '2025-04-09T09:00:00.000Z', + duration: 99 + } + ]; + component.selectedSlotsModel = ['1']; + }); + + it('should reset allocation and selectedSlotsModel', () => { + component.reset(); + + expect(component.selectedSlotsModel).toEqual([]); + expect(component.allocations).toEqual([]); + }); + + describe('slot based ', () => { + it('should emit allocation when sendNotificationToParties is defined', () => { + component.sendNotificationToParties = true; + component.formConfig = { + formFields: ['sendNotificationToParties'] + }; + + component.handleSubmitAllocations(); + + expect(component.hearingSlotAllocations.emit).toHaveBeenCalledWith({ + hearingSlotAllocations: component.allocations, + sendNotificationToParties: true + }); + }); + }); + + it('should emit allocation and sendNotificationToParties when defined but hearingType is undefined', () => { + component.sendNotificationToParties = true; + component.hearingType = undefined; + component.formConfig = { + formFields: ['sendNotificationToParties'] + }; + + jest.spyOn(component.hearingSlotAllocations, 'emit'); + + component.handleSubmitAllocations(); + + expect(component.hearingSlotAllocations.emit).toHaveBeenCalledWith({ + hearingSlotAllocations: component.allocations, + sendNotificationToParties: true + }); + }); + it('should emit allocation and hearingType when sendNotificationToParties is undefined', () => { + component.sendNotificationToParties = undefined; + component.hearingType = hearingType; + + component.handleSubmitAllocations(); + + expect(component.hearingSlotAllocations.emit).toHaveBeenCalledWith({ + hearingSlotAllocations: component.allocations, + hearingType: component.hearingType + }); + }); + + it('should emit allocation, sendNotificationToParties, and hearingType when both are defined', () => { + component.sendNotificationToParties = true; + component.hearingType = hearingType; + component.formConfig = { + formFields: ['sendNotificationToParties'] + }; + + component.handleSubmitAllocations(); + + expect(component.hearingSlotAllocations.emit).toHaveBeenCalledWith({ + hearingSlotAllocations: component.allocations, + sendNotificationToParties: true, + hearingType: component.hearingType + }); + }); + }); + + describe('duration based', () => { + it('should handle hearing slot time changes and update allocation', () => { + const courtScheduleId = '1'; + const defaultHearingSlotTime = '2025-04-09T09:00:00.000Z'; + const updatedHearingSlotTime = '2025-04-09T10:00:00.000Z'; + + const hearingSlot = { + courtScheduleId, + slotBased: false + } as HearingSlot; + + component.hearingSlots = [hearingSlot]; + component.allocations = [ + { + hearingSlot, + hearingSlotTime: defaultHearingSlotTime + } as HearingSlotAllocation + ]; + + component.handleHearingSlotTimeChanged({ [courtScheduleId]: updatedHearingSlotTime }); + + expect(component.selectedHearingSlotTimestamps[courtScheduleId]).toEqual( + updatedHearingSlotTime + ); + expect(component.allocations[0].hearingSlotTime).toEqual(updatedHearingSlotTime); + }); + + it('should update allocation with selected hearingStartTime', () => { + const courtScheduleId = '1'; + const hearingSlotTime = '2025-04-09T09:00:00.000Z'; + + const hearingSlot = { + courtScheduleId, + slotBased: false + } as HearingSlot; + + component.hearingSlots = [hearingSlot]; + component.selectedHearingSlotTimestamps = { + [courtScheduleId]: hearingSlotTime + }; + + component.handleAllocationChanged([courtScheduleId]); + + expect(component.allocations.length).toBe(1); + expect(component.allocations[0].hearingSlot.courtScheduleId).toBe(courtScheduleId); + expect(component.allocations[0].hearingSlotTime).toBe(hearingSlotTime); + }); + + it('should handle submitting duration-based all day split slots', () => { + const courtScheduleId = '1'; + const hearingSlotTime = '2025-04-09T09:00:00.000Z'; + + const hearingSlot = { + courtScheduleId, + slotBased: false, + sessionDate: '2025-01-24', + courtHouseName: `Lavender Hill Magistrates' Court`, + courtRoomName: 'Courtroom 1', + courtSession: 'AD', + businessType: 'TRL', + panel: 'ADULT', + allDaySplit: true, + availableDuration: 0, + availableDurationForMorning: 90, + availableDurationForAfternoon: 120, + availableSlots: 0, + maxDuration: 0, + maxDurationForMorning: 90, + maxDurationForAfternoon: 120, + maxSlots: 0, + slotStartTimes: [ + { + sessionStartTime: '2025-01-24T10:00:00.000Z', + sessionEndTime: '2025-01-24T14:00:00.000Z', + count: 1 + } + ] + } as HearingSlot; + + component.hearingSlots = [hearingSlot]; + component.selectedHearingSlotTimestamps = { + [courtScheduleId]: hearingSlotTime + }; + + component.handleAllocationChanged([courtScheduleId]); + + expect(component.allocations.length).toBe(1); + expect(component.allocations[0].hearingSlot.courtScheduleId).toBe(courtScheduleId); + expect(component.allocations[0].hearingSlotTime).toBe(hearingSlotTime); + }); + + it('should update allocation with default hearingStartTime if none selected', () => { + const courtScheduleId = '1'; + const hearingSlotTime = '2025-04-09T10:00:00.000Z'; + + const hearingSlot = { + courtScheduleId, + sessionDate: '2025-04-09', + courtSession: 'AM', + slotBased: false, + slotStartTimes: [ + { + sessionStartTime: '2025-04-09T10:00:00.000Z', + sessionEndTime: '2025-04-09T11:00:00.000Z', + count: 1 + } + ] + } as HearingSlot; + + component.hearingSlots = [hearingSlot]; + component.handleAllocationChanged([courtScheduleId]); + + expect(component.allocations.length).toBe(1); + expect(component.allocations[0].hearingSlotTime).toBe(hearingSlotTime); + }); + }); + + it('should prevent submission of slots that share the same date', () => { + jest.spyOn(component.errors, 'emit'); + + const courtScheduleId = '1'; + + const hearingSlot = { + courtScheduleId, + sessionDate: '2025-04-09', + courtSession: 'AM', + slotBased: true + } as HearingSlot; + + component.hearingSlots = [ + hearingSlot, + { + ...hearingSlot, + courtScheduleId: '2' + } + ]; + + const selectedSlots = [courtScheduleId, '2']; + component.handleAllocationChanged(selectedSlots); + component.handleSubmitAllocations(); + + expect(component.errors.emit).toHaveBeenCalled(); + }); +}); diff --git a/projects/scheduling/src/components/scheduling-slots/scheduling-slots.component.ts b/projects/scheduling/src/components/scheduling-slots/scheduling-slots.component.ts new file mode 100644 index 0000000..f84cc31 --- /dev/null +++ b/projects/scheduling/src/components/scheduling-slots/scheduling-slots.component.ts @@ -0,0 +1,203 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +import { + PdkCheckboxGroupComponent, + PdkPaginationComponent, + PdkButton, + PdkCore, + PdkForm, + PdkGrid, + PdkRadio, + PdkRadioGroupComponent, + PdkSelectComponent, + SelectOption, + ValidationError +} from '@cpp/pdk'; +import { + AllocationsFormConfig, + AllocationsFormConfigField, + HearingSlot, + HearingSlotAllocation +} from '../../types'; +import * as utils from '../../utils'; +import { HearingType, RotaBusinessType } from '@cpp/reference-data'; +import { HearingSlotsTableComponent } from '../hearing-slots-table/hearing-slots-table.component'; +import { FormsModule } from '@angular/forms'; + +@Component({ + selector: 'scheduling-slots', + templateUrl: './scheduling-slots.component.html', + styles: [''], + imports: [ + HearingSlotsTableComponent, + PdkCheckboxGroupComponent, + PdkPaginationComponent, + PdkSelectComponent, + PdkGrid, + PdkButton, + PdkRadio, + PdkCore, + PdkForm, + FormsModule + ] +}) +export class SchedulingSlotsComponent { + @Input() selectionMode: 'readonly' | 'single' | 'multi' = 'readonly'; + @Input() currentPage = 1; + @Input() hearingSlots: HearingSlot[] = []; + @Input() hearingSlotMinutes?: number = 0; + @Input() maxPages = 9; + @Input() pageSize = 10; + @Input() totalResults = 0; + @Input() formConfig: AllocationsFormConfig | undefined; + + @Input() + set rotaBusinessTypes(rotaBusinessTypes: RotaBusinessType[]) { + this.rotaBusinessTypesByCode = rotaBusinessTypes.reduce((map, rotaBusinessType) => { + map[rotaBusinessType.typeCode] = rotaBusinessType; + return map; + }, {} as Record); + } + + private _hearingTypes: HearingType[] = []; + + @Input() + set hearingTypes(hearingTypes: HearingType[]) { + this._hearingTypes = hearingTypes; + this.hearingTypesOptions = hearingTypes.map((hearingType) => ({ + value: hearingType.id, + label: hearingType.hearingDescription + })); + } + + get hearingTypes(): HearingType[] { + return this._hearingTypes; + } + + @Input() + set hearingType(hearingType: HearingType | undefined) { + this.selectedHearingTypeId = hearingType?.id ?? null; + } + + @Output() errors = new EventEmitter(); + @Output() hearingSlotAllocations = new EventEmitter<{ + hearingSlotAllocations: HearingSlotAllocation[]; + sendNotificationToParties?: boolean | undefined; + hearingType?: HearingType | undefined; + }>(); + @Output() pageChange = new EventEmitter(); + + selectedHearingTypeId: string | null = null; + selectedHearingSlotTimestamps: { [courtScheduleId: string]: string } = {}; + allocations: HearingSlotAllocation[] = []; + selectedSlotsModel: string[] = []; + rotaBusinessTypesByCode: Record = {}; + hearingTypesOptions: SelectOption[] = []; + + private _sendNotificationToParties = false; + + get sendNotificationToParties(): boolean | undefined { + return this.isFieldEnabled('sendNotificationToParties') + ? this._sendNotificationToParties + : undefined; + } + + set sendNotificationToParties(value: boolean | undefined) { + this._sendNotificationToParties = value ?? false; + } + + handleSubmitAllocations() { + if (this.validateAllocations(this.allocations)) { + this.errors.emit(null); + this.allocations.sort((a, b) => +new Date(a.hearingSlotTime) - +new Date(b.hearingSlotTime)); + + this.hearingSlotAllocations.emit({ + hearingSlotAllocations: this.allocations, + sendNotificationToParties: this.sendNotificationToParties, + hearingType: this._hearingTypes.find( + (hearingType) => hearingType.id === this.selectedHearingTypeId + ) + }); + } else { + this.errors.emit([ + { + id: 'slotList', + message: 'You can only book 1 hearing on the same day' + } + ]); + } + } + + reset() { + this.selectedSlotsModel = []; + this.allocations = []; + } + + handleAllocationChanged(newSelectedSlotsModel: string[]) { + const existingAllocations = this.allocations.filter(({ hearingSlot }) => + newSelectedSlotsModel.includes(hearingSlot.courtScheduleId) + ); + + const existingIds = existingAllocations.map(({ hearingSlot }) => hearingSlot.courtScheduleId); + + const newAllocations = newSelectedSlotsModel + .filter((id) => !existingIds.includes(id)) + .map((id) => { + const hearingSlot = this.getHearingSlot(id); + if (!hearingSlot) return null; + + const startTime = this.selectedHearingSlotTimestamps[id]; + const hearingSlotTime = startTime || utils.getHearingSlotTimestamp(hearingSlot); + + return { + hearingSlot, + hearingSlotTime, + ...(!hearingSlot.slotBased ? { duration: this.hearingSlotMinutes } : {}) + } as HearingSlotAllocation; + }) + .filter((allocation): allocation is HearingSlotAllocation => allocation !== null); + + this.allocations = [...existingAllocations, ...newAllocations]; + } + + handleHearingSlotTimeChanged(selectedHearingSlotTimestamp: Record) { + const courtScheduleId = Object.keys(selectedHearingSlotTimestamp)[0]; + + this.selectedHearingSlotTimestamps = { + ...this.selectedHearingSlotTimestamps, + ...selectedHearingSlotTimestamp + }; + + const allocation = this.getAllocation(courtScheduleId); + + if (allocation) { + allocation.hearingSlotTime = this.selectedHearingSlotTimestamps[courtScheduleId]; + } + } + + isFieldEnabled(field: AllocationsFormConfigField): boolean { + return this.formConfig?.formFields?.includes(field) ?? false; + } + + handleDisabled(): boolean { + const hasAllocations = this.allocations.length > 0; + const hearingTypeValid = !this.isFieldEnabled('hearingType') || !!this.selectedHearingTypeId; + + return !(hasAllocations && hearingTypeValid); + } + + private getAllocation(courtScheduleId: string): HearingSlotAllocation | undefined { + return this.allocations.find( + (allocation) => allocation.hearingSlot.courtScheduleId === courtScheduleId + ); + } + + private getHearingSlot(courtScheduleId: string): HearingSlot | undefined { + return this.hearingSlots.find((hearingSlot) => hearingSlot.courtScheduleId === courtScheduleId); + } + + private validateAllocations(allocations: HearingSlotAllocation[]): boolean { + // each slot must have a unique session date + return allocations.length === new Set(allocations.map((a) => a.hearingSlot.sessionDate)).size; + } +} diff --git a/projects/scheduling/src/index.ts b/projects/scheduling/src/index.ts new file mode 100644 index 0000000..7e1a213 --- /dev/null +++ b/projects/scheduling/src/index.ts @@ -0,0 +1 @@ +export * from './public-api'; diff --git a/projects/scheduling/src/pipes/__tests__/businessTypeDescription.pipe.spec.ts b/projects/scheduling/src/pipes/__tests__/businessTypeDescription.pipe.spec.ts new file mode 100644 index 0000000..05d844f --- /dev/null +++ b/projects/scheduling/src/pipes/__tests__/businessTypeDescription.pipe.spec.ts @@ -0,0 +1,30 @@ +import { RotaBusinessType, RotaBusinessTypeCode } from '@cpp/reference-data'; +import { BusinessTypeDescriptionPipe } from '../businessTypeDescription.pipe'; + +describe('BusinessTypeDescriptionPipe', () => { + let pipe: BusinessTypeDescriptionPipe; + + const rotaBusinessTypesByCode: Record = { + TRL: { typeCode: 'TRL', typeDescription: 'Trial' } as unknown as RotaBusinessType + }; + + beforeEach(() => { + pipe = new BusinessTypeDescriptionPipe(); + }); + + it('should be created', () => { + expect(pipe).toBeTruthy(); + }); + + it('should return the correct description for a valid type code', () => { + expect(pipe.transform('TRL', rotaBusinessTypesByCode)).toBe('Trial'); + }); + + it('should return an empty string for an unknown type code', () => { + expect(pipe.transform('XYZ' as string, rotaBusinessTypesByCode)).toBe(''); + }); + + it('should return an empty string when rotaBusinessTypesByCode is empty', () => { + expect(pipe.transform('TRL', {} as Record)).toBe(''); + }); +}); diff --git a/projects/scheduling/src/pipes/__tests__/duration.pipe.spec.ts b/projects/scheduling/src/pipes/__tests__/duration.pipe.spec.ts new file mode 100644 index 0000000..f05f5ba --- /dev/null +++ b/projects/scheduling/src/pipes/__tests__/duration.pipe.spec.ts @@ -0,0 +1,37 @@ +import { DurationPipe } from '../duration.pipe'; + +describe('DurationPipe', () => { + let pipe: DurationPipe; + + beforeEach(() => { + pipe = new DurationPipe(); + }); + + it('should be created', () => { + expect(pipe).toBeTruthy(); + }); + + it('should return "0" when duration is 0', () => { + expect(pipe.transform(0)).toBe('0'); + }); + + it('should return minutes only when duration is less than 60', () => { + expect(pipe.transform(5)).toBe('5 mins'); + expect(pipe.transform(1)).toBe('1 min'); + }); + + it('should return hours only when duration is a multiple of 60', () => { + expect(pipe.transform(60)).toBe('1 hour'); + expect(pipe.transform(120)).toBe('2 hours'); + }); + + it('should return both hours and minutes when duration is more than 60', () => { + expect(pipe.transform(61)).toBe('1 hour 1 min'); + expect(pipe.transform(125)).toBe('2 hours 5 mins'); + }); + + it('should handle edge cases correctly', () => { + expect(pipe.transform(59)).toBe('59 mins'); + expect(pipe.transform(121)).toBe('2 hours 1 min'); + }); +}); diff --git a/projects/scheduling/src/pipes/businessTypeDescription.pipe.ts b/projects/scheduling/src/pipes/businessTypeDescription.pipe.ts new file mode 100644 index 0000000..4ba09b3 --- /dev/null +++ b/projects/scheduling/src/pipes/businessTypeDescription.pipe.ts @@ -0,0 +1,13 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { RotaBusinessType } from '@cpp/reference-data'; + +@Pipe({ + name: 'businessTypeDescription', + standalone: true +}) +export class BusinessTypeDescriptionPipe implements PipeTransform { + transform(typeCode: string, rotaBusinessTypesByCode: Record): string { + const rotaBusinessType = rotaBusinessTypesByCode[typeCode]; + return rotaBusinessType ? rotaBusinessType.typeDescription : ''; + } +} diff --git a/projects/scheduling/src/pipes/duration.pipe.ts b/projects/scheduling/src/pipes/duration.pipe.ts new file mode 100644 index 0000000..873c1e0 --- /dev/null +++ b/projects/scheduling/src/pipes/duration.pipe.ts @@ -0,0 +1,24 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'durationPipe', + standalone: true +}) +export class DurationPipe implements PipeTransform { + transform(duration: number): string { + if (duration === 0) return '0'; + + const hours = Math.floor(duration / 60); + const minutes = duration % 60; + const durationText: string[] = []; + + if (hours > 0) { + durationText.push(`${hours} hour${hours === 1 ? '' : 's'}`); + } + if (minutes > 0) { + durationText.push(`${minutes} min${minutes === 1 ? '' : 's'}`); + } + + return durationText.join(' '); + } +} diff --git a/projects/scheduling/src/providers.ts b/projects/scheduling/src/providers.ts new file mode 100644 index 0000000..5351af6 --- /dev/null +++ b/projects/scheduling/src/providers.ts @@ -0,0 +1,18 @@ +import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'; +import { provideState } from '@ngrx/store'; +import { schedulingReducer } from './reducers'; +import { ALLOCATION_FORM_CONFIGS, allocationFormConfigs } from './utils'; + +export const provideSchedulingstore = (): EnvironmentProviders => { + return provideState({ name: 'scheduling', reducer: schedulingReducer }); +}; + +export const provideSchedulingEnvironmentContext = (): EnvironmentProviders => { + return makeEnvironmentProviders([ + { + provide: ALLOCATION_FORM_CONFIGS, + useValue: allocationFormConfigs + }, + provideSchedulingstore() + ]); +}; diff --git a/projects/scheduling/src/public-api.ts b/projects/scheduling/src/public-api.ts new file mode 100644 index 0000000..2d9089e --- /dev/null +++ b/projects/scheduling/src/public-api.ts @@ -0,0 +1,34 @@ +/* + * Public API Surface of scheduling + */ + +import { SchedulingSlotsComponent } from './components/scheduling-slots/scheduling-slots.component'; +import { SchedulingFiltersComponent } from './components/scheduling-filters/scheduling-filters.component'; +import { EstimateInput } from './components/estimate-input/estimate-input'; +import { ListingNoteContainerComponent } from './components/listing-notes/listing-note.container'; +export const cppSchedulingComponents = [ + SchedulingSlotsComponent, + SchedulingFiltersComponent, + EstimateInput, + ListingNoteContainerComponent +] as const; + +export { + SchedulingSlotsComponent, + SchedulingFiltersComponent, + EstimateInput, + ListingNoteContainerComponent +}; + +export * from './scheduling.module'; +export * from './types/'; +export * from './reducers/index'; +export * from './actions/scheduling.actions'; +export * from './actions/listing-notes.actions'; +export * from './selectors/scheduling'; +export * from './selectors/listing-notes'; +export * from './selectors/index'; +export * from './utils/index'; +export * from './services/scheduling.service'; +export * from './services/listing-notes.service'; +export * from './providers'; diff --git a/projects/scheduling/src/reducers/__snapshots__/scheduling.spec.ts.snap b/projects/scheduling/src/reducers/__snapshots__/scheduling.spec.ts.snap new file mode 100644 index 0000000..e281afa --- /dev/null +++ b/projects/scheduling/src/reducers/__snapshots__/scheduling.spec.ts.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`scheduling reducer undefined action should return the default state 1`] = ` +{ + "allocation": { + "hearingSlots": [], + "params": null, + "totalResults": -1, + }, + "listingNotes": { + "notes": [], + "publishStatusMessage": undefined, + }, +} +`; diff --git a/projects/scheduling/src/reducers/index.ts b/projects/scheduling/src/reducers/index.ts new file mode 100644 index 0000000..fb6df2e --- /dev/null +++ b/projects/scheduling/src/reducers/index.ts @@ -0,0 +1,10 @@ +import { Action } from '@ngrx/store'; +import { scheduling, SchedulingState as SchedulingFeatureState } from './scheduling'; + +export interface SchedulingState { + scheduling: SchedulingFeatureState; +} + +export function schedulingReducer(state: SchedulingFeatureState | undefined, action: Action) { + return scheduling(state, action); +} diff --git a/projects/scheduling/src/reducers/listing-notes.spec.ts b/projects/scheduling/src/reducers/listing-notes.spec.ts new file mode 100644 index 0000000..2000112 --- /dev/null +++ b/projects/scheduling/src/reducers/listing-notes.spec.ts @@ -0,0 +1,71 @@ +import { ListingNote } from '../types'; +import { + createListingNoteSuccess, + deleteListingNoteSuccess, + loadListingNotes, + showListingNoteSuccessMessage, + updateListingNoteSuccess +} from '../actions/listing-notes.actions'; +import { scheduling, SchedulingState } from './scheduling'; + +const listingNotesStateMock = { + listingNotes: { + notes: [], + publishStatusMessage: undefined + } +} as unknown as SchedulingState; + +describe('Listing notes reducer', () => { + it('should load listing notes', () => { + const state = listingNotesStateMock; + const notes = [{ id: 'note-id' } as ListingNote]; + + const actualState = scheduling(state, loadListingNotes({ notes })); + + expect(actualState.listingNotes.notes).toEqual(notes); + }); + + it('should create listing note', () => { + const state = listingNotesStateMock; + const note = { id: 'note-id', courtRoomId: 'courtRoomId' } as ListingNote; + + const actualState = scheduling(state, createListingNoteSuccess({ note })); + + expect(actualState.listingNotes.notes).toContainEqual(note); + }); + + it('should update note', () => { + const state = { + ...listingNotesStateMock, + listingNotes: { + notes: [{ id: 'note-id', note: 'created note' }] as ListingNote[] + } + }; + + const payload = { noteId: 'note-id', noteDescription: 'updated note' }; + const actualState = scheduling(state, updateListingNoteSuccess(payload)); + + expect(actualState.listingNotes.notes[0]).toEqual({ id: 'note-id', note: 'updated note' }); + }); + + it('should delete note', () => { + const state = { + ...listingNotesStateMock, + notes: [{ id: 'note-id', note: 'created note' }] as ListingNote[] + }; + + const noteId = { noteId: 'note-id' }; + const actualState = scheduling(state, deleteListingNoteSuccess(noteId)); + + expect(actualState.listingNotes.notes).toEqual([]); + }); + + it('should set publishStatusMessage', () => { + const state = listingNotesStateMock; + const successMessage = 'Note saved successfully'; + + const actualState = scheduling(state, showListingNoteSuccessMessage({ successMessage })); + + expect(actualState.listingNotes.publishStatusMessage).toBe(successMessage); + }); +}); diff --git a/projects/scheduling/src/reducers/scheduling.spec.ts b/projects/scheduling/src/reducers/scheduling.spec.ts new file mode 100644 index 0000000..caa501a --- /dev/null +++ b/projects/scheduling/src/reducers/scheduling.spec.ts @@ -0,0 +1,119 @@ +import { SchedulingActions } from '../actions'; +import { HearingSlot, SearchHearingSlotsParams, ListingNote } from '../types'; +import { scheduling } from './scheduling'; +import { + createListingNoteSuccess, + deleteListingNoteSuccess, + loadListingNotes, + showListingNoteSuccessMessage, + updateListingNoteSuccess +} from '../actions/listing-notes.actions'; + +const mockHearingSlot = [{ courtScheduleId: '*' }] as HearingSlot[]; + +const schedulingStateMock = { + allocation: { + params: { pageSize: 10 } as SearchHearingSlotsParams, + hearingSlots: mockHearingSlot, + totalResults: 1 + }, + listingNotes: { + notes: [], + publishStatusMessage: undefined + } +}; + +describe('scheduling reducer', () => { + describe('undefined action', () => { + it('should return the default state', () => { + const result = scheduling(undefined, {} as any); + expect(result).toMatchSnapshot(); + }); + }); + + describe('SchedulingActions.loadHearingSlotsSuccess', () => { + it('should populate hearingSlots, totalResults, and params', () => { + const action = SchedulingActions.loadHearingSlotsSuccess({ + params: { pageSize: 10 } as SearchHearingSlotsParams, + hearingSlots: mockHearingSlot, + totalResults: 1 + }); + const result = scheduling(undefined, action); + expect(result.allocation).toEqual({ + hearingSlots: mockHearingSlot, + totalResults: 1, + params: { pageSize: 10 } + }); + }); + }); + + describe('SchedulingActions.resetHearingSlots', () => { + it('should reset allocation to initial state', () => { + const action = SchedulingActions.resetHearingSlots(); + const result = scheduling(schedulingStateMock, action); + expect(result.allocation).toEqual({ + hearingSlots: [], + totalResults: -1, + params: null + }); + }); + }); + + describe('Listing notes', () => { + it('should load listing notes', () => { + const state = schedulingStateMock; + const notes = [{ id: 'note-id' } as ListingNote]; + + const actualState = scheduling(state, loadListingNotes({ notes })); + + expect(actualState.listingNotes.notes).toEqual(notes); + }); + + it('should create listing note', () => { + const state = schedulingStateMock; + const note = { id: 'note-id', courtRoomId: 'courtRoomId' } as ListingNote; + + const actualState = scheduling(state, createListingNoteSuccess({ note })); + + expect(actualState.listingNotes.notes).toContainEqual(note); + }); + + it('should update note', () => { + const state = { + ...schedulingStateMock, + listingNotes: { + ...schedulingStateMock.listingNotes, + notes: [{ id: 'note-id', note: 'created note' }] as ListingNote[] + } + }; + + const payload = { noteId: 'note-id', noteDescription: 'updated note' }; + const actualState = scheduling(state, updateListingNoteSuccess(payload)); + + expect(actualState.listingNotes.notes[0]).toEqual({ id: 'note-id', note: 'updated note' }); + }); + + it('should delete note', () => { + const state = { + ...schedulingStateMock, + listingNotes: { + ...schedulingStateMock.listingNotes, + notes: [{ id: 'note-id', note: 'created note' }] as ListingNote[] + } + }; + + const actualState = scheduling(state, deleteListingNoteSuccess({ noteId: 'note-id' })); + + expect(actualState.listingNotes.notes).toEqual([]); + }); + + it('should set publishStatusMessage', () => { + const state = schedulingStateMock; + const successMessage = 'Note saved successfully'; + + const actualState = scheduling(state, showListingNoteSuccessMessage({ successMessage })); + + expect(actualState.listingNotes.publishStatusMessage).toBe(successMessage); + }); + }); +}); diff --git a/projects/scheduling/src/reducers/scheduling.ts b/projects/scheduling/src/reducers/scheduling.ts new file mode 100644 index 0000000..d4571db --- /dev/null +++ b/projects/scheduling/src/reducers/scheduling.ts @@ -0,0 +1,89 @@ +import { createReducer, on } from '@ngrx/store'; +import { Allocation, ListingNotes } from '../types'; +import { ListingNotesActions, SchedulingActions } from '../actions/index'; + +export interface SchedulingState { + allocation: Allocation; + listingNotes: ListingNotes; +} + +export const initialState: SchedulingState = { + allocation: { + params: null, + totalResults: -1, + hearingSlots: [] + }, + listingNotes: { + notes: [], + publishStatusMessage: undefined + } +}; + +export const scheduling = createReducer( + initialState, + + // Allocation + on( + SchedulingActions.loadHearingSlotsSuccess, + (state, { totalResults, hearingSlots, params }) => ({ + ...state, + allocation: { + ...state.allocation, + hearingSlots: [...hearingSlots], + totalResults, + params + } + }) + ), + + on(SchedulingActions.resetHearingSlots, (state) => ({ + ...state, + allocation: initialState.allocation + })), + + // Listing notes + on(ListingNotesActions.loadListingNotes, (state, { notes }) => ({ + ...state, + listingNotes: { + ...state.listingNotes, + notes + } + })), + + on(ListingNotesActions.createListingNoteSuccess, (state, { note }) => ({ + ...state, + listingNotes: { + ...state.listingNotes, + notes: [...state.listingNotes.notes, note] + } + })), + + on( + ListingNotesActions.updateListingNoteSuccess, + (state, { noteId: id, noteDescription: note }) => ({ + ...state, + listingNotes: { + ...state.listingNotes, + notes: state.listingNotes.notes.map((listingNote) => + listingNote.id === id ? { ...listingNote, note } : listingNote + ) + } + }) + ), + + on(ListingNotesActions.showListingNoteSuccessMessage, (state, { successMessage }) => ({ + ...state, + listingNotes: { + ...state.listingNotes, + publishStatusMessage: successMessage + } + })), + + on(ListingNotesActions.deleteListingNoteSuccess, (state, { noteId }) => ({ + ...state, + listingNotes: { + ...state.listingNotes, + notes: state.listingNotes.notes.filter(({ id }) => id !== noteId) + } + })) +); diff --git a/projects/scheduling/src/scheduling.module.ts b/projects/scheduling/src/scheduling.module.ts new file mode 100644 index 0000000..4b80f3f --- /dev/null +++ b/projects/scheduling/src/scheduling.module.ts @@ -0,0 +1,51 @@ +import { NgModule } from '@angular/core'; +import { SchedulingSlotsComponent } from './components/scheduling-slots/scheduling-slots.component'; +import { SchedulingFiltersComponent } from './components/scheduling-filters/scheduling-filters.component'; +import { EstimateInput } from './components/estimate-input/estimate-input'; +import { StoreModule } from '@ngrx/store'; +import { schedulingReducer } from './reducers'; +import { ALLOCATION_FORM_CONFIGS, allocationFormConfigs } from './utils'; +import { ListingNoteContainerComponent } from './components/listing-notes/listing-note.container'; + +// Reference: https://v16.angular.io/cli/generate#library-command +// TODO: After upgrading from Angular 15, update the library to use the standalone API. + +const SHARED = [ + SchedulingSlotsComponent, + SchedulingFiltersComponent, + EstimateInput, + ListingNoteContainerComponent +]; + +/** + * @deprecated + * This will be removed in some release moving forward but is + * left here for Backward compatilibity. + * + * To use scheduling, remove the module where used. + * In the app module or Bootstrap function (Standalone) or Route , + * provide Scheduling context using the following as per preference + * @method provideSchedulingEnvironmentContext + * - This will provide the configs inclusive of the feature store. + * @method provideSchedulingstore + * - You can provide just the feature store using this method in your module or route providers and import the config you need on demand. + * + * + * PLEASE ENSURE THAT YOUR BOOTSTRAP OR APPMODULE USES THE PROVIDESTORE as the root prior to using any of the methods above mentioned. You can + * mix StoreModule.forRoot and provideStore if the application is still modular - Please refer to Ngrx docs for details + * + * Finally all scheduling components are standalone and can be imported on demand in the modules or standalone components + * when needed. All exposed shared components have been exported as @constant cppSchedulingComponents + */ +@NgModule({ + declarations: [], + imports: [...SHARED, StoreModule.forFeature('scheduling', schedulingReducer)], + exports: SHARED, + providers: [ + { + provide: ALLOCATION_FORM_CONFIGS, + useValue: allocationFormConfigs + } + ] +}) +export class SchedulingModule {} diff --git a/projects/scheduling/src/selectors/index.ts b/projects/scheduling/src/selectors/index.ts new file mode 100644 index 0000000..ff75e79 --- /dev/null +++ b/projects/scheduling/src/selectors/index.ts @@ -0,0 +1,4 @@ +import * as SchedulingSelectors from './scheduling'; +import * as ListingNotesSelectors from './listing-notes'; + +export { SchedulingSelectors, ListingNotesSelectors }; diff --git a/projects/scheduling/src/selectors/listing-notes.spec.ts b/projects/scheduling/src/selectors/listing-notes.spec.ts new file mode 100644 index 0000000..85a33ba --- /dev/null +++ b/projects/scheduling/src/selectors/listing-notes.spec.ts @@ -0,0 +1,121 @@ +import { TestBed } from '@angular/core/testing'; +import { + getListingNoteByCourtRoomAndDate, + getListingNotes, + getListingNotesMap +} from './listing-notes'; +import { ListingNote } from '../types'; +import { SchedulingState } from '../reducers'; + +describe('Listing note selectors', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + teardown: { destroyAfterEach: false } + }); + }); + + describe('getListingNotes', () => { + it('should get listing notes from store', () => { + const state = { + scheduling: { + listingNotes: { + notes: [{ id: 'note-id' }] as ListingNote[], + publishStatusMessage: null + } + } + } as unknown as SchedulingState; + + const notes = getListingNotes(state); + + expect(notes).toEqual([{ id: 'note-id' }]); + }); + }); + + describe('getListingNotesMap', () => { + it('should get map of listing notes', () => { + const listingNotes = [ + { + id: 'note-id', + courtRoomId: 'courtRoom-id-1', + note: 'note-1', + date: '2020-09-16' + }, + { + id: 'note-id-2', + courtRoomId: 'courtRoom-id-1', + note: 'note-2', + date: '2020-09-22' + }, + { + id: 'note-id-3', + courtRoomId: 'courtRoom-id-2', + note: 'note-3', + date: '2020-09-16' + }, + { + id: 'note-id-4', + courtRoomId: 'courtRoom-id-2', + note: 'note-4', + date: '2020-09-22' + } + ] as ListingNote[]; + + const expectedMap = { + 'courtRoom-id-1': { + '2020-09-16': listingNotes[0], + '2020-09-22': listingNotes[1] + }, + 'courtRoom-id-2': { + '2020-09-16': listingNotes[2], + '2020-09-22': listingNotes[3] + } + }; + + expect(getListingNotesMap.projector(listingNotes)).toEqual(expectedMap); + }); + }); + + describe('getListingNoteByCourtRoomAndDate', () => { + it('should get listing note by court room and date', () => { + const courtRoom = 'courtRoom-id-1'; + const date = '2020-09-16'; + + const listingNoteMap = { + 'courtRoom-id-1': { + '2020-09-16': { + id: 'note-id', + courtRoomId: 'courtRoom-id-1', + note: 'note-1', + date: '2020-09-16' + }, + '2020-09-22': { + id: 'note-id-2', + courtRoomId: 'courtRoom-id-1', + note: 'note-2', + date: '2020-09-22' + } + }, + 'courtRoom-id-2': { + '2020-09-16': { + id: 'note-id-3', + courtRoomId: 'courtRoom-id-2', + note: 'note-3', + date: '2020-09-16' + }, + '2020-09-22': { + id: 'note-id-4', + courtRoomId: 'courtRoom-id-2', + note: 'note-4', + date: '2020-09-22' + } + } + }; + + const expectedListingNote = listingNoteMap['courtRoom-id-1']['2020-09-16']; + + const getListingNoteSelector = getListingNoteByCourtRoomAndDate(courtRoom, date); + + expect(getListingNoteSelector.projector(listingNoteMap)).toEqual(expectedListingNote); + }); + }); +}); diff --git a/projects/scheduling/src/selectors/listing-notes.ts b/projects/scheduling/src/selectors/listing-notes.ts new file mode 100644 index 0000000..558f28e --- /dev/null +++ b/projects/scheduling/src/selectors/listing-notes.ts @@ -0,0 +1,31 @@ +import { createSelector } from '@ngrx/store'; +import { SchedulingState } from '../reducers'; +import { ListingNote } from '../types'; + +export const getListingNotesState = (state: SchedulingState) => state.scheduling.listingNotes; + +export const getListingNotes = createSelector( + getListingNotesState, + (listingNotesState) => listingNotesState.notes +); + +export const getListingNotesMap = createSelector(getListingNotes, (listingNotes: ListingNote[]) => + listingNotes.reduce( + (notesMap, note) => ({ + ...notesMap, + [note.courtRoomId]: { + ...notesMap[note.courtRoomId], + [note.date]: note + } + }), + {} as Record> + ) +); + +export const getListingNoteByCourtRoomAndDate = (courtRoomId: string, hearingDate: string) => + createSelector(getListingNotesMap, (notesMap) => notesMap[courtRoomId]?.[hearingDate]); + +export const getPublishStatusMessage = createSelector( + getListingNotesState, + (listingNotesState) => listingNotesState.publishStatusMessage +); diff --git a/projects/scheduling/src/selectors/scheduling.spec.ts b/projects/scheduling/src/selectors/scheduling.spec.ts new file mode 100644 index 0000000..85a79c1 --- /dev/null +++ b/projects/scheduling/src/selectors/scheduling.spec.ts @@ -0,0 +1,124 @@ +import { getSearchMetadata, getSearchParams, getSearchResults } from './scheduling'; +import { SchedulingState } from '../reducers'; + +describe('Scheduling selectors', () => { + describe('getSearchParams', () => { + it('should return search params without pagination info', () => { + const state = { + scheduling: { + allocation: { + params: { + pageSize: 5, + pageNumber: 2, + court: 'ABC', + startDate: '2025-01-01', + endDate: '2025-01-02' + } + } + } + } as unknown as SchedulingState; + + const result = getSearchParams(state); + + expect(result).toEqual({ + court: 'ABC', + startDate: '2025-01-01', + endDate: '2025-01-02' + }); + }); + + it('should return undefined if params are not defined', () => { + const state = { + scheduling: { + allocation: { + params: undefined + } + } + } as unknown as SchedulingState; + + const result = getSearchParams(state); + + expect(result).toBeUndefined(); + }); + }); + + describe('getSearchMetadata', () => { + it('should return metadata with totalResults, pageSize and currentPage', () => { + const state = { + scheduling: { + allocation: { + totalResults: 42, + params: { + pageSize: 20, + pageNumber: 3 + } + } + } + } as unknown as SchedulingState; + + const result = getSearchMetadata(state); + + expect(result).toEqual({ + totalResults: 42, + pageSize: 20, + currentPage: 3 + }); + }); + + it('should fallback to default pageSize if not provided', () => { + const state = { + scheduling: { + allocation: { + totalResults: 10, + params: { + pageNumber: 1 + } + } + } + } as unknown as SchedulingState; + + const result = getSearchMetadata(state); + + expect(result).toEqual({ + totalResults: 10, + pageSize: 10, + currentPage: 1 + }); + }); + + it('should handle undefined params', () => { + const state = { + scheduling: { + allocation: { + totalResults: 5, + params: undefined + } + } + } as unknown as SchedulingState; + + const result = getSearchMetadata(state); + + expect(result).toEqual({ + totalResults: 5, + pageSize: 10, + currentPage: undefined + }); + }); + }); + + describe('getSearchResults', () => { + it('should return hearing slots', () => { + const state = { + scheduling: { + allocation: { + hearingSlots: [{ id: 'slot-1' }, { id: 'slot-2' }] + } + } + } as unknown as SchedulingState; + + const result = getSearchResults(state); + + expect(result).toEqual([{ id: 'slot-1' }, { id: 'slot-2' }]); + }); + }); +}); diff --git a/projects/scheduling/src/selectors/scheduling.ts b/projects/scheduling/src/selectors/scheduling.ts new file mode 100644 index 0000000..22eadb4 --- /dev/null +++ b/projects/scheduling/src/selectors/scheduling.ts @@ -0,0 +1,20 @@ +import { createSelector } from '@ngrx/store'; +import { SchedulingState } from '../reducers'; + +export const getSchedulingState = (state: SchedulingState) => state.scheduling.allocation; + +export const getSearchParams = createSelector(getSchedulingState, (result) => { + if (result.params) { + const { pageSize, pageNumber, ...params } = result.params; + + return params; + } +}); + +export const getSearchMetadata = createSelector(getSchedulingState, ({ totalResults, params }) => ({ + totalResults, + pageSize: (params && params.pageSize) || 10, + currentPage: params && params.pageNumber +})); + +export const getSearchResults = createSelector(getSchedulingState, (result) => result.hearingSlots); diff --git a/projects/scheduling/src/services/listing-notes.service.spec.ts b/projects/scheduling/src/services/listing-notes.service.spec.ts new file mode 100644 index 0000000..014529d --- /dev/null +++ b/projects/scheduling/src/services/listing-notes.service.spec.ts @@ -0,0 +1,85 @@ +import { TestBed } from '@angular/core/testing'; +import { CppHttp } from '@cpp/core'; +import { cold } from 'jasmine-marbles'; +import { ListingNote } from '../types'; +import { ListingNotesService } from './listing-notes.service'; + +describe('ListingNotesService', () => { + let service: ListingNotesService; + let http: CppHttp; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [], + providers: [ + ListingNotesService, + { + provide: CppHttp, + useValue: { + commandSync: jest.fn() + } + } + ], + teardown: { destroyAfterEach: false } + }); + http = TestBed.inject(CppHttp); + service = TestBed.inject(ListingNotesService); + }); + + describe('Listing Notes', () => { + it('#createListingNotes should create listing note as instructed', () => { + const newNote = { + id: 'noteId', + date: '*', + courtRoomId: 'courtRoomId', + note: '*' + } as ListingNote; + const expected$ = cold('-b|', { b: newNote }); + + (http.commandSync as jest.Mock).mockImplementation(({ body }: { body: any }) => { + const createdNote = { + id: 'noteId', + date: body.hearingDate, + courtRoomId: body.courtRoomId, + note: body.noteDescription + } as ListingNote; + + return cold('-a|', { a: createdNote }); + }); + + const noteData = { + hearingDate: '*', + courtRoomId: 'courtRoomId', + noteDescription: '*' + }; + const command$ = service.createListingNotes(noteData); + expect(command$).toBeObservable(expected$); + }); + + it('#updateListingNote should update listing note as instructed', () => { + const updatedData = { noteId: 'noteId', noteDescription: 'description' }; + const expected$ = cold('-a|', { a: updatedData }); + + (http.commandSync as jest.Mock).mockImplementation(({ body }: { body: any }) => + cold('-b|', { b: { noteId: 'noteId', noteDescription: body.noteDescription } }) + ); + + const update = { noteId: 'noteId', noteDescription: 'description' }; + const command$ = service.updateListingNote(update); + expect(command$).toBeObservable(expected$); + }); + + it('#deleteListingNote should deleteNote listing note as instructed', () => { + const deleteData = 'noteId'; + const expected$ = cold('-a|', { a: true }); + + (http.commandSync as jest.Mock).mockImplementation( + (_args: { url: string; successEvent: string }) => cold('-b|', { b: true }) + ); + + const command$ = service.deleteListingNote(deleteData); + + expect(command$).toBeObservable(expected$); + }); + }); +}); diff --git a/projects/scheduling/src/services/listing-notes.service.ts b/projects/scheduling/src/services/listing-notes.service.ts new file mode 100644 index 0000000..c599a86 --- /dev/null +++ b/projects/scheduling/src/services/listing-notes.service.ts @@ -0,0 +1,50 @@ +import { Observable } from 'rxjs'; +import { ListingNote } from '../types'; +import { Injectable } from '@angular/core'; +import { CppHttp } from '@cpp/core'; + +@Injectable({ + providedIn: 'root' +}) +export class ListingNotesService { + constructor(private cppHttp: CppHttp) {} + + createListingNotes(note: { + hearingDate: string; + courtRoomId: string; + noteDescription: string; + }): Observable { + return this.cppHttp.commandSync({ + url: `/listing-command-api/command/api/rest/listing/listing-note`, + requestType: 'application/vnd.listing.command.create-listing-note+json', + successEvent: 'public.listing.created-listing-note', + body: note + }); + } + + updateListingNote({ + noteId, + noteDescription + }: { + noteId: string; + noteDescription: string; + }): Observable<{ + noteId: string; + noteDescription: string; + }> { + return this.cppHttp.commandSync<{ noteId: string; noteDescription: string }>({ + url: `/listing-command-api/command/api/rest/listing/listing-notes/${noteId}`, + requestType: 'application/vnd.listing.command.edit-listing-note+json', + successEvent: 'public.listing.note-edited', + body: { noteDescription } + }); + } + + deleteListingNote(noteId: string): Observable<{ noteId: string }> { + return this.cppHttp.commandSync<{ noteId: string; noteDescription: string }>({ + url: `/listing-command-api/command/api/rest/listing/listing-notes/${noteId}`, + requestType: ' application/vnd.listing.command.delete-listing-note+json', + successEvent: 'public.listing.deleted-listing-note' + }); + } +} diff --git a/projects/scheduling/src/services/scheduling.service.spec.ts b/projects/scheduling/src/services/scheduling.service.spec.ts new file mode 100644 index 0000000..f597d60 --- /dev/null +++ b/projects/scheduling/src/services/scheduling.service.spec.ts @@ -0,0 +1,68 @@ +import { HttpParams } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { CppHttp } from '@cpp/core'; +import { of } from 'rxjs'; +import { SchedulingService } from './scheduling.service'; +import { HearingSlot, ListingNote, SearchHearingSlotsParams } from '../types'; + +describe('SchedulingService', () => { + let service: SchedulingService; + let http: CppHttp; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + SchedulingService, + { + provide: CppHttp, + useValue: { + query: jest.fn() + } + } + ], + teardown: { destroyAfterEach: false } + }); + http = TestBed.inject(CppHttp); + service = TestBed.inject(SchedulingService); + }); + + describe('searchHearingSlots()', () => { + it('should search for filtered hearing slots', () => { + expect.assertions(2); + + const hearingSlot = { courtScheduleId: '*' } as HearingSlot; + const params: SearchHearingSlotsParams = { + oucodeL3Code: '*', + courtRoomId: '*', + oucodeL2Code: undefined, + sessionStartDate: '2020-09-16', + sessionEndDate: '2020-09-23', + panel: 'YOUTH', + courtSession: 'AM', + businessType: '*' + }; + + (http.query as jest.Mock).mockReturnValue( + of({ + results: 10, + pageCount: 2, + hearingSlots: [hearingSlot], + notes: [{ id: 'note-id' } as ListingNote] + }) + ); + + service.searchHearingSlots(params).subscribe((result) => { + expect(result).toEqual({ + hearingSlots: [hearingSlot], + totalResults: 10, + notes: [{ id: 'note-id' }] + }); + expect(http.query).toHaveBeenCalledWith({ + url: '/listing-query-api/query/api/rest/listing/hearingSlots', + requestType: 'application/vnd.listing.search.hearing.slots+json', + params: new HttpParams({ fromObject: params as any }) + }); + }); + }); + }); +}); diff --git a/projects/scheduling/src/services/scheduling.service.ts b/projects/scheduling/src/services/scheduling.service.ts new file mode 100644 index 0000000..553e083 --- /dev/null +++ b/projects/scheduling/src/services/scheduling.service.ts @@ -0,0 +1,62 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { CppHttp, HttpQueryOptions, mapObjectToHttpParams } from '@cpp/core'; +import { Observable, throwError, timer } from 'rxjs'; +import { map, retryWhen, switchMap, take, timeout } from 'rxjs/operators'; +import { HearingSlot, ListingNote, SearchHearingSlotsParams } from '../types'; +import { omit } from 'lodash-es'; + +@Injectable({ + providedIn: 'root' +}) +export class SchedulingService { + constructor(protected cppHttp: CppHttp) {} + + searchHearingSlots( + paramsValues: SearchHearingSlotsParams, + inBackground = false + ): Observable<{ + hearingSlots: HearingSlot[]; + totalResults: number; + notes: ListingNote[]; + }> { + return this.cppHttp + .query<{ hearingSlots: HearingSlot[]; results: number; notes: ListingNote[] }>({ + url: '/listing-query-api/query/api/rest/listing/hearingSlots', + requestType: 'application/vnd.listing.search.hearing.slots+json', + params: mapObjectToHttpParams(paramsValues), + background: inBackground + } as HttpQueryOptions) + .pipe( + map(({ hearingSlots, results, notes }) => ({ + hearingSlots, + totalResults: results, + notes + })), + retryWhen((errors$) => + errors$.pipe( + switchMap((error: HttpErrorResponse) => + error.status === 502 ? timer(1000) : throwError(error) + ) + ) + ), + timeout(30000) + ); + } + + async hasHearingSlotsFor(paramsValues: SearchHearingSlotsParams) { + const extendedParams: SearchHearingSlotsParams = { + ...paramsValues, + showOverbookedSlots: true + }; + + return new Promise((res, reject) => + this.searchHearingSlots(extendedParams, true) + .pipe( + map(({ hearingSlots }) => hearingSlots.length > 0), + take(1) + ) + .subscribe(res, reject) + ); + } +} diff --git a/projects/scheduling/src/types/allocation.ts b/projects/scheduling/src/types/allocation.ts new file mode 100644 index 0000000..197e3f5 --- /dev/null +++ b/projects/scheduling/src/types/allocation.ts @@ -0,0 +1,13 @@ +import { HearingSlot, SearchHearingSlotsParams } from './hearingSlot'; + +export type AllocationsFormConfigField = 'hearingType' | 'sendNotificationToParties'; + +export interface AllocationsFormConfig { + formFields: AllocationsFormConfigField[]; +} + +export interface Allocation { + params: SearchHearingSlotsParams | null; + totalResults: number; + hearingSlots: HearingSlot[]; +} diff --git a/projects/scheduling/src/types/filters.ts b/projects/scheduling/src/types/filters.ts new file mode 100644 index 0000000..5a42ac8 --- /dev/null +++ b/projects/scheduling/src/types/filters.ts @@ -0,0 +1,17 @@ +import { HearingType, OrganisationUnit } from '@cpp/reference-data'; +import { CourtSession, Panel } from './hearingSlot'; + +export interface SchedulingFilters { + oucodeL2Code?: string; + organisationUnit?: OrganisationUnit; + courtRoomId?: string; + sessionStartDate: string; + sessionEndDate?: string; + courtSession?: CourtSession; + panel?: Panel; + businessType?: string; + availableDurationMins?: number; + hearingType?: HearingType; + isMultiday?: boolean; + isSlotBased?: boolean; +} diff --git a/projects/scheduling/src/types/hearingSlot.ts b/projects/scheduling/src/types/hearingSlot.ts new file mode 100644 index 0000000..d308f3c --- /dev/null +++ b/projects/scheduling/src/types/hearingSlot.ts @@ -0,0 +1,84 @@ +enum PanelType { + ADULT = 'ADULT', + YOUTH = 'YOUTH' +} + +export type CourtSession = 'AM' | 'PM' | 'AD'; +export type Panel = 'ADULT' | 'YOUTH' | 'ADULT,YOUTH'; + +export interface HearingSlot { + courtScheduleId: string; + panel: PanelType; + sessionDate: string; + courtHouseName: string; + courtRoomName?: string; + courtSession: CourtSession; + maxSlots?: number; + maxDuration?: number; + availableSlots?: number; + availableDuration?: number; + availableDurationForMorning?: number; + availableDurationForAfternoon?: number; + businessType?: string; + hearingType?: string; + ouCode?: string; + courtRoomId?: string; + courtHouseId?: string; + courtRoomNumber?: number; + judiciaries?: HearingSlotJudiciary[]; + slotStartTimes: { + sessionStartTime: string; + sessionEndTime: string; + count: number; + }[]; + allDaySplit?: boolean; + totalBooked?: number; + totalBookedForMorning?: number; + totalBookedForAfternoon?: number; + slotBased: boolean; + sessionStartTime: string; + sessionEndTime: string; + minHearingTime: string; + maxHearingTime: string; + overbookingAllowed: boolean; + maxDurationForMorning?: number; + maxDurationForAfternoon?: number; + createdOn: string; + updatedOn: string; +} + +export interface HearingSlotJudiciary { + judiciaryId: string; + courtScheduleId: string; + courtListingProfileId: string; + judiciaryType: string; + deputy: boolean; + benchChairman: boolean; +} + +export interface HearingSlotAllocation { + hearingSlot: HearingSlot; + hearingSlotTime: string; + duration?: number; +} + +export interface SearchHearingSlotsParams { + oucodeL2Code?: string; + oucodeL3Code?: string; + courtRoomId?: string; + sessionStartDate: string; + sessionEndDate?: string; + courtSession?: CourtSession; + panel?: Panel; + businessType?: string; + availableDurationMins?: number; + pageSize?: number; + pageNumber?: number; + ouCode?: string; + duration?: number; + slots?: number; + isUnscheduled?: boolean; + hearingTypeId?: string; + showOverbookedSlots?: boolean; + hearingStartTime?: string; +} diff --git a/projects/scheduling/src/types/index.ts b/projects/scheduling/src/types/index.ts new file mode 100644 index 0000000..ce85d86 --- /dev/null +++ b/projects/scheduling/src/types/index.ts @@ -0,0 +1,4 @@ +export * from './hearingSlot'; +export * from './filters'; +export * from './allocation'; +export * from './listingNotes'; diff --git a/projects/scheduling/src/types/listingNotes.ts b/projects/scheduling/src/types/listingNotes.ts new file mode 100644 index 0000000..710341d --- /dev/null +++ b/projects/scheduling/src/types/listingNotes.ts @@ -0,0 +1,11 @@ +export interface ListingNote { + id: string; + date: string; + courtRoomId: string; + note: string; +} + +export interface ListingNotes { + notes: ListingNote[]; + publishStatusMessage?: string; +} diff --git a/projects/scheduling/src/utils/__tests__/courtroom.spec.ts b/projects/scheduling/src/utils/__tests__/courtroom.spec.ts new file mode 100644 index 0000000..7a6beb0 --- /dev/null +++ b/projects/scheduling/src/utils/__tests__/courtroom.spec.ts @@ -0,0 +1,27 @@ +import { getCourtroomOptions } from '../courtrooms'; + +describe('getCourtroomOptions', () => { + it('should return mapped courtroom options if courtrooms exist', () => { + const organisationUnit: any = { + courtrooms: [ + { id: '1', courtroomName: 'Court A' }, + { id: '2', courtroomName: 'Court B' } + ] + }; + + const result = getCourtroomOptions(organisationUnit); + expect(result).toEqual([ + { value: '1', label: 'Court A' }, + { value: '2', label: 'Court B' } + ]); + }); + + it('should return an empty array if no courtrooms exist', () => { + const organisationUnit: any = {}; + expect(getCourtroomOptions(organisationUnit)).toEqual([]); + }); + + it('should return an empty array if no organisation unit is provided', () => { + expect(getCourtroomOptions(undefined)).toEqual([]); + }); +}); diff --git a/projects/scheduling/src/utils/__tests__/hearingSlotTime.spec.ts b/projects/scheduling/src/utils/__tests__/hearingSlotTime.spec.ts new file mode 100644 index 0000000..dda1273 --- /dev/null +++ b/projects/scheduling/src/utils/__tests__/hearingSlotTime.spec.ts @@ -0,0 +1,172 @@ +import { getHearingSlotTimeOptions, formatSessionTime } from '../hearingSlotTime'; +import { HearingSlot } from '../../types'; + +describe('getHearingSlotTimeOptions', () => { + it('should return correct slot times for all-day split sessions', () => { + const mockHearingSlot: HearingSlot = { + courtSession: 'AD', + sessionDate: '2025-03-25', + slotStartTimes: [ + { + sessionStartTime: '2025-03-25T10:00:00.000Z', + sessionEndTime: '2025-03-25T13:00:00.000Z', + count: 2 + }, + { + sessionStartTime: '2025-03-25T14:00:00.000Z', + sessionEndTime: '2025-03-25T17:00:00.000Z', + count: 3 + } + ], + allDaySplit: true + } as HearingSlot; + + const result = getHearingSlotTimeOptions(mockHearingSlot); + + expect(result).toEqual([ + { value: '2025-03-25T10:00:00.000Z', count: 2, label: '10:00am to 1:00pm' }, + { value: '2025-03-25T14:00:00.000Z', count: 3, label: '2:00pm to 5:00pm' } + ]); + }); + + it('should return correct slot times for AM session', () => { + const mockHearingSlot: HearingSlot = { + sessionDate: '2025-03-25', + courtSession: 'AM', + slotStartTimes: [ + { + sessionStartTime: '2025-03-25T10:00:00.000Z', + sessionEndTime: '2025-03-25T11:00:00.000Z', + count: 2 + }, + { + sessionStartTime: '2025-03-25T11:00:00.000Z', + sessionEndTime: '2025-03-25T12:00:00.000Z', + count: 0 + }, + { + sessionStartTime: '2025-03-25T12:00:00.000Z', + sessionEndTime: '2025-03-25T13:00:00.000Z', + count: 0 + } + ], + allDaySplit: false + } as HearingSlot; + + const result = getHearingSlotTimeOptions(mockHearingSlot); + + expect(result).toEqual([ + { value: '2025-03-25T10:00:00.000Z', count: 2, label: '10:00am to 11:00am' }, + { value: '2025-03-25T11:00:00.000Z', count: 0, label: '11:00am to 12:00pm' }, + { value: '2025-03-25T12:00:00.000Z', count: 0, label: '12:00pm to 1:00pm' } + ]); + }); + + it('should return correct slot times for PM session', () => { + const mockHearingSlot: HearingSlot = { + sessionDate: '2025-03-25', + courtSession: 'PM', + slotStartTimes: [ + { + sessionStartTime: '2025-03-25T14:00:00.000Z', + sessionEndTime: '2025-03-25T15:00:00.000Z', + count: 3 + }, + { + sessionStartTime: '2025-03-25T15:00:00.000Z', + sessionEndTime: '2025-03-25T16:00:00.000Z', + count: 0 + }, + { + sessionStartTime: '2025-03-25T16:00:00.000Z', + sessionEndTime: '2025-03-25T17:00:00.000Z', + count: 0 + } + ], + allDaySplit: false + } as HearingSlot; + + const result = getHearingSlotTimeOptions(mockHearingSlot); + + expect(result).toEqual([ + { value: '2025-03-25T14:00:00.000Z', count: 3, label: '2:00pm to 3:00pm' }, + { value: '2025-03-25T15:00:00.000Z', count: 0, label: '3:00pm to 4:00pm' }, + { value: '2025-03-25T16:00:00.000Z', count: 0, label: '4:00pm to 5:00pm' } + ]); + }); + + it('should return correct slot times for AD session (morning + afternoon)', () => { + const mockHearingSlot: HearingSlot = { + sessionDate: '2025-03-25', + courtSession: 'AD', + slotStartTimes: [ + { + sessionStartTime: '2025-03-25T10:00:00.000Z', + sessionEndTime: '2025-03-25T11:00:00.000Z', + count: 2 + }, + { + sessionStartTime: '2025-03-25T11:00:00.000Z', + sessionEndTime: '2025-03-25T12:00:00.000Z', + count: 0 + }, + { + sessionStartTime: '2025-03-25T12:00:00.000Z', + sessionEndTime: '2025-03-25T13:00:00.000Z', + count: 0 + }, + { + sessionStartTime: '2025-03-25T14:00:00.000Z', + sessionEndTime: '2025-03-25T15:00:00.000Z', + count: 3 + }, + { + sessionStartTime: '2025-03-25T15:00:00.000Z', + sessionEndTime: '2025-03-25T16:00:00.000Z', + count: 0 + }, + { + sessionStartTime: '2025-03-25T16:00:00.000Z', + sessionEndTime: '2025-03-25T17:00:00.000Z', + count: 0 + } + ], + allDaySplit: false + } as HearingSlot; + + const result = getHearingSlotTimeOptions(mockHearingSlot); + + expect(result).toEqual([ + { value: '2025-03-25T10:00:00.000Z', count: 2, label: '10:00am to 11:00am' }, + { value: '2025-03-25T11:00:00.000Z', count: 0, label: '11:00am to 12:00pm' }, + { value: '2025-03-25T12:00:00.000Z', count: 0, label: '12:00pm to 1:00pm' }, + { value: '2025-03-25T14:00:00.000Z', count: 3, label: '2:00pm to 3:00pm' }, + { value: '2025-03-25T15:00:00.000Z', count: 0, label: '3:00pm to 4:00pm' }, + { value: '2025-03-25T16:00:00.000Z', count: 0, label: '4:00pm to 5:00pm' } + ]); + }); +}); + +describe('formatSessionTime', () => { + it('should format ISO string as expected', () => { + const result = formatSessionTime('2025-03-25T10:30:00.000Z'); + expect(result).toBe('10:30am'); + }); + + it('should format HH:mm string with sessionDate', () => { + const result = formatSessionTime('10:00', '2025-03-25'); + expect(result).toBe('10:00am'); + }); + + it('should fallback to local time formatting when sessionDate is not provided', () => { + const result = formatSessionTime('15:00'); + expect(result.includes('pm')).toBe(true); + }); + + it('should handle 12:00 edge cases correctly', () => { + const morning = formatSessionTime('2025-03-25T00:00:00.000Z'); + const noon = formatSessionTime('2025-03-25T12:00:00.000Z'); + expect(morning).toBe('12:00am'); + expect(noon).toBe('12:00pm'); + }); +}); diff --git a/projects/scheduling/src/utils/__tests__/operationalUnit.spec.ts b/projects/scheduling/src/utils/__tests__/operationalUnit.spec.ts new file mode 100644 index 0000000..66c8fee --- /dev/null +++ b/projects/scheduling/src/utils/__tests__/operationalUnit.spec.ts @@ -0,0 +1,27 @@ +import { getOperationalUnitOptions, isMagistratesCourt } from '../operationalUnit'; + +describe('getOperationalUnitOptions', () => { + it('should generate unique sorted operational unit options', () => { + const input = [ + { oucodeL2Code: 'C', oucodeL2Name: 'South' }, + { oucodeL2Code: 'B', oucodeL2Name: 'North' }, + { oucodeL2Code: 'C', oucodeL2Name: 'South' } // duplicate + ] as any; + + const result = getOperationalUnitOptions(input); + expect(result).toEqual([ + { value: 'B', label: 'North' }, + { value: 'C', label: 'South' } + ]); + }); +}); + +describe('isMagistratesCourt', () => { + it('should return true if oucodeL1Code is B', () => { + expect(isMagistratesCourt({ oucodeL1Code: 'B' } as any)).toBe(true); + }); + + it('should return false if oucodeL1Code is not B', () => { + expect(isMagistratesCourt({ oucodeL1Code: 'X' } as any)).toBe(false); + }); +}); diff --git a/projects/scheduling/src/utils/__tests__/rotaBusinessType.spec.ts b/projects/scheduling/src/utils/__tests__/rotaBusinessType.spec.ts new file mode 100644 index 0000000..bd57b15 --- /dev/null +++ b/projects/scheduling/src/utils/__tests__/rotaBusinessType.spec.ts @@ -0,0 +1,33 @@ +import { getRotaBusinessTypeOptions, isRotaBusinessTypeDurationBased } from '../rotaBusinessType'; + +describe('getRotaBusinessTypeOptions', () => { + it('should map and sort rota business types', () => { + const input = [ + { typeCode: 'TRL', typeDescription: 'Trial' }, + { typeCode: 'BL', typeDescription: 'Bail' } + ] as any; + + const result = getRotaBusinessTypeOptions(input); + expect(result).toEqual([ + { value: 'BL', label: 'Bail' }, + { value: 'TRL', label: 'Trial' } + ]); + }); +}); + +describe('isRotaBusinessTypeDurationBased', () => { + it('should return true if the business type has duration', () => { + const input = [{ typeCode: 'X', duration: true }] as any; + expect(isRotaBusinessTypeDurationBased('X', input)).toBe(true); + }); + + it('should return false if the business type has no duration', () => { + const input = [{ typeCode: 'X', duration: false }] as any; + expect(isRotaBusinessTypeDurationBased('X', input)).toBe(false); + }); + + it('should return false if the business type is not found', () => { + const input = [{ typeCode: 'A', duration: true }] as any; + expect(isRotaBusinessTypeDurationBased('Z', input)).toBe(false); + }); +}); diff --git a/projects/scheduling/src/utils/allocations.ts b/projects/scheduling/src/utils/allocations.ts new file mode 100644 index 0000000..cfc9e73 --- /dev/null +++ b/projects/scheduling/src/utils/allocations.ts @@ -0,0 +1,18 @@ +import { AllocationsFormConfig } from '../types'; +import { InjectionToken } from '@angular/core'; + +export const ALLOCATION_FORM_CONFIGS = new InjectionToken>( + 'AllocationFormConfigs' +); + +export const allocationFormConfigs: Record = { + showHearingType: { + formFields: ['hearingType'] + }, + showNotification: { + formFields: ['sendNotificationToParties'] + }, + showHearingTypeAndNotification: { + formFields: ['hearingType', 'sendNotificationToParties'] + } +}; diff --git a/projects/scheduling/src/utils/courtrooms.ts b/projects/scheduling/src/utils/courtrooms.ts new file mode 100644 index 0000000..18738e5 --- /dev/null +++ b/projects/scheduling/src/utils/courtrooms.ts @@ -0,0 +1,14 @@ +import { SelectOption } from '@cpp/pdk'; +import { OrganisationUnit } from '@cpp/reference-data'; + +export const getCourtroomOptions = ( + organisationUnit?: OrganisationUnit +): SelectOption[] => { + if (organisationUnit && organisationUnit.courtrooms) { + return organisationUnit.courtrooms.map((courtroom) => ({ + value: courtroom.id, + label: courtroom.courtroomName + })); + } + return []; +}; diff --git a/projects/scheduling/src/utils/hearingSlotTime.ts b/projects/scheduling/src/utils/hearingSlotTime.ts new file mode 100644 index 0000000..d294c0b --- /dev/null +++ b/projects/scheduling/src/utils/hearingSlotTime.ts @@ -0,0 +1,90 @@ +import { HearingSlot } from '../types'; +import { SelectOption } from '@cpp/pdk'; +import { CUSTOM_SESSION_TIME_LIMITS } from './sessionTimings'; + +type SelectTimeOption = SelectOption & { count: number }; + +/** + * Converts hours and minutes to a 12-hour formatted time string with am/pm. + */ +const formatHoursMinutes = (hours: number, minutes: number): string => { + const isPM = hours >= 12; + const formattedHour = hours % 12 || 12; + const formattedMinutes = minutes.toString().padStart(2, '0'); + return `${formattedHour}:${formattedMinutes}${isPM ? 'pm' : 'am'}`; +}; + +/** + * Formats a "HH:mm" time string to 12-hour time. + */ +const formatTimeString = (timeStr: string): string => { + const [hhStr, mmStr] = timeStr.split(':'); + const hours = parseInt(hhStr, 10); + const minutes = parseInt(mmStr, 10); + return formatHoursMinutes(hours, minutes); +}; + +/** + * Checks if input is a time-only string ("HH:mm"). + */ +const isTimeOnlyFormat = (timeOrIsoDate: string): boolean => + Number.isNaN(Date.parse(timeOrIsoDate)); + +/** + * Formats a time string or full ISO datetime string to 12-hour time with am/pm. + * If sessionDate is provided and timeOrIsoDate is "HH:mm", time is treated as UTC on that date, then converted to local time. + * If a full ISO datetime string is passed, it's parsed directly. + * + * @param timeOrIsoDate - "HH:mm" or full ISO datetime string + * @param sessionDate - Optional YYYY-MM-DD date string + * @returns Formatted 12-hour time string (e.g., "2:00pm") + */ +export const formatSessionTime = (timeOrIsoDate: string, sessionDate?: string): string => { + if (!timeOrIsoDate) return ''; + + if (sessionDate && isTimeOnlyFormat(timeOrIsoDate)) { + const [hh, mm] = timeOrIsoDate.split(':'); + const date = new Date(`${sessionDate}T${hh}:${mm}:00Z`); + return formatHoursMinutes(date.getHours(), date.getMinutes()); + } else if (isTimeOnlyFormat(timeOrIsoDate)) { + return formatTimeString(timeOrIsoDate); + } else { + const date = new Date(timeOrIsoDate); + return formatHoursMinutes(date.getHours(), date.getMinutes()); + } +}; + +export const getHearingSlotTimeOptions = (hearingSlot: HearingSlot): SelectTimeOption[] => { + const { courtSession, slotStartTimes = [] } = hearingSlot; + const sessionRange = CUSTOM_SESSION_TIME_LIMITS[courtSession]; + + const isWithinSessionRange = (localTime: string): boolean => + localTime >= sessionRange.min && localTime <= sessionRange.max; + + return slotStartTimes + .filter((slot) => { + const localStart = new Date(slot.sessionStartTime); + const localStartTimeStr = localStart.toTimeString().slice(0, 5); // "HH:mm" + return isWithinSessionRange(localStartTimeStr); + }) + .map((slot) => ({ + value: slot.sessionStartTime, + count: slot.count, + label: `${formatSessionTime(slot.sessionStartTime)} to ${formatSessionTime( + slot.sessionEndTime + )}` + })); +}; + +export const getHearingSlotTimestamp = ({ + sessionDate, + slotStartTimes, + courtSession +}: HearingSlot): string => { + if (slotStartTimes?.[0]?.sessionStartTime) { + return slotStartTimes[0].sessionStartTime; + } + + const defaultTime = courtSession === 'PM' ? '14:00' : '10:00'; + return new Date(`${sessionDate}T${defaultTime}`).toISOString(); +}; diff --git a/projects/scheduling/src/utils/index.ts b/projects/scheduling/src/utils/index.ts new file mode 100644 index 0000000..799210e --- /dev/null +++ b/projects/scheduling/src/utils/index.ts @@ -0,0 +1,6 @@ +export * from './rotaBusinessType'; +export * from './operationalUnit'; +export * from './courtrooms'; +export * from './hearingSlotTime'; +export * from './allocations'; +export * from './sessionTimings'; diff --git a/projects/scheduling/src/utils/operationalUnit.ts b/projects/scheduling/src/utils/operationalUnit.ts new file mode 100644 index 0000000..0e401bf --- /dev/null +++ b/projects/scheduling/src/utils/operationalUnit.ts @@ -0,0 +1,21 @@ +import { SelectOption } from '@cpp/pdk'; +import { OrganisationUnit, sortSelectOptionAlphabetical } from '@cpp/reference-data'; + +export const getOperationalUnitOptions = ( + organisationUnits: OrganisationUnit[] +): SelectOption[] => { + const operationalUnitOptions = [] as SelectOption[]; + for (const organisationUnit of organisationUnits) { + if (!operationalUnitOptions.find((option) => option.value === organisationUnit.oucodeL2Code)) { + operationalUnitOptions.push({ + value: organisationUnit.oucodeL2Code!, + label: organisationUnit.oucodeL2Name! + }); + } + } + operationalUnitOptions.sort(sortSelectOptionAlphabetical); + return operationalUnitOptions; +}; + +export const isMagistratesCourt = (organisationUnit: OrganisationUnit): boolean => + organisationUnit?.oucodeL1Code === 'B'; diff --git a/projects/scheduling/src/utils/rotaBusinessType.ts b/projects/scheduling/src/utils/rotaBusinessType.ts new file mode 100644 index 0000000..1f40f37 --- /dev/null +++ b/projects/scheduling/src/utils/rotaBusinessType.ts @@ -0,0 +1,22 @@ +import { SelectOption } from '@cpp/pdk'; +import { RotaBusinessType, sortSelectOptionAlphabetical } from '@cpp/reference-data'; + +export const getRotaBusinessTypeOptions = ( + rotaBusinessTypes: RotaBusinessType[] +): SelectOption[] => + rotaBusinessTypes + .map((rotaBusinessType) => ({ + value: rotaBusinessType.typeCode, + label: rotaBusinessType.typeDescription + })) + .sort(sortSelectOptionAlphabetical); + +export const isRotaBusinessTypeDurationBased = ( + rotaBusinessTypeCode: string, + initialRotaBusinessTypes: RotaBusinessType[] +): boolean => { + const rotaBusinessType = initialRotaBusinessTypes.find( + (type) => type.typeCode === rotaBusinessTypeCode + ); + return rotaBusinessType ? rotaBusinessType.duration : false; +}; diff --git a/projects/scheduling/src/utils/sessionTimings.ts b/projects/scheduling/src/utils/sessionTimings.ts new file mode 100644 index 0000000..1bdf0e4 --- /dev/null +++ b/projects/scheduling/src/utils/sessionTimings.ts @@ -0,0 +1,19 @@ +import { HearingSlot } from '../types'; + +export const CUSTOM_SESSION_TIME_LIMITS: Record< + HearingSlot['courtSession'], + { min: string; max: string } +> = { + AM: { min: '01:00', max: '13:00' }, + PM: { min: '14:00', max: '23:00' }, + AD: { min: '01:00', max: '23:00' } +} as const; + +export const NATIONAL_STANDARD_TIMES: Record< + HearingSlot['courtSession'], + { sessionStartTime: string; sessionEndTime: string } +> = { + AM: { sessionStartTime: '10:00', sessionEndTime: '13:00' }, + PM: { sessionStartTime: '14:00', sessionEndTime: '17:00' }, + AD: { sessionStartTime: '10:00', sessionEndTime: '17:00' } +} as const; diff --git a/projects/scheduling/tsconfig.lib.json b/projects/scheduling/tsconfig.lib.json new file mode 100644 index 0000000..f7a6ac0 --- /dev/null +++ b/projects/scheduling/tsconfig.lib.json @@ -0,0 +1,25 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "../../out-tsc/lib", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "skipLibCheck": true, + "paths": { + "@cpp/core": ["../../dist/core"], + "@cpp/reference-data": ["../../dist/reference-data"] + } + }, + "angularCompilerOptions": { + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true, + "compilationMode": "partial" + }, + "exclude": ["**/*.spec.ts"] +} diff --git a/projects/scheduling/tsconfig.lib.prod.json b/projects/scheduling/tsconfig.lib.prod.json new file mode 100644 index 0000000..06de549 --- /dev/null +++ b/projects/scheduling/tsconfig.lib.prod.json @@ -0,0 +1,10 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/projects/scheduling/tsconfig.spec.json b/projects/scheduling/tsconfig.spec.json new file mode 100644 index 0000000..d6498a8 --- /dev/null +++ b/projects/scheduling/tsconfig.spec.json @@ -0,0 +1,10 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "allowJs": true, + "outDir": "../../out-tsc/spec", + "types": ["jest", "node"] + }, + "include": ["**/*.spec.ts", "**/*.d.ts"] +} diff --git a/projects/testing/package.json b/projects/testing/package.json new file mode 100644 index 0000000..71eb48a --- /dev/null +++ b/projects/testing/package.json @@ -0,0 +1,11 @@ +{ + "name": "@cpp/testing", + "version": "0.0.0-PLACEHOLDER", + "main": "index.js", + "dependencies": { + "chalk": "^3.0.0", + "request": "^2.88.0", + "tslib": "^2.0.0", + "uuid": "^3.3.2" + } +} diff --git a/projects/testing/src/index.ts b/projects/testing/src/index.ts new file mode 100644 index 0000000..4aaf8f9 --- /dev/null +++ b/projects/testing/src/index.ts @@ -0,0 +1 @@ +export * from './public_api'; diff --git a/projects/testing/src/public_api.ts b/projects/testing/src/public_api.ts new file mode 100644 index 0000000..5f003df --- /dev/null +++ b/projects/testing/src/public_api.ts @@ -0,0 +1,4 @@ +export * from './util/log'; +export * from './util/pollUntil'; +export * from './util/request'; +export * from './util/urn'; diff --git a/projects/testing/src/resources/index.ts b/projects/testing/src/resources/index.ts new file mode 100644 index 0000000..5dcfb85 --- /dev/null +++ b/projects/testing/src/resources/index.ts @@ -0,0 +1,2 @@ +export * from './organisationUnits'; +export * from './users'; diff --git a/projects/testing/src/resources/organisationUnits.ts b/projects/testing/src/resources/organisationUnits.ts new file mode 100644 index 0000000..75b97de --- /dev/null +++ b/projects/testing/src/resources/organisationUnits.ts @@ -0,0 +1,43 @@ +interface OrganisationUnit { + id: string; + oucodeL3Name: string; + courtrooms: Array<{ + id: string; + courtroomName: string; + }>; +} + +export const LAVENDAR_HILL_MAGISTRATES_COURT: OrganisationUnit = { + id: 'f8254db1-1683-483e-afb3-b87fde5a0a26', + oucodeL3Name: `Lavender Hill Magistrates' Court`, + courtrooms: [ + { id: '9e4932f7-97b2-3010-b942-ddd2624e4dd8', courtroomName: 'Courtroom 01' }, + { id: 'b4562684-9209-3ec4-a544-7f80dabd94d8', courtroomName: 'Courtroom 02' }, + { id: 'f1ead1d2-4b26-3230-b781-508d6aaafd26', courtroomName: 'Courtroom 03' }, + { id: 'b6cc0e08-6227-3786-8ebe-36febddec7ff', courtroomName: 'Courtroom 04' } + ] +}; + +export const LIVERPOOL_CROWN_COURT: OrganisationUnit = { + id: '9b583616-049b-30f9-a14f-028a53b7cfe8', + oucodeL3Name: 'Liverpool Crown Court', + courtrooms: [ + { id: '7cb09222-49e1-3622-a5a6-ad253d2b3c39', courtroomName: 'Crown Court 3-1' }, + { id: 'a5e56fa9-c4a6-300a-98e3-2596895f0305', courtroomName: 'Crown Court 3-2' }, + { id: 'd54eae66-32e7-31da-84f1-66e24ec08d29', courtroomName: 'Crown Court 3-3' }, + { id: '3613ed6d-f727-317e-842e-ce437c4dc632', courtroomName: 'Crown Court 4-1' }, + { id: 'd8b5a2cd-a100-3912-861f-f7b93147d01f', courtroomName: 'Crown Court 4-2' }, + { id: 'b890bd6d-6903-3d4d-af01-3c41df38bfb6', courtroomName: 'Crown Court 4-3' }, + { id: 'c4d71387-a21f-30a1-b09b-b777a67961ab', courtroomName: 'Crown Court 4-4' }, + { id: 'b61a5a89-0b19-3f8b-a98f-3ba5c15b7254', courtroomName: 'Crown Court 4-5' }, + { id: '6508af42-e4d4-396d-a752-d676ebd38f6d', courtroomName: 'Crown Court 4-6' }, + { id: '414ecb12-f91f-3031-b9ce-f40c48c3f620', courtroomName: 'Crown Court 5-1' }, + { id: 'eab274c1-8879-3f08-9c42-1a7673e7100a', courtroomName: 'Crown Court 5-2' }, + { id: 'fbe3ca1a-6be6-3bd5-86e8-fc879aa5e3e7', courtroomName: 'Crown Court 5-3' }, + { id: 'a92d8cb1-69b4-37c4-9fb0-9e1d508eaebc', courtroomName: 'Crown Court 5-4' }, + { id: '0997c600-8dc5-330b-81b1-94cb6fcec37f', courtroomName: 'Crown Court 5-5' }, + { id: '8a6178d5-ad30-3d75-92ea-e44a12c50a52', courtroomName: 'Crown Court 5-6' }, + { id: '106b248f-ac0f-39b4-a64c-7d90356d0771', courtroomName: 'Crown Court 6-1' }, + { id: '39b885b5-034f-30cb-83ca-e45982230402', courtroomName: 'Crown Court 6-2' } + ] +}; diff --git a/projects/testing/src/resources/users.ts b/projects/testing/src/resources/users.ts new file mode 100644 index 0000000..fd06b53 --- /dev/null +++ b/projects/testing/src/resources/users.ts @@ -0,0 +1,244 @@ +export interface User { + userId: string; + firstName: string; + lastName: string; + email: string; +} + +export const CHARGING_LAWYER: User = { + userId: 'e54c087a-ff26-4088-ad2b-040a0182cd12', + firstName: 'Jake', + lastName: 'Johnson', + email: 'j.johnson@test.cps.gov.uk' +}; + +export const CHARGING_LAWYER_II: User = { + userId: '4665a811-2257-44b1-a04c-53a5c0bc1dd4', + firstName: 'Lana', + lastName: 'Lampard', + email: 'l.lampard@test.cps.gov.uk' +}; + +export const CHARGING_LAWYER_III: User = { + userId: 'e54c087a-ff26-4088-ad2b-040a0182cd11', + firstName: 'Tina', + lastName: 'Turner', + email: 't.turner@test.cps.gov.uk' +}; + +export const CJSE_USER: User = { + userId: 'd7c91866-646a-462c-9203-46678e8cddef', + firstName: 'cjse', + lastName: 'system', + email: 'cjse@system.gov' +}; + +export const CMS_USER: User = { + userId: '48a948dc-7d96-45bd-baa5-5237432152d2', + firstName: 'cms', + lastName: 'system', + email: 'cms@system.gov' +}; + +export const COURT_ADMINISTRATOR: User = { + userId: 'a9448185-672e-4aea-94d6-5988355ed459', + firstName: 'Helen', + lastName: 'Sutton', + email: 'helen@test.hmcts.net' +}; + +export const COURT_ADMINISTRATOR_II: User = { + userId: 'a9448185-672e-4aea-94d6-5988355ed459', + firstName: 'Amy', + lastName: 'Simmons', + email: 'b53e576a-23cd-4e55-9434-19c9a59171b6' +}; + +export const COURT_CLERK: User = { + userId: '8959b8b5-92bd-4ada-96f4-7ac9d482671a', + firstName: 'Robert', + lastName: 'Barnes', + email: 'robert.barnes@test.hmcts.gov.uk' +}; + +export const COURT_CLERK_II: User = { + userId: 'c631f396-76a6-4a35-a6bc-4dca10b9e6d3', + firstName: 'Marion', + lastName: 'Martin', + email: 'marion.martin@test.hmcts.gov.uk' +}; + +export const CPS_USER: User = { + userId: 'ad0920bd-521a-4f40-b942-f82d258ea3cc', + firstName: 'Cps', + lastName: 'User', + email: 'cps.user@hmcts.net' +}; + +export const CROWN_COURT_ADMIN: User = { + userId: '42c405cd-294a-4f32-b55b-afef8e5fd618', + firstName: 'Sarah', + lastName: 'Simmons', + email: 'sarah.simmons@test.hmcts.net' +}; + +export const DEFENCE_USER: User = { + userId: 'fba5005d-13db-4658-8d3c-a3fdfc1fb9d9', + firstName: 'John', + lastName: 'Smith', + email: 'john.smith@smithsolicitors.co.uk' +}; + +export const DEFENCE_USER_II: User = { + userId: 'fba6664d-13db-4658-8d3c-a3fdfc1fb9d9', + firstName: 'David', + lastName: 'Wilson', + email: 'david.wilson@wilsonsolicitors.co.uk' +}; + +export const DEFENCE_USER_III: User = { + userId: 'fba5554d-13db-4658-8d3c-a3fdfc1fb9d9', + firstName: 'Mark', + lastName: 'Brown', + email: 'mark.brown@brownsolicitors.co.uk' +}; + +export const JUDGE: User = { + userId: 'e54c087a-ff26-5099-ad2b-040a0182cd22', + firstName: 'Richard', + lastName: 'Chapman', + email: 'richard.chapman@acme.com' +}; + +export const JUDICIARY: User = { + userId: '3ad9a9df-956a-4413-abc9-a9351219f0fc', + firstName: 'James', + lastName: 'Black', + email: 'james.black@test.hmcts.net' +}; + +export const LEGAL_ADVISER: User = { + userId: '676ae4c5-fdd9-469e-a528-dd5b12c90287', + firstName: 'Emma', + lastName: 'Cleaner', + email: 'emma.cleaner@test.hmcts.net' +}; + +export const LEGAL_ADVISER_II: User = { + userId: '735b9bf6-2f4c-4947-92af-b607c7d2880f', + firstName: 'Evan', + lastName: 'Roberts', + email: 'evan@test.hmcts.net' +}; + +export const LEGAL_ADVISER_III: User = { + userId: 'a085e359-6069-4694-8820-7810e7dfe762', + firstName: 'Erica', + lastName: 'Wilson', + email: 'erica@test.hmcts.net' +}; + +export const LISTING_OFFICER: User = { + userId: '3ad7a9df-956a-4413-abc7-a9351217f0fc', + firstName: 'Jane', + lastName: 'Davies', + email: 'jane.davies@test.hmcts.net' +}; + +export const POLICE_ADMIN: User = { + userId: 'c03ad5ae-648e-4ee1-8bed-68935602ea69', + firstName: 'Krista', + lastName: 'Knight', + email: 'krista.knight@test.Merseyside.pnn.police.uk' +}; + +export const PRISON_ADMIN: User = { + userId: 'fda4005d-13db-4658-8d3c-a3fdfc1fb7d9', + firstName: 'Joe', + lastName: 'Bloggs', + email: 'joe.bloggs@test.hmps.gsi.gov.uk' +}; + +export const PRISON_ADMIN_II: User = { + userId: '23967a19-06ec-41bd-a472-f31344c8946d', + firstName: 'Mark', + lastName: 'Adams', + email: 'mark.adams@test.cps.gov.uk' +}; + +export const PROBATION_ADMIN: User = { + userId: '4bae9821-6a14-425a-ae0d-6c5476bdd0ba', + firstName: 'Rickey', + lastName: 'Vaughn', + email: 'rickey.vaughn@test.probation.gsi.gov.uk' +}; + +export const SJP_PROSECUTOR: User = { + userId: '85435116-0f4b-4616-ae9a-9954ed1c3ee1', + firstName: 'Trevor', + lastName: 'Lawson', + email: 'trevor@test.tvl.uk' +}; + +export const SJP_PROSECUTOR_II: User = { + userId: '1bf60455-11c9-427e-b087-d8331dcea44f', + firstName: 'David', + lastName: 'Brown', + email: 'david@test.tfl.net' +}; + +export const TFL_PROSECUTOR: User = { + userId: '1bf60455-11c9-427e-b087-d8331dcea44f', + firstName: 'David', + lastName: 'Brown', + email: 'david@test.tfl.net' +}; + +export const TVL_PROSECUTOR: User = { + userId: '85435116-0f4b-4616-ae9a-9954ed1c3ee1', + firstName: 'Trevor', + lastName: 'Lawson', + email: 'trevor@test.tvl.uk' +}; + +export const SYS_ADMIN: User = { + userId: '0e61972a-0a26-4de1-a676-36119c535a60', + firstName: 'Chris', + lastName: 'Williams', + email: 'chris.williams@test.hmcts.net' +}; + +export const ORG_ADMIN: User = { + userId: '9b07e56c-3d50-4d2f-ad03-168c6b0b43f6', + firstName: 'Matt', + lastName: 'Block', + email: 'matt.block@legalco.net' +}; + +export const CPS_MANAGER_USER: User = { + userId: '2c4744e4-09ee-4599-b7cd-94a06b0a1473', + firstName: 'Manager', + lastName: 'Manager', + email: 'manager.manager@test.cps.gov.uk' +}; + +export const CPS_PROSECUTING_ADVOCATE_USER: User = { + userId: '92689d17-5c69-43d0-b629-babc8481d9db', + firstName: 'Prosecuting', + lastName: 'Advocate', + email: 'prosecuting.advocate@test.cps.gov.uk' +}; + +export const CPS_PROSECUTOR_USER: User = { + userId: '41022edf-b033-40a2-b70d-056c94b8a46f', + firstName: 'Operational', + lastName: 'Delvery', + email: 'operational.delivery@test.cps.gov.uk' +}; + +export const CPS_PARALEGAL_USER: User = { + userId: 'cad49221-2a1e-4195-a66c-38c1025e7d34', + firstName: 'Paralegal', + lastName: 'Paralegal', + email: 'paralegal.paralegal@test.cps.gov.uk' +}; diff --git a/projects/testing/src/util/log.ts b/projects/testing/src/util/log.ts new file mode 100644 index 0000000..352c71e --- /dev/null +++ b/projects/testing/src/util/log.ts @@ -0,0 +1,39 @@ +import chalk from 'chalk'; +import { RequestResponse } from 'request'; + +const log = (msg: string, addTimestamp = true): void => { + let finalMsg = msg; + + if (addTimestamp) { + const now = new Date(); + const time = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`; + const timestamp = `[${chalk.gray(time)}]`; + finalMsg = `${timestamp} ${msg}`; + } + process.stdout.write(`${finalMsg}\n`); + + function pad(num: number) { + const val = num !== undefined ? num.toString() : ''; + return val.length >= 2 ? val : new Array(2 - val.length + 1).join('0') + val; + } +}; + +export const debug = (msg: string): void => { + log(chalk.cyan(msg)); +}; + +export const info = (msg: string): void => { + log(chalk.magenta(msg)); +}; + +export const error = (msg: string): void => { + log(chalk.red(msg)); +}; + +export const logResponse = ({ method, request, statusCode }: RequestResponse): void => { + const methodMsg = chalk.cyan(`${method || request.method} `.slice(0, 4)); + const statusMsg = + statusCode >= 400 ? chalk.red(String(statusCode)) : chalk.green(String(statusCode)); + + log(`${methodMsg} ${statusMsg} ${request.uri.href}`); +}; diff --git a/projects/testing/src/util/pollUntil.ts b/projects/testing/src/util/pollUntil.ts new file mode 100644 index 0000000..4d023f2 --- /dev/null +++ b/projects/testing/src/util/pollUntil.ts @@ -0,0 +1,34 @@ +import { of, throwError } from 'rxjs'; +import { concat, delay, map, retryWhen, switchMap, take } from 'rxjs/operators'; + +export function pollUntil( + fn: () => Promise, + conditionFn?: (result: T) => boolean +): Promise { + const hasCriteria = conditionFn || (result => Boolean(result)); + + return new Promise((resolve, reject) => { + of(null) + .pipe( + switchMap(fn), + map(result => { + if (hasCriteria(result)) { + return result; + } + throw new Error('Criteria did not match'); + }), + retryWhen(errors$ => + errors$.pipe( + delay(1000), + take(24), + concat(throwError('Polling expired after 25 seconds.')) + ) + ) + ) + .subscribe(resolve, reject); + }); +} + +export function pollUntilExists(fn: () => Promise): Promise { + return pollUntil(fn, value => Boolean(value)); +} diff --git a/projects/testing/src/util/request.ts b/projects/testing/src/util/request.ts new file mode 100644 index 0000000..19b9579 --- /dev/null +++ b/projects/testing/src/util/request.ts @@ -0,0 +1,56 @@ +import nodeRequest, { CoreOptions, OptionsWithUrl } from 'request'; +import { User } from '../resources'; +import { logResponse } from './log'; + +export type CppOptions = OptionsWithUrl & { + user: User; +}; + +let defaultOptions: CoreOptions = {}; + +const isJson = (str: string): boolean => { + try { + JSON.parse(str); + } catch (e) { + return false; + } + return true; +}; + +export const request = ({ user, url, ...options }: CppOptions): Promise => { + const { userId } = user; + const finalOptions = { + ...defaultOptions, + ...options, + url, + body: typeof options.body === 'object' ? JSON.stringify(options.body) : options.body, + // set agent to false to prevent ESOCKETTIMEDOUT errors on dns resolution + // https://github.com/request/request/issues/1231 + agent: false as any, + headers: { + ...(options.headers || {}), + CJSCPPUID: userId + }, + qs: { + ...(options.qs || {}), + CJSCPPUID: userId + } + }; + + return new Promise((resolve, reject) => { + nodeRequest(finalOptions, (err, response, body) => { + if (response && response.statusCode) { + logResponse(response); + } + if (err || response.statusCode >= 400) { + reject(err || response); + } else { + resolve(isJson(body) ? JSON.parse(body) : body); + } + }); + }); +}; + +export const setPrimingDefaults = (options: CoreOptions): void => { + defaultOptions = options; +}; diff --git a/projects/testing/src/util/urn.ts b/projects/testing/src/util/urn.ts new file mode 100644 index 0000000..63cffe5 --- /dev/null +++ b/projects/testing/src/util/urn.ts @@ -0,0 +1,14 @@ +export const createUrn = () => { + const force = randomIntFromRange(10, 99).toString(); + const unit = 'GD'; + const number = randomIntFromRange(10000, 99999).toString(); + const suffix = new Date() + .getFullYear() + .toString() + .slice(2); + + function randomIntFromRange(min: number, max: number) { + return Math.floor(Math.random() * (max - min + 1) + min); + } + return `${force}${unit}${number}${suffix}`; +}; diff --git a/projects/testing/tsconfig.json b/projects/testing/tsconfig.json new file mode 100644 index 0000000..440b7a2 --- /dev/null +++ b/projects/testing/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "../../dist/testing", + "target": "es2015", + "module": "CommonJS", + "moduleResolution": "node", + "esModuleInterop": true, + "declaration": true, + "sourceMap": false, + "importHelpers": true, + "lib": ["es2018", "DOM"] + }, + "include": ["src"], + "exclude": ["**/*.spec.ts"] +} diff --git a/projects/users-groups/.eslintrc.json b/projects/users-groups/.eslintrc.json new file mode 100644 index 0000000..0ade740 --- /dev/null +++ b/projects/users-groups/.eslintrc.json @@ -0,0 +1,38 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": [ + "projects/users-groups/tsconfig.lib.json", + "projects/users-groups/tsconfig.spec.json" + ], + "createDefaultProgram": true + }, + "extends": ["prettier"], + "rules": { + "@angular-eslint/component-class-suffix": "off", + "@typescript-eslint/consistent-type-definitions": "off", + "@typescript-eslint/dot-notation": "off", + "@typescript-eslint/explicit-member-accessibility": [ + "off", + { + "accessibility": "explicit" + } + ], + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/unified-signatures": "off", + "@typescript-eslint/no-shadow": "off", + "id-blacklist": "off", + "id-match": "off", + "no-underscore-dangle": "off" + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/projects/users-groups/ng-package.json b/projects/users-groups/ng-package.json new file mode 100644 index 0000000..95b63d9 --- /dev/null +++ b/projects/users-groups/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/users-groups", + "lib": { + "entryFile": "src/index.ts" + } +} diff --git a/projects/users-groups/package.json b/projects/users-groups/package.json new file mode 100644 index 0000000..83a905e --- /dev/null +++ b/projects/users-groups/package.json @@ -0,0 +1,15 @@ +{ + "name": "@cpp/users-groups", + "version": "0.0.0-PLACEHOLDER", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": "^19.0.0", + "@angular/core": "^19.0.0", + "@angular/router": "^19.0.0", + "@cpp/core": "^0.0.0-PLACEHOLDER", + "@ngrx/store": "^19.0.0" + }, + "peerDepenciesComment": "Do not modify placeholders in this file" +} diff --git a/projects/users-groups/src/actions/index.ts b/projects/users-groups/src/actions/index.ts new file mode 100644 index 0000000..f4b7ad0 --- /dev/null +++ b/projects/users-groups/src/actions/index.ts @@ -0,0 +1,3 @@ +import * as UsersGroupsActions from './users-groups.actions'; + +export { UsersGroupsActions }; diff --git a/projects/users-groups/src/actions/users-groups.actions.ts b/projects/users-groups/src/actions/users-groups.actions.ts new file mode 100644 index 0000000..932b256 --- /dev/null +++ b/projects/users-groups/src/actions/users-groups.actions.ts @@ -0,0 +1,61 @@ +import { createAction, props } from '@ngrx/store'; +import { + UserDetails, + UserGroup, + UserService, + RolePermission, + UserRole, + UserOrganisation, + UserGroupWithOrganisation, + UserServiceFeature +} from '../users-groups.interfaces'; +import { HttpErrorResponse } from '@angular/common/http'; + +export const setUserDetails = createAction( + 'SET_USER_DETAILS', + props<{ userDetails: UserDetails }>() +); + +/**@deprecated use the method, setUserPermissions, action instead. */ +export const setUserGroups = createAction('SET_USER_GROUPS', props<{ userGroups: UserGroup[] }>()); + +export const setUserRoles = createAction('SET_USER_ROLES', props<{ userRoles: UserRole[] }>()); + +export const setUserServices = createAction( + 'SET_USER_SERVICES', + props<{ userServices: UserService[] }>() +); + +export const setUserOrganisations = createAction( + 'SET_USER_ORGANISATIONS', + props<{ organisations: UserOrganisation[] }>() +); + +export const setGroupsWithOrganisation = createAction( + 'SET_GROUPS_WITH_ORGANISATION', + props<{ groupsWithOrganisation: UserGroupWithOrganisation[] }>() +); + +export const setUserPermissions = createAction( + 'SET_USER_PERMISSIONS', + props<{ + userGroups?: UserGroup[]; + permissions?: RolePermission[]; + switchableRoles?: UserRole[]; + }>() +); + +export const setUserFeatures = createAction( + 'SET_USER_FEATURES', + props<{ pollingInterval?: number }>() +); + +export const setUserFeaturesSuccess = createAction( + 'SET_USER_FEATURES_SUCCESS', + props<{ userFeatures: UserServiceFeature[] }>() +); + +export const setUserFeaturesError = createAction( + 'SET_USER_FEATURES_ERROR', + props<{ error: HttpErrorResponse }>() +); diff --git a/projects/users-groups/src/effects/__tests__/user-groups.effects.spec.ts b/projects/users-groups/src/effects/__tests__/user-groups.effects.spec.ts new file mode 100644 index 0000000..a3d9b02 --- /dev/null +++ b/projects/users-groups/src/effects/__tests__/user-groups.effects.spec.ts @@ -0,0 +1,104 @@ +import { Observable } from 'rxjs'; +import { UserGroupsEffects } from '../user-groups.effects'; +import { TestBed, tick, fakeAsync } from '@angular/core/testing'; +import { StoreModule } from '@ngrx/store'; +import { provideMockActions } from '@ngrx/effects/testing'; +import { UsersGroupsService } from '../../services/users-groups.service'; +import { userGroupsReducer } from '../../reducers/users-groups.reducer'; +import { marbles } from 'rxjs-marbles/marbles'; +import { UsersGroupsActions } from '../../actions'; +import { take, tap } from 'rxjs/operators'; +import { UserServiceFeature } from '../../users-groups.interfaces'; + +describe('UserGroupsEffects', () => { + let actions$: Observable; + let effects: UserGroupsEffects; + let service: UsersGroupsService; + let fetchUserFeatures: jest.Mock; + + beforeEach(() => { + fetchUserFeatures = jest.fn(); + + TestBed.configureTestingModule({ + imports: [ + StoreModule.forRoot( + { + referenceData: userGroupsReducer + }, + { + runtimeChecks: {} + } + ) + ], + providers: [ + UserGroupsEffects, + { + provide: UsersGroupsService, + useValue: { + fetchUserFeatures + } + }, + provideMockActions(() => actions$) + ] + }); + + effects = TestBed.inject(UserGroupsEffects); + service = TestBed.inject(UsersGroupsService); + }); + + const createFeaturesSuccessAction = (userFeatures: UserServiceFeature[]) => + UsersGroupsActions.setUserFeaturesSuccess({ + userFeatures + }); + describe('startFeaturesPolling$', () => { + it('should fetch the user features from the server', fakeAsync( + marbles((m) => { + const setFeaturesAction = UsersGroupsActions.setUserFeatures({}); + + actions$ = m.cold(' -(a|)----', { a: setFeaturesAction }); + const response$ = m.cold('--(b|)---', { b: [{ key: 'feature1' }] }); + const expected$ = m.cold('---(c|)---', { + c: createFeaturesSuccessAction([{ key: 'feature1' }] as UserServiceFeature[]) + }); + + fetchUserFeatures.mockReturnValueOnce(response$); + + m.expect(effects.startFeaturesPolling$.pipe(take(1))).toBeObservable(expected$); + }) + )); + + it('should fetch the user features from the server for the second time after polling interval', fakeAsync( + marbles((m) => { + const setFeaturesAction = UsersGroupsActions.setUserFeatures({ pollingInterval: 1500 }); + + actions$ = m.cold(' -(a|)----', { a: setFeaturesAction }); + const response$ = m.cold(' --(b|)---', { b: [{ key: 'feature1' }] }); + const response2$ = m.cold('--(c|)---', { c: [{ key: 'feature1' }, { key: 'feature2' }] }); + const expected$ = m.cold(' ---(d|)---', { + d: createFeaturesSuccessAction([{ key: 'feature1' }] as UserServiceFeature[]) + }); + const expected2$ = m.cold('---(e|)---', { + e: createFeaturesSuccessAction([ + { key: 'feature1' }, + { key: 'feature2' } + ] as UserServiceFeature[]) + }); + + fetchUserFeatures.mockReturnValueOnce(response$); + m.expect(effects.startFeaturesPolling$.pipe(take(1))).toBeObservable(expected$); + + fetchUserFeatures.mockReturnValueOnce(response2$); + + tick(1550); + m.expect( + effects.startFeaturesPolling$.pipe( + tap(() => { + expect(fetchUserFeatures).toHaveBeenCalledTimes(2); + }), + take(1) + ) + ).toBeObservable(expected2$); + }) + )); + }); +}); diff --git a/projects/users-groups/src/effects/user-groups.effects.ts b/projects/users-groups/src/effects/user-groups.effects.ts new file mode 100644 index 0000000..e5b3a00 --- /dev/null +++ b/projects/users-groups/src/effects/user-groups.effects.ts @@ -0,0 +1,37 @@ +import { Injectable } from '@angular/core'; +import { Observable, timer, of } from 'rxjs'; +import { createEffect, Actions, ofType } from '@ngrx/effects'; +import { Action } from '@ngrx/store'; +import { UsersGroupsService } from '../services/users-groups.service'; +import { + setUserFeatures, + setUserFeaturesSuccess, + setUserFeaturesError +} from '../actions/users-groups.actions'; +import { switchMap, exhaustMap, map, catchError, retryWhen } from 'rxjs/operators'; + +@Injectable() +export class UserGroupsEffects { + // This should be done in the BE using Azure durable functions and a form + // of notification triggered to the front end to mitigate performance issues. + // At this stage the FE shouldn't handle these kind of requests. + // However given that the design had already been + // agreed upon, it was insisted that the FE should handle this polling requests + startFeaturesPolling$: Observable = createEffect(() => + this.actions$.pipe( + ofType(setUserFeatures), + switchMap(({ pollingInterval = 600000 }) => + timer(0, pollingInterval).pipe( + exhaustMap(() => + this.usersGroups.fetchUserFeatures().pipe( + map((userFeatures) => setUserFeaturesSuccess({ userFeatures })), + catchError((error) => of(setUserFeaturesError({ error }))) + ) + ) + ) + ) + ) + ); + + constructor(private actions$: Actions, private usersGroups: UsersGroupsService) {} +} diff --git a/projects/users-groups/src/features/directives/__tests__/__snapshots__/cpp-user-has-feature-enabled.directive.spec.ts.snap b/projects/users-groups/src/features/directives/__tests__/__snapshots__/cpp-user-has-feature-enabled.directive.spec.ts.snap new file mode 100644 index 0000000..ba83833 --- /dev/null +++ b/projects/users-groups/src/features/directives/__tests__/__snapshots__/cpp-user-has-feature-enabled.directive.spec.ts.snap @@ -0,0 +1,30 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CppHasFeatureEnabledDirective Given *cppHasFeatureEnabled is used should not render the expected component is the feature is not found 1`] = ` + + +`; + +exports[`CppHasFeatureEnabledDirective Given *cppHasFeatureEnabled is used should render the alternative template if the feature is not found 1`] = ` + +
+ User does not have this feature enabled. +
+
+`; + +exports[`CppHasFeatureEnabledDirective Given *cppHasFeatureEnabled is used should render the expected component is the feature is found 1`] = ` + +
+ This is displayed only if the feature is enabled +
+
+`; + +exports[`CppHasFeatureEnabledDirective should render 1`] = ` + +
+ This is displayed always. +
+
+`; diff --git a/projects/users-groups/src/features/directives/__tests__/cpp-user-has-feature-enabled.directive.spec.ts b/projects/users-groups/src/features/directives/__tests__/cpp-user-has-feature-enabled.directive.spec.ts new file mode 100644 index 0000000..9cc70d9 --- /dev/null +++ b/projects/users-groups/src/features/directives/__tests__/cpp-user-has-feature-enabled.directive.spec.ts @@ -0,0 +1,94 @@ +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { Component, ChangeDetectorRef } from '@angular/core'; +import { StoreModule } from '@ngrx/store'; +import { CppHasFeatureEnabledDirective } from '../cpp-user-has-feature-enabled.directive'; +import { usersGroups } from '../../../reducers'; +import { provideMockStore } from '@ngrx/store/testing'; + +describe('CppHasFeatureEnabledDirective', () => { + let fixture: ComponentFixture; + let component: CppHasFeatureEnabledTestComponent; + const initialState = { + usersGroups: { + userServices: [], + features: [ + { + key: 'someKey', + title: 'someTitle', + type: 'COMPONENT' + } + ] + } + }; + + beforeEach(async () => { + TestBed.configureTestingModule({ + declarations: [CppHasFeatureEnabledTestComponent], + imports: [ + StoreModule.forRoot({ usersGroups }, { runtimeChecks: {} }), + CppHasFeatureEnabledDirective + ], + providers: [ + provideMockStore({ initialState }), + { provide: ChangeDetectorRef, useValue: { markForCheck: jest.fn() } } + ] + }); + }); + + const setUpFixture = (template: string) => { + TestBed.overrideTemplate(CppHasFeatureEnabledTestComponent, template).compileComponents(); + fixture = TestBed.createComponent(CppHasFeatureEnabledTestComponent); + component = fixture.componentInstance; + }; + + it('should render', () => { + const template = `
This is displayed always.
`; + setUpFixture(template); + expect(fixture).toMatchSnapshot(); + }); + + describe('Given *cppHasFeatureEnabled is used', () => { + it('should render the expected component is the feature is found', () => { + const template = ` +
+ This is displayed only if the feature is enabled +
+ `; + setUpFixture(template); + fixture.detectChanges(); + expect(fixture).toMatchSnapshot(); + }); + + it('should not render the expected component is the feature is not found', () => { + const template = ` +
+ This shouldn't be displayed +
+ `; + setUpFixture(template); + fixture.detectChanges(); + expect(fixture).toMatchSnapshot(); + }); + + it('should render the alternative template if the feature is not found', () => { + const template = ` +
+ This shouldn't be displayed +
+ +
User does not have this feature enabled.
+
+ `; + setUpFixture(template); + fixture.detectChanges(); + expect(fixture).toMatchSnapshot(); + }); + }); +}); + +@Component({ + selector: 'cpp-user-has-feature-enabled-test', + template: ``, + standalone: false +}) +export class CppHasFeatureEnabledTestComponent {} diff --git a/projects/users-groups/src/features/directives/cpp-user-has-feature-enabled.directive.ts b/projects/users-groups/src/features/directives/cpp-user-has-feature-enabled.directive.ts new file mode 100644 index 0000000..305e6e3 --- /dev/null +++ b/projects/users-groups/src/features/directives/cpp-user-has-feature-enabled.directive.ts @@ -0,0 +1,86 @@ +import { + Directive, + Input, + TemplateRef, + ViewContainerRef, + OnDestroy, + ChangeDetectorRef +} from '@angular/core'; +import { select, Store } from '@ngrx/store'; +import { getFeaturesByFeatureType, UsersGroupsState } from '../../reducers'; +import { featuresExist } from '../../utils'; +import { UserServiceFeature } from '../../users-groups.interfaces'; +import { Subscription } from 'rxjs'; + +export interface HasFeatureContext { + $implicit?: boolean; + cppHasFeature?: boolean; +} + +@Directive({ selector: '[cppHasFeatureEnabled]' }) +export class CppHasFeatureEnabledDirective implements OnDestroy { + private context: HasFeatureContext = {} as HasFeatureContext; + private templateRef: TemplateRef | undefined; + private elseTemplateRef: TemplateRef | undefined; + private featuresInStore: UserServiceFeature[] = []; + private expectedFeatureKeys: string[] = []; + private subscription: Subscription; + + @Input() + set cppHasFeatureEnabled(keys: string | string[]) { + this.expectedFeatureKeys = Array.isArray(keys) ? keys : [keys]; + this.updateView(); + } + + @Input() + set cppHasFeatureEnabledElse(templateRef: TemplateRef) { + this.elseTemplateRef = templateRef; + this.updateView(); + } + + constructor( + private viewContainerRef: ViewContainerRef, + templateRef: TemplateRef, + private store: Store, + private cdr: ChangeDetectorRef + ) { + this.templateRef = templateRef; + this.subscription = this.store + .pipe(select(getFeaturesByFeatureType('COMPONENT'))) + .subscribe((features) => { + this.featuresInStore = features; + this.updateView(); + this.cdr.markForCheck(); // cater for change detection OnPush scenarios + }); + } + + updateView() { + this.viewContainerRef.clear(); + this.displayRequiredView(); + } + + displayRequiredView() { + const currentTemplateRef = this.verifyFeature() ? this.templateRef : this.elseTemplateRef; + if (currentTemplateRef) { + return this.viewContainerRef.createEmbeddedView(currentTemplateRef, this.context); + } + } + + // this optional argument is exposed for directive explicitly used in components + verifyFeature(expectedFeatureKeys?: string[]): boolean { + if (expectedFeatureKeys) { + this.expectedFeatureKeys = expectedFeatureKeys; + } + this.context.$implicit = this.context.cppHasFeature = featuresExist( + this.featuresInStore, + this.expectedFeatureKeys + ); + return this.context.$implicit; + } + + ngOnDestroy(): void { + if (this.subscription) { + this.subscription.unsubscribe(); + } + } +} diff --git a/projects/users-groups/src/guards/__tests__/user-details.guard.spec.ts b/projects/users-groups/src/guards/__tests__/user-details.guard.spec.ts new file mode 100644 index 0000000..1e3daf2 --- /dev/null +++ b/projects/users-groups/src/guards/__tests__/user-details.guard.spec.ts @@ -0,0 +1,135 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { DynatraceService } from '@cpp/core'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import * as UsersGroupsActions from '../../actions/users-groups.actions'; +import { usersGroups } from '../../reducers/index'; +import { UsersGroupsService } from '../../services/users-groups.service'; +import { UserDetails } from '../../users-groups.interfaces'; +import { UserDetailsGuard } from '../user-details.guard'; + +describe('UserDetailsGuard', () => { + const trackUserName = jest.fn(); + let guard: UserDetailsGuard; + let store: Store; + let fetchLoggedInUserDetails: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + navigateByUrl = jest.fn(); + fetchLoggedInUserDetails = jest.fn(); + + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot({ usersGroups }, { runtimeChecks: {} })], + providers: [ + UserDetailsGuard, + { + provide: UsersGroupsService, + useValue: { + fetchLoggedInUserDetails + } + }, + { + provide: DynatraceService, + useValue: { + trackUserName + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(UserDetailsGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const mockUserDetails: UserDetails = { + userId: '*', + firstName: 'James', + lastName: 'Gray', + email: 'james@gray.org', + prosecutingAuthorityAccess: 'TFL' + }; + + const createSnapshot = ({ + userDetailsErrorRedirectTo = '', + serviceUnavailableRedirectTo = '' + }: { + userDetailsErrorRedirectTo?: string; + serviceUnavailableRedirectTo?: string; + } = {}) => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + userDetailsErrorRedirectTo, + serviceUnavailableRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the user details exist in the store', () => { + expect.assertions(1); + + const snapshot = createSnapshot(); + + store.dispatch(UsersGroupsActions.setUserDetails({ userDetails: mockUserDetails })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching the user details from the server', () => { + expect.assertions(3); + + const snapshot = createSnapshot(); + + fetchLoggedInUserDetails.mockReturnValue(of(mockUserDetails)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(trackUserName).toHaveBeenCalledWith(mockUserDetails.email); + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + UsersGroupsActions.setUserDetails({ userDetails: mockUserDetails }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the user details', () => { + expect.assertions(2); + + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot({ userDetailsErrorRedirectTo: '/error-page' }); + + fetchLoggedInUserDetails.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + expect(didResolve).toBe(false); + }); + }); + + it('should reject the activation when there is a 404 error fetching the user details', () => { + expect.assertions(2); + + const error = new HttpErrorResponse({ status: 404 }); + const snapshot = createSnapshot({ + serviceUnavailableRedirectTo: '/service-unavailable-error-page' + }); + + fetchLoggedInUserDetails.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(navigateByUrl).toHaveBeenCalledWith('/service-unavailable-error-page'); + expect(didResolve).toBe(false); + }); + }); +}); diff --git a/projects/users-groups/src/guards/__tests__/user-feature-exists.guard.spec.ts b/projects/users-groups/src/guards/__tests__/user-feature-exists.guard.spec.ts new file mode 100644 index 0000000..04e22a0 --- /dev/null +++ b/projects/users-groups/src/guards/__tests__/user-feature-exists.guard.spec.ts @@ -0,0 +1,77 @@ +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import * as UsersGroupsActions from '../../actions/users-groups.actions'; +import { usersGroups } from '../../reducers/index'; +import { UserService, UserServiceFeature } from '../../users-groups.interfaces'; +import { UserFeatureExistsGuard } from '../user-feature-exist.guard'; + +describe('UserFeatureExistsGuard', () => { + let guard: UserFeatureExistsGuard; + let store: Store; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot({ usersGroups }, { runtimeChecks: {} })], + providers: [ + UserFeatureExistsGuard, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(UserFeatureExistsGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + userFeatureExistsPredicate: (userFeatures: UserServiceFeature[]) => + userFeatures.some((userFeature) => userFeature.key === 'someFeature'), + userServiceExistsErrorRedirectTo: '/error-page' + }; + + it('should resolve to true when the predicate matches the user features', () => { + expect.assertions(1); + + store.dispatch( + UsersGroupsActions.setUserFeaturesSuccess({ + userFeatures: [ + { + key: 'someFeature', + title: 'someFeature', + type: 'COMPONENT' + } + ] + }) + ); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should reject the activation when the predicate does not match the user services', () => { + expect.assertions(2); + + store.dispatch( + UsersGroupsActions.setUserFeaturesSuccess({ + userFeatures: [] + }) + ); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + }); +}); diff --git a/projects/users-groups/src/guards/__tests__/user-features.guard.spec.ts b/projects/users-groups/src/guards/__tests__/user-features.guard.spec.ts new file mode 100644 index 0000000..c7f1827 --- /dev/null +++ b/projects/users-groups/src/guards/__tests__/user-features.guard.spec.ts @@ -0,0 +1,120 @@ +import { TestBed } from '@angular/core/testing'; +import { Router, ActivatedRouteSnapshot } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import * as UsersGroupsActions from '../../actions/users-groups.actions'; +import { usersGroups } from '../../reducers/index'; +import { UsersGroupsService } from '../../services/users-groups.service'; +import { UserFeaturesGuard } from '../user-features.guard'; +import { of, throwError } from 'rxjs'; +import { UserServiceFeature } from '../../users-groups.interfaces'; +import { HttpErrorResponse } from '@angular/common/http'; + +describe('UserFeaturesGuard', () => { + let guard: UserFeaturesGuard; + let store: Store; + + let fetchUserFeatures: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + navigateByUrl = jest.fn(); + fetchUserFeatures = jest.fn(); + + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot({ usersGroups }, { runtimeChecks: {} })], + providers: [ + UserFeaturesGuard, + { + provide: UsersGroupsService, + useValue: { + fetchUserFeatures + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(UserFeaturesGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = ({ + userFeaturesErrorRedirectTo = '', + serviceUnavailableRedirectTo = '' + }: { + userFeaturesErrorRedirectTo?: string; + serviceUnavailableRedirectTo?: string; + } = {}) => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + userFeaturesErrorRedirectTo, + serviceUnavailableRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the user services exist in the store', () => { + expect.assertions(1); + const snapshot = createSnapshot(); + store.dispatch( + UsersGroupsActions.setUserFeaturesSuccess({ + userFeatures: [{ key: 'somefeature', title: 'sometitle', type: 'COMPONENT' }] + }) + ); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('Should dispatch an action and resolve true when user features returns an empty array', () => { + expect.assertions(2); + const snapshot = createSnapshot(); + + fetchUserFeatures.mockReturnValue(of([] as UserServiceFeature[])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + UsersGroupsActions.setUserFeaturesSuccess({ userFeatures: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the user features', () => { + expect.assertions(2); + + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot({ userFeaturesErrorRedirectTo: '/error-page' }); + + fetchUserFeatures.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + expect(didResolve).toBe(false); + }); + }); + + it('should reject the activation when there is a 404 error fetching the user features', () => { + expect.assertions(2); + + const error = new HttpErrorResponse({ status: 404 }); + const snapshot = createSnapshot({ + serviceUnavailableRedirectTo: '/service-unavailable-error-page' + }); + + fetchUserFeatures.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(navigateByUrl).toHaveBeenCalledWith('/service-unavailable-error-page'); + expect(didResolve).toBe(false); + }); + }); +}); diff --git a/projects/users-groups/src/guards/__tests__/user-groups-with-organisation.guard.spec.ts b/projects/users-groups/src/guards/__tests__/user-groups-with-organisation.guard.spec.ts new file mode 100644 index 0000000..1c26f34 --- /dev/null +++ b/projects/users-groups/src/guards/__tests__/user-groups-with-organisation.guard.spec.ts @@ -0,0 +1,115 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import * as UsersGroupsActions from '../../actions/users-groups.actions'; +import { usersGroups } from '../../reducers/index'; +import { UsersGroupsService } from '../../services/users-groups.service'; +import { UserGroupWithOrganisation } from '../../users-groups.interfaces'; +import { UserGroupsWithOrganisationGuard } from '@cpp/users-groups'; + +describe('UserGroupsWithOrganisationGuard', () => { + let guard: UserGroupsWithOrganisationGuard; + let store: Store; + + let fetchGroupsWithOrganisation: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + navigateByUrl = jest.fn(); + fetchGroupsWithOrganisation = jest.fn(); + + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot({ usersGroups }, { runtimeChecks: {} })], + providers: [ + UserGroupsWithOrganisationGuard, + { + provide: UsersGroupsService, + useValue: { + fetchGroupsWithOrganisation + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(UserGroupsWithOrganisationGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const mockGroupWithOrganisations: UserGroupWithOrganisation[] = [ + { + groupName: 'SJP Prosecutors', + description: 'Transport for London', + category: 'speciality', + organisationId: '6127a06c-c67b-4972-8b47-ba7b22c0eb10', + roleIds: [], + resultsReferenceDataGroup: 'Probation', + documentsReferenceDataGroup: 'Probation Admin', + groupId: 'd231b119-d748-46da-89fc-293edf114e1' + } + ]; + + const createSnapshot = (groupWithOrganisationsErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + groupWithOrganisationsErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the groups with organisation exist in the store', () => { + expect.assertions(1); + + const snapshot = createSnapshot(); + + store.dispatch( + UsersGroupsActions.setGroupsWithOrganisation({ + groupsWithOrganisation: mockGroupWithOrganisations + }) + ); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching the groups with organisation from the server', () => { + expect.assertions(2); + + const snapshot = createSnapshot(); + + fetchGroupsWithOrganisation.mockReturnValue(of(mockGroupWithOrganisations)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + UsersGroupsActions.setGroupsWithOrganisation({ + groupsWithOrganisation: mockGroupWithOrganisations + }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the groups with organisation', () => { + expect.assertions(1); + + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchGroupsWithOrganisation.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + expect(didResolve).toBe(false); + }); + }); +}); diff --git a/projects/users-groups/src/guards/__tests__/user-groups.guard.spec.ts b/projects/users-groups/src/guards/__tests__/user-groups.guard.spec.ts new file mode 100644 index 0000000..75ef1c8 --- /dev/null +++ b/projects/users-groups/src/guards/__tests__/user-groups.guard.spec.ts @@ -0,0 +1,146 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { DynatraceService } from '@cpp/core'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import * as UsersGroupsActions from '../../actions/users-groups.actions'; +import { usersGroups } from '../../reducers/index'; +import { UsersGroupsService } from '../../services/users-groups.service'; +import { UserGroup } from '../../users-groups.interfaces'; +import { UserGroupsGuard } from '../user-groups.guard'; + +describe('UserGroupsGuard', () => { + const trackUserGroups = jest.fn(); + let guard: UserGroupsGuard; + let store: Store; + let fetchUserGroups: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + navigateByUrl = jest.fn(); + fetchUserGroups = jest.fn(); + + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot({ usersGroups }, { runtimeChecks: {} })], + providers: [ + UserGroupsGuard, + { + provide: UsersGroupsService, + useValue: { + fetchUserGroups + } + }, + { + provide: DynatraceService, + useValue: { + trackUserGroups + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(UserGroupsGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const mockUserGroups: UserGroup[] = [ + { + groupId: 'mock-group-id-1', + groupName: 'mock-group-name-1', + description: 'mock-group-description-1' + }, + { + groupId: 'mock-group-id-2', + groupName: 'mock-group-name-2', + description: 'mock-group-description-£' + }, + { + groupId: 'mock-group-id-3', + groupName: 'mock-group-name-3', + description: 'mock-group-description-3' + } + ]; + + const createSnapshot = ({ + userGroupsErrorRedirectTo = '', + serviceUnavailableRedirectTo = '' + }: { + userGroupsErrorRedirectTo?: string; + serviceUnavailableRedirectTo?: string; + } = {}) => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + userGroupsErrorRedirectTo, + serviceUnavailableRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the user groups exist in the store', () => { + expect.assertions(1); + + const snapshot = createSnapshot(); + + store.dispatch(UsersGroupsActions.setUserGroups({ userGroups: mockUserGroups })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching the user groups from the server', () => { + expect.assertions(3); + + const snapshot = createSnapshot(); + + fetchUserGroups.mockReturnValue(of(mockUserGroups)); + const userGroupNames = (mockUserGroups || []).map((group) => group.groupName); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(trackUserGroups).toHaveBeenCalledWith(userGroupNames); + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + UsersGroupsActions.setUserGroups({ userGroups: mockUserGroups }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the user groups', () => { + expect.assertions(2); + + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot({ userGroupsErrorRedirectTo: '/error-page' }); + + fetchUserGroups.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + expect(didResolve).toBe(false); + }); + }); + + it('should reject the activation when there is a 404 error fetching the user groups', () => { + expect.assertions(2); + + const error = new HttpErrorResponse({ status: 404 }); + const snapshot = createSnapshot({ + serviceUnavailableRedirectTo: '/service-unavailable-error-page' + }); + + fetchUserGroups.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(navigateByUrl).toHaveBeenCalledWith('/service-unavailable-error-page'); + expect(didResolve).toBe(false); + }); + }); +}); diff --git a/projects/users-groups/src/guards/__tests__/user-organisations.guard.spec.ts b/projects/users-groups/src/guards/__tests__/user-organisations.guard.spec.ts new file mode 100644 index 0000000..240f3cb --- /dev/null +++ b/projects/users-groups/src/guards/__tests__/user-organisations.guard.spec.ts @@ -0,0 +1,104 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import * as UsersGroupsActions from '../../actions/users-groups.actions'; +import { usersGroups } from '../../reducers/index'; +import { UsersGroupsService } from '../../services/users-groups.service'; +import { UserOrganisation } from '../../users-groups.interfaces'; +import { UserOrganisationsGuard } from '@cpp/users-groups'; + +describe('UserOrganisationsGuard', () => { + let guard: UserOrganisationsGuard; + let store: Store; + + let fetchOrganisations: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + navigateByUrl = jest.fn(); + fetchOrganisations = jest.fn(); + + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot({ usersGroups }, { runtimeChecks: {} })], + providers: [ + UserOrganisationsGuard, + { + provide: UsersGroupsService, + useValue: { + fetchOrganisations + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(UserOrganisationsGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const mockOrganisations: UserOrganisation[] = [ + { + organisationId: 'test-organisation-id', + organisationName: 'test-organisation-name', + organisationType: 'test-organisation-type' + } + ]; + + const createSnapshot = (userOrganisationsErrorRedirectTo = '') => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + userOrganisationsErrorRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the organisations exist in the store', () => { + expect.assertions(1); + + const snapshot = createSnapshot(); + + store.dispatch(UsersGroupsActions.setUserOrganisations({ organisations: mockOrganisations })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching the organisations from the server', () => { + expect.assertions(2); + + const snapshot = createSnapshot(); + + fetchOrganisations.mockReturnValue(of(mockOrganisations)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + UsersGroupsActions.setUserOrganisations({ organisations: mockOrganisations }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the organisations', () => { + expect.assertions(2); + + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot('/error-page'); + + fetchOrganisations.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + expect(didResolve).toBe(false); + }); + }); +}); diff --git a/projects/users-groups/src/guards/__tests__/user-permissions-exist.guard.spec.ts b/projects/users-groups/src/guards/__tests__/user-permissions-exist.guard.spec.ts new file mode 100644 index 0000000..6408a64 --- /dev/null +++ b/projects/users-groups/src/guards/__tests__/user-permissions-exist.guard.spec.ts @@ -0,0 +1,78 @@ +import { TestBed } from '@angular/core/testing'; +import { Store, StoreModule } from '@ngrx/store'; +import { UsersGroupsState, usersGroups } from '../../reducers/index'; +import { Router, ActivatedRouteSnapshot } from '@angular/router'; +import { setUserPermissions } from '../../actions/users-groups.actions'; +import { RolePermission } from '../../users-groups.interfaces'; +import { UserPermissionsExistGuard } from '../permissions/user-permissions-exist.guard'; + +describe('UserPermissionsExistGuard', () => { + const navigateByUrl = jest.fn(); + let store: Store; + let router: Router; + let guardService: UserPermissionsExistGuard; + let snapShot: ActivatedRouteSnapshot; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot({ usersGroups }, { runtimeChecks: {} })], + providers: [ + UserPermissionsExistGuard, + { + provide: Router, + useValue: { navigateByUrl } + } + ] + }); + + store = TestBed.inject(Store); + guardService = TestBed.inject(UserPermissionsExistGuard); + router = TestBed.inject(Router); + jest.spyOn(store, 'dispatch'); + }); + + it('should activate route when the predicate condition is truthy', () => { + const expectedPermission = { action: 'view', object: 'case' } as RolePermission; + + setUpPermissionTestData(expectedPermission); + + store.dispatch(setUserPermissions({ permissions: [expectedPermission] })); + + expect.assertions(1); + + guardService.canActivate(snapShot).subscribe((canActivate) => { + expect(canActivate).toBeTruthy(); + }); + }); + + it('should not activate route when the predicate condition is falsy', () => { + const expectedPermission = { action: 'view', object: 'case' } as RolePermission; + const existingPermission = { action: 'view', object: 'hearing' } as RolePermission; + setUpPermissionTestData(expectedPermission); + + store.dispatch(setUserPermissions({ permissions: [existingPermission] })); + + expect.assertions(2); + + guardService.canActivate(snapShot).subscribe((canActivate) => { + expect(canActivate).toBeFalsy(); + expect(navigateByUrl).toHaveBeenCalledWith('/unauthorised'); + }); + }); + + const setUpPermissionTestData = ({ action, object, source, target }: RolePermission) => { + snapShot = new ActivatedRouteSnapshot(); + snapShot.data = { + userPermissionsExistsErrorRedirectTo: '/unauthorised', + userPermissionsExistsPredicate: (userPermissions: RolePermission[]) => + userPermissions.some( + (perm) => + perm.action === action && + perm.object === object && + perm.source === source && + perm.target === target + ) + }; + return snapShot; + }; +}); diff --git a/projects/users-groups/src/guards/__tests__/user-permissions.guard.spec.ts b/projects/users-groups/src/guards/__tests__/user-permissions.guard.spec.ts new file mode 100644 index 0000000..97edee8 --- /dev/null +++ b/projects/users-groups/src/guards/__tests__/user-permissions.guard.spec.ts @@ -0,0 +1,220 @@ +import { TestBed } from '@angular/core/testing'; +import { UsersGroupsService } from '../../services/users-groups.service'; +import { Store, StoreModule } from '@ngrx/store'; +import { UsersGroupsState, usersGroups } from '../../reducers/index'; +import { Router, ActivatedRouteSnapshot } from '@angular/router'; +import { setUserPermissions } from '../../actions/users-groups.actions'; +import { RolePermission } from '../../users-groups.interfaces'; +import { of, throwError } from 'rxjs'; +import { HttpErrorResponse } from '@angular/common/http'; +import { UserPermissionsGuard } from '../permissions/user-permissions.guard'; + +describe('UserPermissionsGuard', () => { + const fetchUserPermissions = jest.fn(); + const navigateByUrl = jest.fn(); + const getCurrentNavigation = jest.fn().mockReturnValue({ + extras: {} + }); + let store: Store; + let userGroupService: UsersGroupsService; + let router: Router; + let guardService: UserPermissionsGuard; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot({ usersGroups }, { runtimeChecks: {} })], + providers: [ + UserPermissionsGuard, + { + provide: UsersGroupsService, + useValue: { + fetchUserPermissions + } + }, + { + provide: Router, + useValue: { + navigateByUrl, + getCurrentNavigation + } + } + ] + }); + + store = TestBed.inject(Store); + guardService = TestBed.inject(UserPermissionsGuard); + router = TestBed.inject(Router); + userGroupService = TestBed.inject(UsersGroupsService); + jest.spyOn(store, 'dispatch'); + }); + + it('should activate route when user permissions exist in store', () => { + const { snapShot, permissions } = setUpPermissionTestData([ + { action: 'view', object: 'case' } + ] as RolePermission[]); + + store.dispatch(setUserPermissions({ permissions })); + + expect.assertions(1); + + guardService.canActivate(snapShot).subscribe((canActivate) => { + expect(canActivate).toBe(true); + }); + }); + + it('should call api to retrieve user permissions if not in store', () => { + const { snapShot, permissions } = setUpPermissionTestData([]); + + store.dispatch(setUserPermissions({ permissions })); + + expect.assertions(1); + + guardService.canActivate(snapShot).subscribe((_) => { + expect(fetchUserPermissions).toHaveBeenCalled(); + }); + }); + + it('should call api to retrieve user permissions if route state has ignoreUserPermissionsFromStore set to true', () => { + const { snapShot, permissions } = setUpPermissionTestData([ + { action: 'view', object: 'case', target: '' } + ] as RolePermission[]); + + fetchUserPermissions.mockReturnValue(of({ permissions })); + + getCurrentNavigation.mockReturnValueOnce({ + extras: { + state: { + ignoreUserPermissionsFromStore: true + } + } + }); + + store.dispatch(setUserPermissions({ permissions })); + + expect.assertions(1); + + guardService.canActivate(snapShot).subscribe((_) => { + expect(fetchUserPermissions).toHaveBeenCalled(); + }); + }); + + it('should redirect to unauthorised page if user has no permissions & route state has ignoreUserPermissionsFromStore set to true', () => { + const { snapShot, permissions } = setUpPermissionTestData(undefined, { + userNoPermissionsRedirectTo: '/unauthorised-page' + }); + + fetchUserPermissions.mockReturnValue(of({ permissions })); + + getCurrentNavigation.mockReturnValueOnce({ + extras: { + state: { + ignoreUserPermissionsFromStore: true + } + } + }); + + expect.assertions(2); + + guardService.canActivate(snapShot).subscribe((canActivate) => { + expect(canActivate).toBe(false); + expect(router.navigateByUrl).toHaveBeenCalledWith('/unauthorised-page'); + }); + }); + + it('should redirect to error page if error occurs while retrieving user permissions & route state has ignoreUserPermissionsFromStore set to true', () => { + const { snapShot } = setUpPermissionTestData([], { + userPermissionsErrorRedirectTo: '/technical-error-page' + }); + + fetchUserPermissions.mockReturnValue(throwError(new HttpErrorResponse({ status: 400 }))); + + getCurrentNavigation.mockReturnValueOnce({ + extras: { + state: { + ignoreUserPermissionsFromStore: true + } + } + }); + + expect.assertions(2); + + guardService.canActivate(snapShot).subscribe((canActivate) => { + expect(canActivate).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/technical-error-page'); + }); + }); + + it('should activate route when user permissions are to be retrieved from API end point', () => { + const { snapShot, permissions } = setUpPermissionTestData([ + { action: 'view', object: 'case', target: '' } + ] as RolePermission[]); + + fetchUserPermissions.mockReturnValue(of({ permissions })); + + expect.assertions(3); + + guardService.canActivate(snapShot).subscribe((canActivate) => { + expect(store.dispatch).toHaveBeenCalledTimes(1); + expect(store.dispatch).toHaveBeenCalledWith(setUserPermissions({ permissions })); + expect(canActivate).toBe(true); + }); + }); + + it('should redirect to unauthorised page if user has no permissions', () => { + const { snapShot, permissions } = setUpPermissionTestData(undefined, { + userNoPermissionsRedirectTo: '/unauthorised-page' + }); + + fetchUserPermissions.mockReturnValue(of({ permissions })); + + expect.assertions(2); + + guardService.canActivate(snapShot).subscribe((canActivate) => { + expect(canActivate).toBe(false); + expect(router.navigateByUrl).toHaveBeenCalledWith('/unauthorised-page'); + }); + }); + + it('should redirect to error page if error except 404 occurs while retrieving user permissions', () => { + const { snapShot } = setUpPermissionTestData([], { + userPermissionsErrorRedirectTo: '/technical-error-page' + }); + + fetchUserPermissions.mockReturnValue(throwError(new HttpErrorResponse({ status: 400 }))); + + expect.assertions(2); + + guardService.canActivate(snapShot).subscribe((canActivate) => { + expect(canActivate).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/technical-error-page'); + }); + }); + + it('should redirect to service unavailable page if 404 error occurs while retrieving user permissions', () => { + const { snapShot } = setUpPermissionTestData([], { + serviceUnavailableRedirectTo: '/service-unavailable-page' + }); + + fetchUserPermissions.mockReturnValue(throwError(new HttpErrorResponse({ status: 404 }))); + + expect.assertions(2); + + guardService.canActivate(snapShot).subscribe((canActivate) => { + expect(canActivate).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/service-unavailable-page'); + }); + }); + + const setUpPermissionTestData = ( + permissions: RolePermission[] | undefined, + redirectRoutes: { + userPermissionsErrorRedirectTo?: string; + userNoPermissionsRedirectTo?: string; + serviceUnavailableRedirectTo?: string; + } = {} + ) => { + const snapShot = new ActivatedRouteSnapshot(); + snapShot.data = { ...redirectRoutes }; + return { snapShot, permissions }; + }; +}); diff --git a/projects/users-groups/src/guards/__tests__/user-service-exists.guard.spec.ts b/projects/users-groups/src/guards/__tests__/user-service-exists.guard.spec.ts new file mode 100644 index 0000000..f24ae7c --- /dev/null +++ b/projects/users-groups/src/guards/__tests__/user-service-exists.guard.spec.ts @@ -0,0 +1,83 @@ +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import * as UsersGroupsActions from '../../actions/users-groups.actions'; +import { usersGroups } from '../../reducers/index'; +import { UserService } from '../../users-groups.interfaces'; +import { UserServiceExistsGuard } from '../user-service-exists.guard'; + +describe('UserServiceExistsGuard', () => { + let guard: UserServiceExistsGuard; + let store: Store; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + navigateByUrl = jest.fn(); + + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot({ usersGroups }, { runtimeChecks: {} })], + providers: [ + UserServiceExistsGuard, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(UserServiceExistsGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + userServiceExistsPredicate: (userServices: UserService[]) => + userServices.some((userService) => userService.containsSearch), + userServiceExistsErrorRedirectTo: '/error-page' + }; + + it('should resolve to true when the predicate matches the user services', () => { + expect.assertions(1); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + + store.dispatch( + UsersGroupsActions.setUserServices({ + userServices: [ + { + name: '*', + containsSearch: true, + features: [] + } + ] + }) + ); + }); + + it('should reject the activation when the predicate does not match the user services', () => { + expect.assertions(2); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(false); + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + }); + + store.dispatch( + UsersGroupsActions.setUserServices({ + userServices: [ + { + name: '*', + containsSearch: false, + features: [] + } + ] + }) + ); + }); +}); diff --git a/projects/users-groups/src/guards/__tests__/user-services.guard.spec.ts b/projects/users-groups/src/guards/__tests__/user-services.guard.spec.ts new file mode 100644 index 0000000..f05ed07 --- /dev/null +++ b/projects/users-groups/src/guards/__tests__/user-services.guard.spec.ts @@ -0,0 +1,119 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; +import { Router, ActivatedRouteSnapshot } from '@angular/router'; +import { Store, StoreModule } from '@ngrx/store'; +import { of, throwError } from 'rxjs'; +import * as UsersGroupsActions from '../../actions/users-groups.actions'; +import { usersGroups } from '../../reducers/index'; +import { UsersGroupsService } from '../../services/users-groups.service'; +import { UserServicesGuard } from '../user-services.guard'; +import { UserService } from '../../users-groups.interfaces'; + +describe('UserServicesGuard', () => { + let guard: UserServicesGuard; + let store: Store; + + let fetchUserServices: jest.Mock; + let navigateByUrl: jest.Mock; + + beforeEach(() => { + navigateByUrl = jest.fn(); + fetchUserServices = jest.fn(); + + TestBed.configureTestingModule({ + imports: [StoreModule.forRoot({ usersGroups }, { runtimeChecks: {} })], + providers: [ + UserServicesGuard, + { + provide: UsersGroupsService, + useValue: { + fetchUserServices + } + }, + { + provide: Router, + useValue: { + navigateByUrl + } + } + ] + }); + + guard = TestBed.inject(UserServicesGuard); + store = TestBed.inject(Store); + + jest.spyOn(store, 'dispatch'); + }); + + const createSnapshot = ({ + userServicesErrorRedirectTo = '', + serviceUnavailableRedirectTo = '' + }: { + userServicesErrorRedirectTo?: string; + serviceUnavailableRedirectTo?: string; + } = {}) => { + const snapshot = new ActivatedRouteSnapshot(); + snapshot.data = { + userServicesErrorRedirectTo, + serviceUnavailableRedirectTo + }; + return snapshot; + }; + + it('should resolve to true when the user services exist in the store', () => { + expect.assertions(1); + + const snapshot = createSnapshot(); + + store.dispatch(UsersGroupsActions.setUserServices({ userServices: [] })); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + }); + }); + + it('should resolve to true after fetching user services from the server when not found in the store', () => { + expect.assertions(2); + + const snapshot = createSnapshot(); + + fetchUserServices.mockReturnValue(of([] as UserService[])); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(didResolve).toBe(true); + expect(store.dispatch).toHaveBeenCalledWith( + UsersGroupsActions.setUserServices({ userServices: [] }) + ); + }); + }); + + it('should reject the activation when there is an error fetching the user services', () => { + expect.assertions(2); + + const error = new HttpErrorResponse({ status: 500 }); + const snapshot = createSnapshot({ userServicesErrorRedirectTo: '/error-page' }); + + fetchUserServices.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(navigateByUrl).toHaveBeenCalledWith('/error-page'); + expect(didResolve).toBe(false); + }); + }); + + it('should reject the activation when there is a 404 error fetching the user services', () => { + expect.assertions(2); + + const error = new HttpErrorResponse({ status: 404 }); + const snapshot = createSnapshot({ + serviceUnavailableRedirectTo: '/service-unavailable-error-page' + }); + + fetchUserServices.mockReturnValue(throwError(error)); + + guard.canActivate(snapshot).subscribe((didResolve) => { + expect(navigateByUrl).toHaveBeenCalledWith('/service-unavailable-error-page'); + expect(didResolve).toBe(false); + }); + }); +}); diff --git a/projects/users-groups/src/guards/permissions/user-permissions-exist.guard.ts b/projects/users-groups/src/guards/permissions/user-permissions-exist.guard.ts new file mode 100644 index 0000000..1b8d4fd --- /dev/null +++ b/projects/users-groups/src/guards/permissions/user-permissions-exist.guard.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Observable } from 'rxjs'; +import { Store, select } from '@ngrx/store'; +import { UsersGroupsState, getUserRolePermissions } from '../../reducers'; +import { map, tap, filter } from 'rxjs/operators'; +import { AggregatedRolePermission } from '../../users-groups.interfaces'; + +export type UserPermissionsExist = (rolePermissions: AggregatedRolePermission[]) => boolean; + +@Injectable() +export class UserPermissionsExistGuard { + constructor(private store: Store, private router: Router) {} + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { userPermissionsExistsPredicate, userPermissionsExistsErrorRedirectTo } = (route.data || + {}) as { + userPermissionsExistsErrorRedirectTo: string; + userPermissionsExistsPredicate: UserPermissionsExist; + }; + + return this.store.pipe( + select(getUserRolePermissions), + filter((rolePermissions): rolePermissions is AggregatedRolePermission[] => !!rolePermissions), + map((rolePermissions) => userPermissionsExistsPredicate(rolePermissions)), + tap((permissionExist) => { + if (!permissionExist && userPermissionsExistsErrorRedirectTo) { + this.router.navigateByUrl(userPermissionsExistsErrorRedirectTo); + } + }) + ); + } +} diff --git a/projects/users-groups/src/guards/permissions/user-permissions.guard.ts b/projects/users-groups/src/guards/permissions/user-permissions.guard.ts new file mode 100644 index 0000000..c7dbc20 --- /dev/null +++ b/projects/users-groups/src/guards/permissions/user-permissions.guard.ts @@ -0,0 +1,110 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Observable, of } from 'rxjs'; +import { Store, select } from '@ngrx/store'; +import { UsersGroupsState, getUserRolePermissions } from '../../reducers'; +import { map, tap, switchMap, catchError, take } from 'rxjs/operators'; +import { UsersGroupsService } from '../../services/users-groups.service'; +import { setUserPermissions } from '../../actions/users-groups.actions'; +import { HttpErrorResponse } from '@angular/common/http'; + +interface RedirectToRoutes { + userPermissionsErrorRedirectTo?: string; + userNoPermissionsRedirectTo?: string; + serviceUnavailableRedirectTo?: string; +} + +@Injectable() +export class UserPermissionsGuard { + constructor( + private store: Store, + private usersGroupsService: UsersGroupsService, + private router: Router + ) {} + + hasUserPermissionsInStore(): Observable { + return this.store.pipe( + select(getUserRolePermissions), + map((rolePermissions) => !!rolePermissions && rolePermissions.length > 0), + take(1) + ); + } + + hasUsersPermissionsInApi(): Observable { + return this.usersGroupsService.fetchUserPermissions().pipe( + tap(({ groups: userGroups, permissions, switchableRoles }) => { + this.store.dispatch(setUserPermissions({ userGroups, permissions, switchableRoles })); + }), + map(({ permissions }) => !!permissions), + take(1) + ); + } + + permissionsErrorRedirectRouteObserver = ({ + userPermissionsErrorRedirectTo, + userNoPermissionsRedirectTo, + serviceUnavailableRedirectTo + }: RedirectToRoutes) => ({ + next: (hasPermissions: boolean) => { + if (!hasPermissions && userNoPermissionsRedirectTo) { + this.router.navigateByUrl(userNoPermissionsRedirectTo); + } + }, + error: ({ status }: HttpErrorResponse) => { + if ((status === 404 || status === 0) && serviceUnavailableRedirectTo) { + this.router.navigateByUrl(serviceUnavailableRedirectTo); + return; + } + + if (userPermissionsErrorRedirectTo) { + this.router.navigateByUrl(userPermissionsErrorRedirectTo); + } + } + }); + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { + userPermissionsErrorRedirectTo, + userNoPermissionsRedirectTo, + serviceUnavailableRedirectTo + } = (route.data || {}) as { + userPermissionsErrorRedirectTo?: string; + userNoPermissionsRedirectTo?: string; + serviceUnavailableRedirectTo?: string; + }; + + const routerCurrentNavigation = this.router.getCurrentNavigation(); + const { ignoreUserPermissionsFromStore } = ((!!routerCurrentNavigation && + routerCurrentNavigation.extras.state) || + {}) as { + ignoreUserPermissionsFromStore: boolean; + }; + + if (ignoreUserPermissionsFromStore) { + return this.hasUsersPermissionsInApi().pipe( + tap( + this.permissionsErrorRedirectRouteObserver({ + userPermissionsErrorRedirectTo, + userNoPermissionsRedirectTo, + serviceUnavailableRedirectTo + }) + ), + catchError(() => of(false)) + ); + } + + return this.hasUserPermissionsInStore().pipe( + switchMap((hasPermissions) => + hasPermissions ? of(hasPermissions) : this.hasUsersPermissionsInApi() + ), + tap( + this.permissionsErrorRedirectRouteObserver({ + userPermissionsErrorRedirectTo, + userNoPermissionsRedirectTo, + serviceUnavailableRedirectTo + }) + ), + catchError(() => of(false)) + ); + } +} diff --git a/projects/users-groups/src/guards/user-details.guard.ts b/projects/users-groups/src/guards/user-details.guard.ts new file mode 100644 index 0000000..bfec296 --- /dev/null +++ b/projects/users-groups/src/guards/user-details.guard.ts @@ -0,0 +1,65 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { select, Store } from '@ngrx/store'; +import { DynatraceService } from '@cpp/core'; +import { of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, switchMapTo, take, tap } from 'rxjs/operators'; +import { setUserDetails } from '../actions/users-groups.actions'; +import { getUserDetails, UsersGroupsState } from '../reducers/index'; +import { UsersGroupsService } from '../services/users-groups.service'; +import { HttpErrorResponse } from '@angular/common/http'; + +@Injectable() +export class UserDetailsGuard { + constructor( + private store: Store, + private router: Router, + private usersGroups: UsersGroupsService, + private dynatraceService: DynatraceService + ) {} + + hasUserDetailsInStore() { + return this.store.pipe(select(getUserDetails), map(Boolean), take(1)); + } + + hasUserDetailsInApi() { + return this.usersGroups.fetchLoggedInUserDetails().pipe( + tap((userDetails) => { + this.dynatraceService.trackUserName(userDetails.email); + return this.store.next(setUserDetails({ userDetails })); + }), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot) { + const { userDetailsErrorRedirectTo, serviceUnavailableRedirectTo } = route.data as { + userDetailsErrorRedirectTo?: string; + serviceUnavailableRedirectTo?: string; + }; + + return this.hasUserDetailsInStore().pipe( + switchMap((inStore) => { + if (inStore) { + return of(null); + } + return this.hasUserDetailsInApi(); + }), + switchMapTo(this.store), + mapTo(true), + tap({ + error: ({ status }: HttpErrorResponse) => { + if ((status === 404 || status === 0) && serviceUnavailableRedirectTo) { + this.router.navigateByUrl(serviceUnavailableRedirectTo); + return; + } + + if (userDetailsErrorRedirectTo) { + this.router.navigateByUrl(userDetailsErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/users-groups/src/guards/user-feature-exist.guard.ts b/projects/users-groups/src/guards/user-feature-exist.guard.ts new file mode 100644 index 0000000..0efc172 --- /dev/null +++ b/projects/users-groups/src/guards/user-feature-exist.guard.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { select, Store } from '@ngrx/store'; +import { filter, map, take, tap } from 'rxjs/operators'; +import { getUserFeatures, UsersGroupsState } from '../reducers/index'; +import { UserServiceFeature } from '../users-groups.interfaces'; + +@Injectable() +export class UserFeatureExistsGuard { + constructor(private store: Store, private router: Router) {} + + canActivate(route: ActivatedRouteSnapshot) { + const { userFeatureExistsErrorRedirectTo, userFeatureExistsPredicate } = route.data as { + userFeatureExistsPredicate: (userFeatures: UserServiceFeature[]) => boolean; + userFeatureExistsErrorRedirectTo?: string; + }; + + return this.store.pipe( + select(getUserFeatures), + filter((userFeatures): userFeatures is UserServiceFeature[] => !!userFeatures), + take(1), + map((userFeatures) => userFeatureExistsPredicate(userFeatures)), + tap((valid) => { + if (!valid && userFeatureExistsErrorRedirectTo) { + this.router.navigateByUrl(userFeatureExistsErrorRedirectTo); + } + }) + ); + } +} diff --git a/projects/users-groups/src/guards/user-features.guard.ts b/projects/users-groups/src/guards/user-features.guard.ts new file mode 100644 index 0000000..a6be499 --- /dev/null +++ b/projects/users-groups/src/guards/user-features.guard.ts @@ -0,0 +1,63 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { select, Store } from '@ngrx/store'; +import { of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { setUserFeaturesSuccess } from '../actions/users-groups.actions'; +import { getUserFeatures, UsersGroupsState } from '../reducers/index'; +import { UsersGroupsService } from '../services/users-groups.service'; + +@Injectable() +export class UserFeaturesGuard { + constructor( + private store: Store, + private router: Router, + private usersGroupsService: UsersGroupsService + ) {} + + hasUserFeaturesInStore() { + return this.store.pipe( + select(getUserFeatures), + map((features) => !!features), + take(1) + ); + } + + hasUserFeaturesInApi() { + return this.usersGroupsService.fetchUserFeatures().pipe( + tap((userFeatures) => this.store.next(setUserFeaturesSuccess({ userFeatures }))), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot) { + const { userFeaturesErrorRedirectTo, serviceUnavailableRedirectTo } = route.data as { + userFeaturesErrorRedirectTo?: string; + serviceUnavailableRedirectTo?: string; + }; + + return this.hasUserFeaturesInStore().pipe( + switchMap((inStore) => { + if (inStore) { + return of(null); + } + return this.hasUserFeaturesInApi(); + }), + mapTo(true), + tap({ + error: ({ status }: HttpErrorResponse) => { + if ((status === 404 || status === 0) && serviceUnavailableRedirectTo) { + this.router.navigateByUrl(serviceUnavailableRedirectTo); + return; + } + + if (userFeaturesErrorRedirectTo) { + this.router.navigateByUrl(userFeaturesErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/users-groups/src/guards/user-groups-with-organisation.guard.ts b/projects/users-groups/src/guards/user-groups-with-organisation.guard.ts new file mode 100644 index 0000000..7cc5663 --- /dev/null +++ b/projects/users-groups/src/guards/user-groups-with-organisation.guard.ts @@ -0,0 +1,52 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { select, Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { setGroupsWithOrganisation } from '../actions/users-groups.actions'; +import { getGroupsWithOrganisation, UsersGroupsState } from '../reducers/index'; +import { UsersGroupsService } from '../services/users-groups.service'; + +@Injectable() +export class UserGroupsWithOrganisationGuard { + constructor( + private store: Store, + private router: Router, + private usersGroups: UsersGroupsService + ) {} + + hasGroupsWithOrganisationsInStore() { + return this.store.pipe( + select(getGroupsWithOrganisation), + map( + (groupsWithOrganisation) => !!groupsWithOrganisation && groupsWithOrganisation.length > 0 + ), + take(1) + ); + } + + hasGroupsWithOrganisationsInApi() { + return this.usersGroups.fetchGroupsWithOrganisation().pipe( + tap((groupsWithOrganisation) => + this.store.next(setGroupsWithOrganisation({ groupsWithOrganisation })) + ), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { groupsWithOrganisationsErrorRedirectTo } = route.data as { + groupsWithOrganisationsErrorRedirectTo?: string; + }; + + return this.hasGroupsWithOrganisationsInStore().pipe( + switchMap((data) => (data ? of(data) : this.hasGroupsWithOrganisationsInApi())), + tap({ + error: () => + groupsWithOrganisationsErrorRedirectTo && + this.router.navigateByUrl(groupsWithOrganisationsErrorRedirectTo) + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/users-groups/src/guards/user-groups.guard.ts b/projects/users-groups/src/guards/user-groups.guard.ts new file mode 100644 index 0000000..4ac2a52 --- /dev/null +++ b/projects/users-groups/src/guards/user-groups.guard.ts @@ -0,0 +1,69 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { DynatraceService } from '@cpp/core'; +import { select, Store } from '@ngrx/store'; +import { of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, switchMapTo, take, tap } from 'rxjs/operators'; +import { setUserGroups } from '../actions/users-groups.actions'; +import { getUserGroups, UsersGroupsState } from '../reducers/index'; +import { UsersGroupsService } from '../services/users-groups.service'; + +@Injectable() +export class UserGroupsGuard { + constructor( + private store: Store, + private router: Router, + private usersGroups: UsersGroupsService, + private dynatraceService: DynatraceService + ) {} + + hasUserGroupsInStore() { + return this.store.pipe( + select(getUserGroups), + map((groups) => !!groups), + take(1) + ); + } + + hasUserGroupsInApi() { + return this.usersGroups.fetchUserGroups().pipe( + tap((userGroups) => { + const groupNames = (userGroups || []).map((group) => group.groupName); + this.dynatraceService.trackUserGroups(groupNames); + return this.store.next(setUserGroups({ userGroups })); + }), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot) { + const { userGroupsErrorRedirectTo, serviceUnavailableRedirectTo } = route.data as { + userGroupsErrorRedirectTo?: string; + serviceUnavailableRedirectTo?: string; + }; + + return this.hasUserGroupsInStore().pipe( + switchMap((inStore) => { + if (inStore) { + return of(null); + } + return this.hasUserGroupsInApi(); + }), + switchMapTo(this.store), + mapTo(true), + tap({ + error: ({ status }: HttpErrorResponse) => { + if ((status === 404 || status === 0) && serviceUnavailableRedirectTo) { + this.router.navigateByUrl(serviceUnavailableRedirectTo); + return; + } + if (userGroupsErrorRedirectTo) { + this.router.navigateByUrl(userGroupsErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/users-groups/src/guards/user-organisations.guard.ts b/projects/users-groups/src/guards/user-organisations.guard.ts new file mode 100644 index 0000000..b546bcb --- /dev/null +++ b/projects/users-groups/src/guards/user-organisations.guard.ts @@ -0,0 +1,48 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { select, Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, take, tap } from 'rxjs/operators'; +import { setUserOrganisations } from '../actions/users-groups.actions'; +import { getUserOrganisations, UsersGroupsState } from '../reducers/index'; +import { UsersGroupsService } from '../services/users-groups.service'; + +@Injectable() +export class UserOrganisationsGuard { + constructor( + private store: Store, + private router: Router, + private usersGroups: UsersGroupsService + ) {} + + hasUserOrganisationsInStore() { + return this.store.pipe( + select(getUserOrganisations), + map((organisations) => !!organisations && organisations.length > 0), + take(1) + ); + } + + hasUserOrganisationsInApi() { + return this.usersGroups.fetchOrganisations().pipe( + tap((organisations) => this.store.next(setUserOrganisations({ organisations }))), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot): Observable { + const { userOrganisationsErrorRedirectTo } = route.data as { + userOrganisationsErrorRedirectTo?: string; + }; + + return this.hasUserOrganisationsInStore().pipe( + switchMap((data) => (data ? of(data) : this.hasUserOrganisationsInApi())), + tap({ + error: () => + userOrganisationsErrorRedirectTo && + this.router.navigateByUrl(userOrganisationsErrorRedirectTo) + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/users-groups/src/guards/user-roles.guard.ts b/projects/users-groups/src/guards/user-roles.guard.ts new file mode 100644 index 0000000..ca8188d --- /dev/null +++ b/projects/users-groups/src/guards/user-roles.guard.ts @@ -0,0 +1,65 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { select, Store } from '@ngrx/store'; +import { of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, switchMapTo, take, tap } from 'rxjs/operators'; +import { setUserRoles } from '../actions/users-groups.actions'; +import { getUserRoles, UsersGroupsState } from '../reducers/index'; +import { UsersGroupsService } from '../services/users-groups.service'; + +@Injectable() +export class UserRolesGuard { + constructor( + private store: Store, + private router: Router, + private usersGroups: UsersGroupsService + ) {} + + hasUserRolesInStore() { + return this.store.pipe( + select(getUserRoles), + map((groups) => !!groups), + take(1) + ); + } + + hasUserRolesInApi() { + return this.usersGroups + .fetchUserSelectedRoles() + .pipe( + tap(({ allRoles }) => this.store.next(setUserRoles({ userRoles: allRoles })), mapTo(true)) + ); + } + + canActivate(route: ActivatedRouteSnapshot) { + const { userRolesErrorRedirectTo, serviceUnavailableRedirectTo } = route.data as { + userRolesErrorRedirectTo?: string; + serviceUnavailableRedirectTo?: string; + }; + + return this.hasUserRolesInStore().pipe( + switchMap((inStore) => { + if (inStore) { + return of(null); + } + return this.hasUserRolesInApi(); + }), + switchMapTo(this.store), + mapTo(true), + tap({ + error: ({ status }: HttpErrorResponse) => { + if ((status === 404 || status === 0) && serviceUnavailableRedirectTo) { + this.router.navigateByUrl(serviceUnavailableRedirectTo); + return; + } + + if (userRolesErrorRedirectTo) { + this.router.navigateByUrl(userRolesErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/users-groups/src/guards/user-service-exists.guard.ts b/projects/users-groups/src/guards/user-service-exists.guard.ts new file mode 100644 index 0000000..15fb3b5 --- /dev/null +++ b/projects/users-groups/src/guards/user-service-exists.guard.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { select, Store } from '@ngrx/store'; +import { filter, map, take, tap } from 'rxjs/operators'; +import { getUserServices, UsersGroupsState } from '../reducers/index'; +import { UserService } from '../users-groups.interfaces'; + +@Injectable() +export class UserServiceExistsGuard { + constructor(private store: Store, private router: Router) {} + + canActivate(route: ActivatedRouteSnapshot) { + const { userServiceExistsErrorRedirectTo, userServiceExistsPredicate } = route.data as { + userServiceExistsPredicate: (userServices: UserService[]) => boolean; + userServiceExistsErrorRedirectTo?: string; + }; + + return this.store.pipe( + select(getUserServices), + filter((userServices) => !!userServices), + take(1), + map((userServices) => userServiceExistsPredicate(userServices!)), + tap((valid) => { + if (!valid && userServiceExistsErrorRedirectTo) { + this.router.navigateByUrl(userServiceExistsErrorRedirectTo); + } + }) + ); + } +} diff --git a/projects/users-groups/src/guards/user-services.guard.ts b/projects/users-groups/src/guards/user-services.guard.ts new file mode 100644 index 0000000..88a19a5 --- /dev/null +++ b/projects/users-groups/src/guards/user-services.guard.ts @@ -0,0 +1,64 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { select, Store } from '@ngrx/store'; +import { of } from 'rxjs'; +import { catchError, map, mapTo, switchMap, switchMapTo, take, tap } from 'rxjs/operators'; +import { setUserServices } from '../actions/users-groups.actions'; +import { getUserServices, UsersGroupsState } from '../reducers/index'; +import { UsersGroupsService } from '../services/users-groups.service'; + +@Injectable() +export class UserServicesGuard { + constructor( + private store: Store, + private router: Router, + private usersGroups: UsersGroupsService + ) {} + + hasUserServicesInStore() { + return this.store.pipe( + select(getUserServices), + map((services) => !!services), + take(1) + ); + } + + hasUserServicesInApi() { + return this.usersGroups.fetchUserServices().pipe( + tap((userServices) => this.store.next(setUserServices({ userServices }))), + mapTo(true) + ); + } + + canActivate(route: ActivatedRouteSnapshot) { + const { userServicesErrorRedirectTo, serviceUnavailableRedirectTo } = route.data as { + userServicesErrorRedirectTo?: string; + serviceUnavailableRedirectTo?: string; + }; + + return this.hasUserServicesInStore().pipe( + switchMap((inStore) => { + if (inStore) { + return of(null); + } + return this.hasUserServicesInApi(); + }), + switchMapTo(this.store), + mapTo(true), + tap({ + error: ({ status }: HttpErrorResponse) => { + if ((status === 404 || status === 0) && serviceUnavailableRedirectTo) { + this.router.navigateByUrl(serviceUnavailableRedirectTo); + return; + } + + if (userServicesErrorRedirectTo) { + this.router.navigateByUrl(userServicesErrorRedirectTo); + } + } + }), + catchError(() => of(false)) + ); + } +} diff --git a/projects/users-groups/src/index.ts b/projects/users-groups/src/index.ts new file mode 100644 index 0000000..4aaf8f9 --- /dev/null +++ b/projects/users-groups/src/index.ts @@ -0,0 +1 @@ +export * from './public_api'; diff --git a/projects/users-groups/src/permissions/directives/__tests__/__snapshots__/cpp-user-has-permission.directive.spec.ts.snap b/projects/users-groups/src/permissions/directives/__tests__/__snapshots__/cpp-user-has-permission.directive.spec.ts.snap new file mode 100644 index 0000000..37f8590 --- /dev/null +++ b/projects/users-groups/src/permissions/directives/__tests__/__snapshots__/cpp-user-has-permission.directive.spec.ts.snap @@ -0,0 +1,108 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CppUserHasPermissionDirective Given *cppUserHasPermission is used, and source attribute is provided, when user does not have source attribute access in existing permissions, it should not render view 1`] = ` + + +`; + +exports[`CppUserHasPermissionDirective Given *cppUserHasPermission is used, and source attribute is provided, when user has source attribute access in existing permissions, it should render view 1`] = ` + +
+ This is displayed ONLY if user has the specified SOURCE attribute as part of expected user permission. +
+
+`; + +exports[`CppUserHasPermissionDirective Given *cppUserHasPermission is used, and target attribute is provided, when user does not have target attribute access in existing permissions, it should not render view 1`] = ` + + +`; + +exports[`CppUserHasPermissionDirective Given *cppUserHasPermission is used, and target attribute is provided, when user has target attribute access in existing permissions, it should render view 1`] = ` + +
+ This is displayed ONLY if user has the specified target attribute as part of expected user permission. +
+
+`; + +exports[`CppUserHasPermissionDirective Given *cppUserHasPermission is used, should not render expected view if cpp User does not have permissions 1`] = ` + + +`; + +exports[`CppUserHasPermissionDirective Given *cppUserHasPermission is used, should render expected view if cpp User has permissions 1`] = ` + +
+ This is displayed ONLY if user has permissions. +
+
+`; + +exports[`CppUserHasPermissionDirective Given *cppUserHasPermission is used, when user is required not to have expected permissions, it should render view 1`] = ` + +
+ This is displayed ONLY if user is REQUIRED NOT TO HAVE expected user permission. +
+
+`; + +exports[`CppUserHasPermissionDirective Given *cppUserHasPermission is used, when user is required to have expected permissions, it should render view 1`] = ` + +
+ This is displayed ONLY if user is REQUIRED to have expected user permission. +
+
+`; + +exports[`CppUserHasPermissionDirective Given *cppUserHasPermission is used, when user is required to have some of the permissions, it should render view 1`] = ` + +
+ This is displayed ONLY if user is has SOME of the expected user permissions. +
+
+`; + +exports[`CppUserHasPermissionDirective should render 1`] = ` + +
+ This is displayed without directive. +
+
+`; diff --git a/projects/users-groups/src/permissions/directives/__tests__/cpp-user-has-permission.directive.spec.ts b/projects/users-groups/src/permissions/directives/__tests__/cpp-user-has-permission.directive.spec.ts new file mode 100644 index 0000000..a367703 --- /dev/null +++ b/projects/users-groups/src/permissions/directives/__tests__/cpp-user-has-permission.directive.spec.ts @@ -0,0 +1,230 @@ +import { CppUserHasPermissionDirective } from '../cpp-user-has-permission.directive'; +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { StoreModule, Store } from '@ngrx/store'; +import { usersGroups, UsersGroupsState } from '../../../reducers'; +import { RolePermission } from '../../../users-groups.interfaces'; +import { setUserPermissions } from '../../../actions/users-groups.actions'; +import { Component } from '@angular/core'; + +describe('CppUserHasPermissionDirective', () => { + let permissions: RolePermission[]; + let store: Store; + let fixture: ComponentFixture; + let component: CppUserHasPermissionsTestComponent; + let expectedPermission: RolePermission | RolePermission[]; + + beforeEach(async () => { + TestBed.configureTestingModule({ + declarations: [CppUserHasPermissionsTestComponent], + imports: [ + StoreModule.forRoot({ usersGroups }, { runtimeChecks: {} }), + CppUserHasPermissionDirective + ] + }); + + permissions = [ + { + action: 'view', + object: 'case', + target: 'target 235', + source: 'source a', + permissionId: 'permission-1' + }, + { + action: 'view', + object: 'case', + target: 'target 123', + source: 'source a', + permissionId: 'permission-2' + }, + { action: 'view', object: 'case', target: '', permissionId: 'permission-3' } + ] as RolePermission[]; + }); + + const setUpFixture = (template: string) => { + TestBed.overrideTemplate(CppUserHasPermissionsTestComponent, template).compileComponents(); + fixture = TestBed.createComponent(CppUserHasPermissionsTestComponent); + component = fixture.componentInstance; + }; + + const setUpTestData = ( + expectedPermissions: RolePermission | RolePermission[], + providedTarget?: string, + providedSource?: string + ) => { + store = TestBed.inject(Store); + store.dispatch(setUserPermissions({ permissions })); + component.expectedPermission = expectedPermissions; + component.providedTarget = providedTarget; + component.providedSource = providedSource; + }; + + it('should render', () => { + const template = `
This is displayed without directive.
`; + setUpFixture(template); + expect(fixture).toMatchSnapshot(); + }); + + describe('Given *cppUserHasPermission is used, ', () => { + it('should render expected view if cpp User has permissions', () => { + expect.assertions(1); + + expectedPermission = { action: 'view', object: 'case' } as RolePermission; + const template = `
+ This is displayed ONLY if user has permissions. +
`; + + setUpFixture(template); + setUpTestData(expectedPermission); + fixture.detectChanges(); + + expect(fixture).toMatchSnapshot(); + }); + + it('should not render expected view if cpp User does not have permissions', () => { + expect.assertions(1); + + expectedPermission = { action: 'view', object: 'hearing' } as RolePermission; + const template = `
+ This is displayed ONLY if user has permissions. +
`; + + setUpFixture(template); + setUpTestData(expectedPermission); + fixture.detectChanges(); + + expect(fixture).toMatchSnapshot(); + }); + + describe('and target attribute is provided, ', () => { + beforeEach(() => { + const template = `
+ This is displayed ONLY if user has the specified target attribute as part of expected user permission. +
`; + setUpFixture(template); + expectedPermission = { + action: 'view', + object: 'case', + source: 'source a' + } as RolePermission; + }); + + it('when user has target attribute access in existing permissions, it should render view', () => { + expect.assertions(1); + + setUpTestData(expectedPermission, 'target 235'); + fixture.detectChanges(); + + expect(fixture).toMatchSnapshot(); + }); + + it('when user does not have target attribute access in existing permissions, it should not render view', () => { + expect.assertions(1); + + setUpTestData(expectedPermission, 'target 444'); + fixture.detectChanges(); + + expect(fixture).toMatchSnapshot(); + }); + }); + + describe('and source attribute is provided, ', () => { + beforeEach(() => { + const template = `
+ This is displayed ONLY if user has the specified SOURCE attribute as part of expected user permission. +
`; + setUpFixture(template); + expectedPermission = { action: 'view', object: 'case' } as RolePermission; + }); + + it('when user has source attribute access in existing permissions, it should render view', () => { + expect.assertions(1); + + setUpTestData(expectedPermission, 'target 123', 'source a'); + fixture.detectChanges(); + + expect(fixture).toMatchSnapshot(); + }); + + it('when user does not have source attribute access in existing permissions, it should not render view', () => { + expect.assertions(1); + + setUpTestData(expectedPermission, undefined, 'source a'); + fixture.detectChanges(); + + expect(fixture).toMatchSnapshot(); + }); + }); + + describe('when user is required to have expected permissions, ', () => { + beforeEach(() => { + const template = `
+ This is displayed ONLY if user is REQUIRED to have expected user permission. +
`; + setUpFixture(template); + expectedPermission = { action: 'view', object: 'case' } as RolePermission; + }); + + it('it should render view', () => { + expect.assertions(1); + + setUpTestData(expectedPermission, 'target 123', 'source a'); + fixture.detectChanges(); + + expect(fixture).toMatchSnapshot(); + }); + }); + + describe('when user is required not to have expected permissions, ', () => { + beforeEach(() => { + const template = `
+ This is displayed ONLY if user is REQUIRED NOT TO HAVE expected user permission. +
`; + setUpFixture(template); + expectedPermission = { action: 'view', object: 'case' } as RolePermission; + }); + + it('it should render view', () => { + expect.assertions(1); + + setUpTestData(expectedPermission, 'target 444', 'source a'); + fixture.detectChanges(); + + expect(fixture).toMatchSnapshot(); + }); + }); + + describe('when user is required to have some of the permissions, ', () => { + beforeEach(() => { + const template = `
+ This is displayed ONLY if user is has SOME of the expected user permissions. +
`; + setUpFixture(template); + expectedPermission = [ + { action: 'view', object: 'case', target: 'target 444', source: 'source a' }, + { action: 'view', object: 'case', target: 'target 123', source: 'source a' } + ] as RolePermission[]; + }); + + it('it should render view', () => { + expect.assertions(1); + + setUpTestData(expectedPermission); + fixture.detectChanges(); + + expect(fixture).toMatchSnapshot(); + }); + }); + }); +}); + +@Component({ + selector: 'cpp-user-has-permissions-test', + template: ``, + standalone: false +}) +export class CppUserHasPermissionsTestComponent { + expectedPermission: any; + providedTarget: any; + providedSource: any; +} diff --git a/projects/users-groups/src/permissions/directives/cpp-user-has-permission.directive.ts b/projects/users-groups/src/permissions/directives/cpp-user-has-permission.directive.ts new file mode 100644 index 0000000..13e469a --- /dev/null +++ b/projects/users-groups/src/permissions/directives/cpp-user-has-permission.directive.ts @@ -0,0 +1,109 @@ +import { Directive, TemplateRef, Input, ViewContainerRef, OnDestroy, OnInit } from '@angular/core'; +import { AggregatedRolePermission } from '../../users-groups.interfaces'; +import { Store, select } from '@ngrx/store'; +import { UsersGroupsState, getUserRolePermissions } from '../../reducers'; +import { Subscription } from 'rxjs'; +import { permissionsExist, PermissionOperator, RequiredPermission } from '../../utils'; + +export interface HasPermissionContext { + $implicit: RequiredPermission[]; + cppUserHasPermission?: boolean; +} + +/** + * CppUserHasPermissionDirective should be used (preferably with syntactic sugar) as a structural + * directive to check if user has permissions to access any resource. + */ +@Directive({ selector: '[cppUserHasPermission]' }) +export class CppUserHasPermissionDirective implements OnInit, OnDestroy { + private context: HasPermissionContext = {} as HasPermissionContext; + private templateRef: TemplateRef | undefined; + private permissionsInStore: AggregatedRolePermission[] | undefined; + private subscription: Subscription | undefined; + private _target: string | undefined; + private _source: string | undefined; + private _required = true; + private _operation: PermissionOperator = PermissionOperator.and; + + @Input() + set cppUserHasPermission(value: RequiredPermission | RequiredPermission[]) { + value = (value instanceof Array ? value : [value]) as RequiredPermission[]; + this.context.$implicit = value; + this.updateView(); + } + + @Input() + set cppUserHasPermissionTarget(target: string) { + this._target = target; + this.updateView(); + } + + @Input() + set cppUserHasPermissionSource(source: string) { + this._source = source; + this.updateView(); + } + + @Input() + set cppUserHasPermissionRequired(required: boolean) { + this._required = required; + this.updateView(); + } + + @Input() + set cppUserHasPermissionOperation(operator: PermissionOperator) { + this._operation = operator; + this.updateView(); + } + + constructor( + private viewContainerRef: ViewContainerRef, + templateRef: TemplateRef, + private store: Store + ) { + this.templateRef = templateRef; + } + + ngOnInit() { + this.subscription = this.store.pipe(select(getUserRolePermissions)).subscribe((permissions) => { + this.permissionsInStore = permissions; + this.updateView(); + }); + } + + updateView() { + this.viewContainerRef.clear(); + this.displayRequiredView(); + } + + displayRequiredView() { + if (this.verifyPermissions()) { + return ( + this.templateRef && this.viewContainerRef.createEmbeddedView(this.templateRef, this.context) + ); + } + } + + verifyPermissions(): boolean { + const requiredPermissions = this.context.$implicit; + if (this.permissionsInStore) { + this.context.cppUserHasPermission = permissionsExist( + this.permissionsInStore, + requiredPermissions, + this._operation, + this._target, + this._source + ); + return this._required + ? this.context.cppUserHasPermission + : !this.context.cppUserHasPermission; + } + return false; + } + + ngOnDestroy() { + if (this.subscription) { + this.subscription.unsubscribe(); + } + } +} diff --git a/projects/users-groups/src/providers.ts b/projects/users-groups/src/providers.ts new file mode 100644 index 0000000..19a7a7e --- /dev/null +++ b/projects/users-groups/src/providers.ts @@ -0,0 +1,36 @@ +import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'; +import { provideState } from '@ngrx/store'; +import { usersGroups } from './reducers'; +import { UserDetailsGuard } from './guards/user-details.guard'; +import { UserGroupsGuard } from './guards/user-groups.guard'; +import { UserRolesGuard } from './guards/user-roles.guard'; +import { UserServiceExistsGuard } from './guards/user-service-exists.guard'; +import { UserServicesGuard } from './guards/user-services.guard'; +import { UserOrganisationsGuard } from './guards/user-organisations.guard'; +import { UserGroupsWithOrganisationGuard } from './guards/user-groups-with-organisation.guard'; +import { UsersGroupsService } from './services/users-groups.service'; +import { UserFeaturesGuard } from './guards/user-features.guard'; +import { SystemAnnouncementsService } from './services/system-announcements.service'; +import { UserPermissionsGuard } from './guards/permissions/user-permissions.guard'; +import { UserPermissionsExistGuard } from './guards/permissions/user-permissions-exist.guard'; + +export const provideUsersGroupsStore = (): EnvironmentProviders => { + return provideState({ name: 'usersGroups', reducer: usersGroups }); +}; +export const provideUserGroupsEnvironmentContext = (): EnvironmentProviders => { + return makeEnvironmentProviders([ + provideUsersGroupsStore(), + UserDetailsGuard, + UserGroupsGuard, + UserRolesGuard, + UserServiceExistsGuard, + UserServicesGuard, + UserOrganisationsGuard, + UserGroupsWithOrganisationGuard, + UsersGroupsService, + UserFeaturesGuard, + SystemAnnouncementsService, + UserPermissionsGuard, + UserPermissionsExistGuard + ]); +}; diff --git a/projects/users-groups/src/public_api.ts b/projects/users-groups/src/public_api.ts new file mode 100644 index 0000000..6db511a --- /dev/null +++ b/projects/users-groups/src/public_api.ts @@ -0,0 +1,24 @@ +/* + * Public API Surface of users-groups + */ + +export * from './actions/index'; +export * from './reducers/index'; +export * from './guards/user-details.guard'; +export * from './guards/user-groups.guard'; +export * from './guards/user-roles.guard'; +export * from './guards/user-service-exists.guard'; +export * from './guards/user-services.guard'; +export * from './guards/user-organisations.guard'; +export * from './guards/user-groups-with-organisation.guard'; +export * from './guards/user-features.guard'; +export * from './guards/permissions/user-permissions.guard'; +export * from './guards/permissions/user-permissions-exist.guard'; +export * from './services/users-groups.service'; +export * from './services/system-announcements.service'; +export * from './users-groups.interfaces'; +export * from './users-groups.module'; +export * from './utils/index'; +export * from './permissions/directives/cpp-user-has-permission.directive'; +export * from './features/directives/cpp-user-has-feature-enabled.directive'; +export * from './providers'; diff --git a/projects/users-groups/src/reducers/__tests__/__snapshots__/index.spec.ts.snap b/projects/users-groups/src/reducers/__tests__/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000..de24ac0 --- /dev/null +++ b/projects/users-groups/src/reducers/__tests__/__snapshots__/index.spec.ts.snap @@ -0,0 +1,204 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`usersGroupsReducer UsersGroupsActions.setGroupsWithOrganisation should set the groups with organisation 1`] = ` +{ + "groupsWithOrganisation": [ + { + "category": "speciality", + "description": "Transport for London", + "documentsReferenceDataGroup": "Probation Admin", + "groupId": "d231b119-d748-46da-89fc-293edf114e1", + "groupName": "SJP Prosecutors", + "organisationId": "6127a06c-c67b-4972-8b47-ba7b22c0eb10", + "resultsReferenceDataGroup": "Probation", + "roleIds": [], + }, + ], + "permissionsMap": {}, +} +`; + +exports[`usersGroupsReducer UsersGroupsActions.setUserDetails should set the user details 1`] = ` +{ + "permissionsMap": {}, + "userDetails": { + "email": "james@gray.org", + "firstName": "James", + "lastName": "Gray", + "prosecutingAuthorityAccess": "TFL", + "userId": "*", + }, +} +`; + +exports[`usersGroupsReducer UsersGroupsActions.setUserDetails should set the user roles 1`] = ` +{ + "permissionsMap": {}, + "userRoles": [ + { + "roleId": "test-user-role-id", + }, + ], +} +`; + +exports[`usersGroupsReducer UsersGroupsActions.setUserOrganisations should set the organisations 1`] = ` +{ + "organisations": [ + { + "organisationId": "test-organisation-id", + "organisationName": "test-organisation-name", + "organisationType": "test-organisation-type", + }, + ], + "permissionsMap": {}, +} +`; + +exports[`usersGroupsReducer UsersGroupsActions.setUserPermissions should set user permissions 1`] = ` +{ + "permissionsMap": { + "permission-id-1": { + "action": "test", + "description": "*", + "object": "permission", + "permissionId": "permission-id-1", + "target": "target-01", + }, + "permission-id-2": { + "action": "test", + "description": "*", + "object": "permission", + "permissionId": "permission-id-2", + "target": "target-02", + }, + "permission-id-3": { + "action": "test", + "description": "*", + "object": "permission", + "permissionId": "permission-id-3", + }, + }, + "switchableRoles": undefined, + "userGroups": [], +} +`; + +exports[`usersGroupsReducer UsersGroupsActions.setUserServices should set user services 1`] = ` +{ + "permissionsMap": {}, + "userServices": [ + { + "containsSearch": true, + "features": [], + "name": "*", + }, + ], +} +`; + +exports[`usersGroupsReducer selectors Permissions getAllUserRolePermissionIds should return permission ids for user 1`] = ` +[ + "permission-id", +] +`; + +exports[`usersGroupsReducer selectors Permissions getUserRolePermissions should return aggregated permissions for user 1`] = ` +[ + { + "action": "test", + "description": "*", + "object": "permission", + }, +] +`; + +exports[`usersGroupsReducer selectors Permissions getUserRolePermissionsMap should return permissions map from permissions 1`] = ` +{ + "permission-id": { + "action": "test", + "description": "*", + "object": "permission", + "permissionId": "permission-id", + }, +} +`; + +exports[`usersGroupsReducer selectors getAllUserPlacements should select the all the placements of all the roles 1`] = ` +[ + { + "placementId": "test-role-1-placement-id-1", + }, + { + "placementId": "test-role-1-placement-id-2", + }, + { + "placementId": "test-role-2-placement-id-1", + }, + { + "placementId": "test-role-2-placement-id-2", + }, +] +`; + +exports[`usersGroupsReducer selectors getGroupsWithOrganisation should select the groups with organisation 1`] = ` +[ + { + "category": "speciality", + "description": "Transport for London", + "documentsReferenceDataGroup": "Probation Admin", + "groupId": "d231b119-d748-46da-89fc-293edf114e1", + "groupName": "SJP Prosecutors", + "organisationId": "6127a06c-c67b-4972-8b47-ba7b22c0eb10", + "resultsReferenceDataGroup": "Probation", + "roleIds": [ + "test-role-id", + ], + }, +] +`; + +exports[`usersGroupsReducer selectors getUserDetails should select the user details 1`] = ` +{ + "email": "james@gray.org", + "firstName": "James", + "lastName": "Gray", + "prosecutingAuthorityAccess": "TFL", + "userId": "*", +} +`; + +exports[`usersGroupsReducer selectors getUserOrganisations should select the organisations 1`] = ` +[ + { + "organisationId": "test-organisation-id", + "organisationName": "test-organisation-name", + "organisationType": "test-organisation-type", + }, +] +`; + +exports[`usersGroupsReducer selectors getUserRoles should select the user roles 1`] = ` +[ + { + "description": "test-user-role-description", + "roleId": "test-user-role-id", + }, +] +`; + +exports[`usersGroupsReducer selectors getUserServices should select the user services 1`] = ` +[ + { + "containsSearch": true, + "features": [], + "name": "*", + }, +] +`; + +exports[`usersGroupsReducer undefined action should return the default state 1`] = ` +{ + "permissionsMap": {}, +} +`; diff --git a/projects/users-groups/src/reducers/__tests__/index.spec.ts b/projects/users-groups/src/reducers/__tests__/index.spec.ts new file mode 100644 index 0000000..96b3fe8 --- /dev/null +++ b/projects/users-groups/src/reducers/__tests__/index.spec.ts @@ -0,0 +1,360 @@ +import * as UsersGroupsActions from '../../actions/users-groups.actions'; +import { + UserGroupType, + UserGroup, + UserServiceFeature, + UserRole +} from '../../users-groups.interfaces'; +import * as fromUsersGroups from '../index'; + +describe('usersGroupsReducer', () => { + describe('undefined action', () => { + it('should return the default state', () => { + const result = fromUsersGroups.usersGroups(undefined, {} as any); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('UsersGroupsActions.setUserDetails', () => { + it('should set the user details', () => { + const action = UsersGroupsActions.setUserDetails({ + userDetails: { + userId: '*', + firstName: 'James', + lastName: 'Gray', + email: 'james@gray.org', + prosecutingAuthorityAccess: 'TFL' + } + }); + const result = fromUsersGroups.usersGroups(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('UsersGroupsActions.setUserDetails', () => { + it('should set the user roles', () => { + const action = UsersGroupsActions.setUserRoles({ + userRoles: [{ roleId: 'test-user-role-id' }] as UserRole[] + }); + const result = fromUsersGroups.usersGroups(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('UsersGroupsActions.setUserServices', () => { + it('should set user services', () => { + const action = UsersGroupsActions.setUserServices({ + userServices: [ + { + name: '*', + features: [], + containsSearch: true + } + ] + }); + const result = fromUsersGroups.usersGroups(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('UsersGroupsActions.setUserPermissions', () => { + it('should set user permissions', () => { + const action = UsersGroupsActions.setUserPermissions({ + userGroups: [], + permissions: [ + { + action: 'test', + object: 'permission', + description: '*', + permissionId: 'permission-id-1', + target: 'target-01' + }, + { + action: 'test', + object: 'permission', + description: '*', + permissionId: 'permission-id-2', + target: 'target-02' + }, + { + action: 'test', + object: 'permission', + description: '*', + permissionId: 'permission-id-3' + } + ] + }); + const result = fromUsersGroups.usersGroups(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('UsersGroupsActions.setUserOrganisations', () => { + it('should set the organisations', () => { + const action = UsersGroupsActions.setUserOrganisations({ + organisations: [ + { + organisationId: 'test-organisation-id', + organisationName: 'test-organisation-name', + organisationType: 'test-organisation-type' + } + ] + }); + const result = fromUsersGroups.usersGroups(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('UsersGroupsActions.setGroupsWithOrganisation', () => { + it('should set the groups with organisation', () => { + const action = UsersGroupsActions.setGroupsWithOrganisation({ + groupsWithOrganisation: [ + { + groupName: 'SJP Prosecutors', + description: 'Transport for London', + category: 'speciality', + organisationId: '6127a06c-c67b-4972-8b47-ba7b22c0eb10', + resultsReferenceDataGroup: 'Probation', + documentsReferenceDataGroup: 'Probation Admin', + groupId: 'd231b119-d748-46da-89fc-293edf114e1', + roleIds: [] + } + ] + }); + const result = fromUsersGroups.usersGroups(undefined, action); + + expect(result).toMatchSnapshot(); + }); + }); + + describe('selectors', () => { + describe('getUserDetails', () => { + it('should select the user details', () => { + expect( + fromUsersGroups.getUserDetails({ + usersGroups: { + userDetails: { + userId: '*', + firstName: 'James', + lastName: 'Gray', + email: 'james@gray.org', + prosecutingAuthorityAccess: 'TFL' + } + } + } as fromUsersGroups.UsersGroupsState) + ).toMatchSnapshot(); + }); + }); + + describe('getUserRoles', () => { + it('should select the user roles', () => { + expect( + fromUsersGroups.getUserRoles({ + usersGroups: { + userRoles: [ + { + roleId: 'test-user-role-id', + description: 'test-user-role-description' + } + ] as UserRole[] + } + } as fromUsersGroups.UsersGroupsState) + ).toMatchSnapshot(); + }); + }); + + describe('getAllUserPlacements', () => { + it('should select the all the placements of all the roles', () => { + expect( + fromUsersGroups.getAllUserPlacements({ + usersGroups: { + userRoles: [ + { + roleId: 'test-user-role-id-1', + description: 'test-user-role-description-1', + userPlacements: [ + { + placementId: 'test-role-1-placement-id-1' + }, + { + placementId: 'test-role-1-placement-id-2' + } + ] + }, + { + roleId: 'test-user-role-id-2', + description: 'test-user-role-description-2', + userPlacements: [ + { + placementId: 'test-role-2-placement-id-1' + }, + { + placementId: 'test-role-2-placement-id-2' + } + ] + } + ] as UserRole[] + } + } as fromUsersGroups.UsersGroupsState) + ).toMatchSnapshot(); + }); + }); + + describe('getUserOrganisations', () => { + it('should select the organisations', () => { + expect( + fromUsersGroups.getUserOrganisations({ + usersGroups: { + organisations: [ + { + organisationId: 'test-organisation-id', + organisationName: 'test-organisation-name', + organisationType: 'test-organisation-type' + } + ] + } + } as fromUsersGroups.UsersGroupsState) + ).toMatchSnapshot(); + }); + }); + + describe('getGroupsWithOrganisation', () => { + it('should select the groups with organisation', () => { + expect( + fromUsersGroups.getGroupsWithOrganisation({ + usersGroups: { + groupsWithOrganisation: [ + { + groupName: 'SJP Prosecutors', + description: 'Transport for London', + category: 'speciality', + organisationId: '6127a06c-c67b-4972-8b47-ba7b22c0eb10', + resultsReferenceDataGroup: 'Probation', + documentsReferenceDataGroup: 'Probation Admin', + groupId: 'd231b119-d748-46da-89fc-293edf114e1', + roleIds: ['test-role-id'] + } + ] + } + } as fromUsersGroups.UsersGroupsState) + ).toMatchSnapshot(); + }); + }); + + describe('getUserServices', () => { + it('should select the user services', () => { + expect( + fromUsersGroups.getUserServices({ + usersGroups: { + userServices: [ + { + name: '*', + features: [] as UserServiceFeature[], + containsSearch: true + } + ] + } + } as fromUsersGroups.UsersGroupsState) + ).toMatchSnapshot(); + }); + }); + + describe('getUserCanSearch', () => { + it('should select whether the user has search privileges', () => { + expect( + fromUsersGroups.getUserCanSearch({ + usersGroups: { + userGroups: [] as UserGroup[] + } + } as fromUsersGroups.UsersGroupsState) + ).toEqual(false); + + ( + [ + { groupName: 'Court Administrators', canSearch: true }, + { groupName: 'Crown Court Admin', canSearch: true }, + { groupName: 'Court Clerks', canSearch: true }, + { groupName: 'Legal Advisers', canSearch: true }, + { groupName: 'Listing Officers', canSearch: true }, + { groupName: 'Judge', canSearch: true }, + { groupName: 'CPS', canSearch: true }, + { groupName: 'Court Associate', canSearch: true }, + { groupName: 'Youth Offending Service Admin', canSearch: true }, + { groupName: 'TFL User', canSearch: false } + ] as { groupName: UserGroupType; canSearch: boolean }[] + ).forEach(({ groupName, canSearch }) => { + const valid = fromUsersGroups.getUserCanSearch({ + usersGroups: { + userGroups: [{ groupName, groupId: '*', description: '*' }] + } + } as fromUsersGroups.UsersGroupsState); + if (valid !== canSearch) { + throw new Error( + `Expected \`getUserCanSearch\` for ${groupName} to be ${canSearch}. Got ${valid}.` + ); + } + }); + }); + }); + + describe('Permissions', () => { + const permissions = [ + { + action: 'test', + object: 'permission', + description: '*' + } + ]; + const permissionsMap = { + 'permission-id': { + action: 'test', + object: 'permission', + description: '*', + permissionId: 'permission-id' + } + }; + + describe('getUserRolePermissionsMap', () => { + it('should return permissions map from permissions', () => { + expect( + fromUsersGroups.getUserRolePermissionsMap({ + usersGroups: { + permissionsMap + } + } as fromUsersGroups.UsersGroupsState) + ).toMatchSnapshot(); + }); + }); + + describe('getUserRolePermissions', () => { + it('should return aggregated permissions for user', () => { + expect( + fromUsersGroups.getUserRolePermissions({ + usersGroups: { + permissionsMap + } + } as fromUsersGroups.UsersGroupsState) + ).toMatchSnapshot(); + }); + }); + + describe('getAllUserRolePermissionIds', () => { + it('should return permission ids for user', () => { + expect( + fromUsersGroups.getAllUserRolePermissionIds({ + usersGroups: { + permissionsMap + } + } as fromUsersGroups.UsersGroupsState) + ).toMatchSnapshot(); + }); + }); + }); + }); +}); diff --git a/projects/users-groups/src/reducers/index.ts b/projects/users-groups/src/reducers/index.ts new file mode 100644 index 0000000..291e74e --- /dev/null +++ b/projects/users-groups/src/reducers/index.ts @@ -0,0 +1,85 @@ +import { Action, MemoizedSelector, createSelector, defaultMemoize } from '@ngrx/store'; +import { State, userGroupsReducer } from './users-groups.reducer'; +import { + aggregateRolePermissions, + PermissionOperator, + permissionsExist, + RequiredPermission +} from '../utils'; +import { UserServiceFeature } from '../users-groups.interfaces'; + +export interface UsersGroupsState { + usersGroups: State; +} + +/** Provide reducer in AoT-compilation happy way */ +export function usersGroups(state: State | undefined, action: Action) { + return userGroupsReducer(state, action); +} + +export const getUserDetails = (state: UsersGroupsState) => state.usersGroups.userDetails; +export const getUserGroups = (state: UsersGroupsState) => state.usersGroups.userGroups; +export const getUserRoles = (state: UsersGroupsState) => state.usersGroups.userRoles; +export const getUserServices = (state: UsersGroupsState) => state.usersGroups.userServices; +export const getUserOrganisations = (state: UsersGroupsState) => state.usersGroups.organisations; +export const getUserFeatures = (state: UsersGroupsState) => state.usersGroups.features; + +export const getGroupsWithOrganisation = (state: UsersGroupsState) => + state.usersGroups.groupsWithOrganisation; +export const getUserSwitchableRoles = (state: UsersGroupsState) => + state.usersGroups.switchableRoles; + +export const getUserRolePermissionsMap = (state: UsersGroupsState) => + state.usersGroups.permissionsMap; + +export const getUserRolePermissions = createSelector(getUserRolePermissionsMap, (permissionsMap) => + aggregateRolePermissions(Object.values(permissionsMap)) +); + +export const getAllUserRolePermissionIds = createSelector( + getUserRolePermissionsMap, + (permissionsMap) => Object.keys(permissionsMap) +); + +export const getUserHasPermission = ( + requiredPermissions: RequiredPermission[], + operation = PermissionOperator.and, + target?: string, + source?: string +) => + createSelector(getUserRolePermissions, (userPermissions) => + permissionsExist(userPermissions, requiredPermissions, operation, target, source) + ); + +export const getUserCanSearch = createSelector(getUserGroups, (userGroups) => + (userGroups || []).some((userGroup) => + [ + 'Court Administrators', + 'Crown Court Admin', + 'Court Clerks', + 'Legal Advisers', + 'Listing Officers', + 'Judge', + 'CPS', + 'Court Associate', + 'Youth Offending Service Admin' + ].includes(userGroup.groupName) + ) +); + +export const getAllUserPlacements = createSelector(getUserRoles, (userRoles) => { + const placements = (userRoles || []).map((userRole) => userRole.userPlacements || []); + return placements.reduce( + (flattenedPlacements, nextPlacements) => flattenedPlacements.concat(nextPlacements), + [] + ); +}); + +export const getFeaturesByFeatureType = ( + type: string +): MemoizedSelector => + defaultMemoize((type: string) => + createSelector(getUserFeatures, (features: UserServiceFeature[] | undefined) => + (features || []).filter((feature) => feature.type === type) + ) + ).memoized(type); diff --git a/projects/users-groups/src/reducers/users-groups.reducer.ts b/projects/users-groups/src/reducers/users-groups.reducer.ts new file mode 100644 index 0000000..2a212bc --- /dev/null +++ b/projects/users-groups/src/reducers/users-groups.reducer.ts @@ -0,0 +1,62 @@ +import { createReducer, on } from '@ngrx/store'; +import { + setUserDetails, + setUserGroups, + setUserServices, + setUserPermissions, + setUserOrganisations, + setGroupsWithOrganisation, + setUserFeaturesSuccess +} from '../actions/users-groups.actions'; +import { + UserDetails, + UserGroup, + UserService, + UserRole, + RolePermission, + UserOrganisation, + UserGroupWithOrganisation, + UserServiceFeature +} from '../users-groups.interfaces'; +import { getPermissionsMap } from '../utils'; +import { setUserRoles } from '../actions/users-groups.actions'; + +export interface State { + userDetails?: UserDetails; + userGroups?: UserGroup[]; + userRoles?: UserRole[]; + userServices?: UserService[]; + permissionsMap: Record; + switchableRoles?: UserRole[]; + organisations?: UserOrganisation[]; + groupsWithOrganisation?: UserGroupWithOrganisation[]; + features?: UserServiceFeature[]; +} + +const initialState: State = { + permissionsMap: {} +}; + +export const userGroupsReducer = createReducer( + initialState, + on(setUserDetails, (state, { userDetails }) => ({ ...state, userDetails })), + // action is deprecated and state listener will be removed soon. see setUserPrmissions below. + on(setUserGroups, (state, { userGroups }) => ({ ...state, userGroups })), + on(setUserRoles, (state, { userRoles }) => ({ ...state, userRoles })), + on(setUserServices, (state, { userServices }) => ({ ...state, userServices })), + on(setUserOrganisations, (state, { organisations }) => ({ ...state, organisations })), + on(setGroupsWithOrganisation, (state, { groupsWithOrganisation }) => ({ + ...state, + groupsWithOrganisation + })), + on(setUserPermissions, (state, { userGroups, permissions, switchableRoles }) => ({ + ...state, + userGroups, + permissionsMap: permissions ? getPermissionsMap(permissions) : {}, + switchableRoles + })), + on(setUserFeaturesSuccess, (state, action) => ({ + ...state, + features: action.userFeatures + })) +); diff --git a/projects/users-groups/src/services/__tests__/system-announcements.service.spec.ts b/projects/users-groups/src/services/__tests__/system-announcements.service.spec.ts new file mode 100644 index 0000000..3b744c2 --- /dev/null +++ b/projects/users-groups/src/services/__tests__/system-announcements.service.spec.ts @@ -0,0 +1,94 @@ +import { TestBed } from '@angular/core/testing'; +import { CppHttp } from '@cpp/core'; +import { of, throwError } from 'rxjs'; +import { HttpErrorResponse } from '@angular/common/http'; +import { SystemAnnouncementsService } from '../system-announcements.service'; +import { + AnnouncementCategory, + AnnouncementType, + SystemAnnouncement +} from '../../users-groups.interfaces'; + +describe('SystemAnnouncementService', () => { + let service: SystemAnnouncementsService; + let http: CppHttp; + + const mockApiResponse = { + systemBannerAnnouncements: [ + { + id: 'test-announcement', + createdBy: 'test-user', + category: AnnouncementCategory.PLANNED, + type: AnnouncementType.INFORMATION, + startDate: '2023-12-01', + endDate: '2023-12-02', + startTime: '10:00', + endTime: '18:00', + title: 'Test Announcement', + details: 'Test details', + createdAt: '2023-11-30T10:00:00Z' + } + ] as SystemAnnouncement[] + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + SystemAnnouncementsService, + { + provide: CppHttp, + useValue: { + query: jest.fn() + } + } + ] + }); + http = TestBed.inject(CppHttp); + service = TestBed.inject(SystemAnnouncementsService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('getSystemAnnouncements', () => { + it('should call API and return announcements', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of(mockApiResponse)); + + service.getSystemAnnouncements().subscribe((announcements) => { + expect(announcements).toEqual(mockApiResponse.systemBannerAnnouncements); + expect(http.query).toHaveBeenCalledWith({ + url: '/systemannouncement-service/rest/systemannouncement/announcements', + requestType: 'application/vnd.systemannouncement.get-banner-announcements+json' + }); + }); + }); + + it('should return empty array if API returns empty data', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ systemBannerAnnouncements: [] })); + + service.getSystemAnnouncements().subscribe((announcements) => { + expect(announcements).toEqual([]); + expect(http.query).toHaveBeenCalled(); + }); + }); + + it('should propagate errors from the API', () => { + expect.assertions(1); + const errorResponse = new HttpErrorResponse({ status: 400 }); + + (http.query as jest.Mock).mockReturnValue(throwError(errorResponse)); + + service.getSystemAnnouncements().subscribe( + () => {}, + (error) => { + expect(error instanceof HttpErrorResponse).toBeTruthy(); + } + ); + }); + }); +}); diff --git a/projects/users-groups/src/services/__tests__/users-groups.service.spec.ts b/projects/users-groups/src/services/__tests__/users-groups.service.spec.ts new file mode 100644 index 0000000..a9708b1 --- /dev/null +++ b/projects/users-groups/src/services/__tests__/users-groups.service.spec.ts @@ -0,0 +1,344 @@ +import { TestBed } from '@angular/core/testing'; +import { of, throwError } from 'rxjs'; +import { CppHttp } from '@cpp/core'; +import { UsersGroupsService } from '../users-groups.service'; +import { AddPermissionPayload, RolePermission, UserDetails } from '../../users-groups.interfaces'; +import { cold } from 'jasmine-marbles'; +import { take } from 'rxjs/operators'; +import { HttpErrorResponse } from '@angular/common/http'; + +describe('UsersGroupsService', () => { + let service: UsersGroupsService; + let http: CppHttp; + + const roles = [ + { + roleId: 'role-id-1', + label: 'ATCM case manager', + description: 'ATCM case manager', + selectable: false, + permissionIds: [] + }, + { + roleId: 'role-id-2', + label: 'ATCM case manager', + description: 'ATCM case manager', + selectable: false, + permissionIds: [] + } + ]; + + const userGroups = [ + { + groupId: 'group-id-1', + groupName: 'Charging Lawyers', + description: 'Charging Lawyers', + category: 'speciality', + organisationId: 'organisation-id', + roleIds: ['role-id-1', 'role-id-2'] + }, + { + groupId: 'group-id-2', + groupName: 'cjse', + description: 'CJSE Description', + category: 'speciality', + organisationId: 'organisation-id', + roleIds: [] + } + ]; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + UsersGroupsService, + { + provide: CppHttp, + useValue: { + query: jest.fn(), + command: jest.fn() + } + } + ] + }); + http = TestBed.inject(CppHttp); + service = TestBed.inject(UsersGroupsService); + }); + + describe('fetchLoggedInUserDetails', () => { + it('should fetch the logged in user details', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ userId: '*' } as UserDetails)); + + service.fetchLoggedInUserDetails().subscribe((userDetails) => { + expect(userDetails).toEqual({ userId: '*' }); + expect(http.query).toHaveBeenCalledWith({ + url: '/usersgroups-query-api/query/api/rest/usersgroups/users/logged-in-user', + requestType: 'application/vnd.usersgroups.logged-in-user-details+json' + }); + }); + }); + }); + + describe('fetchUserGroups()', () => { + it('should fetch the user groups', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ groups: [] })); + + service.fetchUserGroups().subscribe((groups) => { + expect(groups).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/usersgroups-query-api/query/api/rest/usersgroups/users/logged-in-user/groups', + requestType: 'application/vnd.usersgroups.get-logged-in-user-groups+json' + }); + }); + }); + }); + + describe('fetchUserServices()', () => { + it('should fetch the user services', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ services: [] })); + + service.fetchUserServices().subscribe((userServices) => { + expect(userServices).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/usersgroups-query-api/query/api/rest/usersgroups/get-user-services', + requestType: 'application/vnd.usersgroups.get-user-services+json' + }); + }); + }); + }); + + describe('fetchOrganisations', () => { + it('should fetch the organisations', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ organisations: [] })); + + service.fetchOrganisations().subscribe((organisations) => { + expect(organisations).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/usersgroups-query-api/query/api/rest/usersgroups/organisationlist', + requestType: 'application/vnd.usersgroups.organisations+json' + }); + }); + }); + }); + + describe('fetchGroupsWithOrganisations', () => { + it('should fetch the groups with organisation', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ groupsWithOrganisation: [] })); + + service.fetchGroupsWithOrganisation().subscribe((groupsWithOrganisation) => { + expect(groupsWithOrganisation).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: '/usersgroups-query-api/query/api/rest/usersgroups/groups/organisation', + requestType: 'application/vnd.usersgroups.get-groups-with-organisation+json' + }); + }); + }); + }); + + describe('fetchUserSelectedGroupsAndRoles', () => { + it('should fetch roles for a user', () => { + const response = { groupIds: userGroups.map(({ groupId }) => groupId), allRoles: roles }; + const expected = { groupIds: userGroups.map(({ groupId }) => groupId), allRoles: roles }; + const response$ = cold('-a|', { a: response }); + const expected$ = cold('-b|', { b: expected }); + + (http.query as jest.Mock).mockReturnValue(response$); + + const query$ = service.fetchUserSelectedRoles(); + + expect(query$).toBeObservable(expected$); + expect(http.query).toHaveBeenCalledWith({ + url: `/usersgroups-query-api/query/api/rest/usersgroups/users/logged-in-user/roles`, + requestType: 'application/vnd.usersgroups.get-roles-for-logged-in-user+json' + }); + }); + }); + + describe('revokeUserPermissions', () => { + it('should revoke permissions for a user', async () => { + expect.assertions(4); + const response$ = of('*').pipe(take(1)); + const permissionIds = ['permission-id-1', 'permission-id-2', 'permission-id-3']; + + (http.command as jest.Mock).mockReturnValue(response$); + + service.revokeUserPermissions(...permissionIds).subscribe((response) => { + const [{ url, requestType, body }] = (http.command as jest.Mock).mock.calls[0]; + expect(response).toEqual('*'); + expect(url).toEqual('/usersgroups-command-api/command/api/rest/usersgroups/permissions'); + expect(requestType).toEqual('application/vnd.usersgroups.delete-bulk-permission+json'); + expect(body).toEqual({ permissionIds }); + }); + }); + }); + + describe('addBulkPermissions', () => { + it('should add permissions for a user', async () => { + expect.assertions(4); + const response$ = of('*').pipe(take(1)); + const permissions: AddPermissionPayload[] = [ + { + object: 'object', + action: 'action', + target: 'target', + id: '*' + } + ] as AddPermissionPayload[]; + + (http.command as jest.Mock).mockReturnValue(response$); + + service.addBulkPermissions(permissions).subscribe((response) => { + const [{ url, requestType, body }] = (http.command as jest.Mock).mock.calls[0]; + expect(response).toEqual('*'); + expect(url).toEqual('/usersgroups-command-api/command/api/rest/usersgroups/permissions'); + expect(requestType).toEqual('application/vnd.usersgroups.add-bulk-permission+json'); + expect(body).toEqual({ permissions }); + }); + }); + }); + + describe('getUsersByRole()', () => { + it('should fetch the user details based on role', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ users: [] })); + + const role = 'Magistrate'; + + service.fetchUsersByRole(role).subscribe((users) => { + expect(users).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: `/usersgroups-query-api/query/api/rest/usersgroups/get-users-by-role?role=${role}`, + requestType: 'application/vnd.usersgroups.get-users-by-role+json' + }); + }); + }); + }); + + describe('getUsersByPlacementAndRole()', () => { + it('should fetch the user details based on placement and role', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ users: [] })); + + const placement = 'B01DU00'; + const role = 'Listing Officer'; + + service.getUsersByPlacementAndRole(placement, role).subscribe((users) => { + expect(users).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: `/usersgroups-query-api/query/api/rest/usersgroups/get-users-by-placement-and-role?placement=${placement}&role=${role}`, + requestType: 'application/vnd.usersgroups.get-users-by-placement-and-role+json' + }); + }); + }); + }); + + describe('getPermissionsBy', () => { + const permissions = [ + { object: 'object', action: 'action', target: 'target' }, + { object: 'object', action: 'action', target: 'target' } + ] as RolePermission[]; + it('should get permissions by action and object', async () => { + expect.assertions(3); + const response$ = of({ permissions }); + const payload = { object: 'object1', action: 'action1' }; + + (http.query as jest.Mock).mockReturnValue(response$); + + service.getPermissionsBy(payload).subscribe((response) => { + const [{ url, requestType }] = (http.query as jest.Mock).mock.calls[0]; + expect(response).toEqual(permissions); + expect(url).toEqual( + `/usersgroups-query-api/query/api/rest/usersgroups/permissions?object=object1&action=action1` + ); + expect(requestType).toEqual('application/vnd.usersgroups.permissions+json'); + }); + }); + + it('should get permissions by action and object and source', async () => { + expect.assertions(3); + const response$ = of({ permissions }); + const payload = { object: 'object1', action: 'action1', source: 'source1' }; + + (http.query as jest.Mock).mockReturnValue(response$); + + service.getPermissionsBy(payload).subscribe((response) => { + const [{ url, requestType }] = (http.query as jest.Mock).mock.calls[0]; + expect(response).toEqual(permissions); + expect(url).toEqual( + `/usersgroups-query-api/query/api/rest/usersgroups/permissions?object=object1&action=action1&source=source1` + ); + expect(requestType).toEqual('application/vnd.usersgroups.permissions+json'); + }); + }); + + it('should get permissions by action, object, source and target', async () => { + expect.assertions(3); + const response$ = of({ permissions }); + const payload = { + object: 'object1', + action: 'action1', + source: 'source1', + target: 'target1' + }; + + (http.query as jest.Mock).mockReturnValue(response$); + + service.getPermissionsBy(payload).subscribe((response) => { + const [{ url, requestType }] = (http.query as jest.Mock).mock.calls[0]; + expect(response).toEqual(permissions); + expect(url).toEqual( + `/usersgroups-query-api/query/api/rest/usersgroups/permissions?object=object1&action=action1&source=source1&target=target1` + ); + expect(requestType).toEqual('application/vnd.usersgroups.permissions+json'); + }); + }); + }); + + describe('getUserDetails()', () => { + it('should fetch the user details based on given userId', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of([])); + + const userId = 'user-id'; + + service.getUserDetails(userId).subscribe((users) => { + expect(users).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: `/usersgroups-query-api/query/api/rest/usersgroups/users/${userId}`, + requestType: 'application/vnd.usersgroups.user-details+json' + }); + }); + }); + }); + + describe('getUsersByRoleAndNamePart()', () => { + it('should fetch the user details based on role and name part', () => { + expect.assertions(2); + + (http.query as jest.Mock).mockReturnValue(of({ users: [] })); + + const role = 'Legal Advisers'; + const namePart = 'Emma'; + + service.fetchUsersByRoleAndNamePart(role, namePart).subscribe((users) => { + expect(users).toEqual([]); + expect(http.query).toHaveBeenCalledWith({ + url: `/usersgroups-query-api/query/api/rest/usersgroups/get-users-by-role-and-name-part?role=${role}&namePart=${namePart}`, + requestType: 'application/vnd.usersgroups.get-users-by-role-and-name-part+json' + }); + }); + }); + }); +}); diff --git a/projects/users-groups/src/services/system-announcements.service.ts b/projects/users-groups/src/services/system-announcements.service.ts new file mode 100644 index 0000000..b3d349d --- /dev/null +++ b/projects/users-groups/src/services/system-announcements.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { CppHttp } from '@cpp/core'; +import { SystemAnnouncement } from '../users-groups.interfaces'; + +@Injectable({ + providedIn: 'root' +}) +export class SystemAnnouncementsService { + private readonly queryApi = '/systemannouncement-service/rest/systemannouncement'; + + constructor(private http: CppHttp) {} + + getSystemAnnouncements(): Observable { + return this.http + .query<{ systemBannerAnnouncements: SystemAnnouncement[] }>({ + url: `${this.queryApi}/announcements`, + requestType: 'application/vnd.systemannouncement.get-banner-announcements+json' + }) + .pipe(map((res) => res.systemBannerAnnouncements)); + } +} diff --git a/projects/users-groups/src/services/users-groups.service.ts b/projects/users-groups/src/services/users-groups.service.ts new file mode 100644 index 0000000..0b90a86 --- /dev/null +++ b/projects/users-groups/src/services/users-groups.service.ts @@ -0,0 +1,173 @@ +import { Injectable } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; +import { CppHttp } from '@cpp/core'; + +import { + UserDetails, + UserGroup, + UserService, + UserPermissions, + UserOrganisation, + UserGroupWithOrganisation, + UserRole, + UserServiceFeature, + RolePermission, + AddPermissionPayload, + UserPersonalDetails +} from '../users-groups.interfaces'; +import { isEmpty } from 'lodash-es'; +@Injectable() +export class UsersGroupsService { + constructor(private http: CppHttp) {} + + fetchLoggedInUserDetails(): Observable { + return this.http.query({ + url: '/usersgroups-query-api/query/api/rest/usersgroups/users/logged-in-user', + requestType: 'application/vnd.usersgroups.logged-in-user-details+json' + }); + } + + /**@deprecated use the fetchUserPermissions method instead to retrieve groups.*/ + fetchUserGroups(): Observable { + return this.http + .query<{ groups: UserGroup[] }>({ + url: '/usersgroups-query-api/query/api/rest/usersgroups/users/logged-in-user/groups', + requestType: 'application/vnd.usersgroups.get-logged-in-user-groups+json' + }) + .pipe(map((result) => result.groups)); + } + + fetchUserPermissions(): Observable { + return this.http.query({ + url: '/usersgroups-query-api/query/api/rest/usersgroups/users/logged-in-user/permissions', + requestType: 'application/vnd.usersgroups.get-logged-in-user-permissions+json' + }); + } + + fetchUserServices(): Observable { + return this.http + .query<{ services: UserService[] }>({ + url: '/usersgroups-query-api/query/api/rest/usersgroups/get-user-services', + requestType: 'application/vnd.usersgroups.get-user-services+json' + }) + .pipe(map((result) => result.services)); + } + + fetchUserFeatures(): Observable { + return this.http + .query<{ features: UserServiceFeature[] }>({ + url: '/usersgroups-query-api/query/api/rest/usersgroups/features/enabled', + requestType: 'application/vnd.usersgroups.features+json' + }) + .pipe(map((result) => result.features)); + } + + fetchOrganisations(): Observable { + return this.http + .query<{ organisations: UserOrganisation[] }>({ + url: '/usersgroups-query-api/query/api/rest/usersgroups/organisationlist', + requestType: 'application/vnd.usersgroups.organisations+json' + }) + .pipe(map((result) => result.organisations)); + } + + fetchGroupsWithOrganisation(): Observable { + return this.http + .query<{ groupsWithOrganisation: UserGroupWithOrganisation[] }>({ + url: '/usersgroups-query-api/query/api/rest/usersgroups/groups/organisation', + requestType: 'application/vnd.usersgroups.get-groups-with-organisation+json' + }) + .pipe(map((result) => result.groupsWithOrganisation)); + } + + fetchUserSelectedRoles(): Observable<{ groupIds: string[]; allRoles: UserRole[] }> { + return this.http.query<{ groupIds: string[]; allRoles: UserRole[] }>({ + url: `/usersgroups-query-api/query/api/rest/usersgroups/users/logged-in-user/roles`, + requestType: 'application/vnd.usersgroups.get-roles-for-logged-in-user+json' + }); + } + + revokeUserPermissions(...permissionIds: string[]): Observable { + return this.http.command({ + url: '/usersgroups-command-api/command/api/rest/usersgroups/permissions', + requestType: 'application/vnd.usersgroups.delete-bulk-permission+json', + body: { + permissionIds + } + }); + } + + addBulkPermissions(permissions: AddPermissionPayload[]): Observable { + return this.http.command({ + url: '/usersgroups-command-api/command/api/rest/usersgroups/permissions', + requestType: 'application/vnd.usersgroups.add-bulk-permission+json', + body: { + permissions + } + }); + } + + getPermissionsBy({ + action, + object, + source, + target + }: { + object: string; + action: string; + source?: string; + target?: string; + }): Observable { + let url = `/usersgroups-query-api/query/api/rest/usersgroups/permissions?object=${object}&action=${action}`; + + if (!!source) { + url = url.concat(`&source=${source}`); + } + + if (!!target) { + url = url.concat(`&target=${target}`); + } + + return this.http + .query<{ permissions: RolePermission[] }>({ + url, + requestType: 'application/vnd.usersgroups.permissions+json' + }) + .pipe(map((result) => result.permissions)); + } + + fetchUsersByRole(role: string): Observable { + return this.http + .query<{ users: UserPersonalDetails[] }>({ + url: `/usersgroups-query-api/query/api/rest/usersgroups/get-users-by-role?role=${role}`, + requestType: 'application/vnd.usersgroups.get-users-by-role+json' + }) + .pipe(map((res) => res.users)); + } + + getUsersByPlacementAndRole(placement: string, role: string): Observable { + return this.http + .query<{ users: UserDetails[] }>({ + url: `/usersgroups-query-api/query/api/rest/usersgroups/get-users-by-placement-and-role?placement=${placement}&role=${role}`, + requestType: 'application/vnd.usersgroups.get-users-by-placement-and-role+json' + }) + .pipe(map((users) => users.users)); + } + + getUserDetails(userId: string): Observable { + return this.http.query({ + url: `/usersgroups-query-api/query/api/rest/usersgroups/users/${userId}`, + requestType: 'application/vnd.usersgroups.user-details+json' + }); + } + + fetchUsersByRoleAndNamePart(role: string, namePart: string): Observable { + return this.http + .query<{ users: UserPersonalDetails[] }>({ + url: `/usersgroups-query-api/query/api/rest/usersgroups/get-users-by-role-and-name-part?role=${role}&namePart=${namePart}`, + requestType: 'application/vnd.usersgroups.get-users-by-role-and-name-part+json' + }) + .pipe(map((res) => res.users)); + } +} diff --git a/projects/users-groups/src/users-groups.interfaces.ts b/projects/users-groups/src/users-groups.interfaces.ts new file mode 100644 index 0000000..6ee5ece --- /dev/null +++ b/projects/users-groups/src/users-groups.interfaces.ts @@ -0,0 +1,167 @@ +export type UserGroupType = + | 'IDAM' + | 'CMS' + | 'Court Clerks' + | 'Prison Admin' + | 'Judge' + | 'Judiciary' + | 'Judicial Officer' + | 'Listing Officers' + | 'Crown Court Admin' + | 'Probation Admin' + | 'Police Admin' + | 'Victims & Witness Care Admin' + | 'Youth Offending Service Admin' + | 'System Users' + | 'Online Plea System Users' + | 'FTPS' + | 'Court Administrators' + | 'Legal Advisers' + | 'Support Users' + | 'TFL Prosecutors' + | 'SJP Prosecutors' + | 'TVL Prosecutors' + | 'HMCTS Analytics and Performance' + | 'Defence Users' + | 'Legal Aid Agency Admin' + | 'CPPI Consumers' + | 'Performance Users' + | 'CPS' + | 'Defence Lawyers'; + +interface Permission { + description: string; + object: string; + action: string; + source?: string; + activeDate?: string; + startTime?: string; + endTime?: string; +} + +export type AddPermissionPayload = Permission & { target?: string; active?: boolean; id: string }; +export interface RolePermission extends Permission { + permissionId: string; + target?: string; +} + +export interface AggregatedRolePermission extends Permission { + targets?: string[]; +} + +export interface UserPersonalDetails { + userId: string; + firstName: string; + lastName: string; + email: string; +} + +export interface UserDetails extends UserPersonalDetails { + organisationId?: string; + userType?: UserType; + prosecutingAuthorityAccess: string; +} + +export enum UserType { + User = 'User', + CPPSupportAdmin = 'CPP-Support-Admin', + OrganisationAdmin = 'Organisation-Admin' +} + +export interface UserService { + name: string; + containsSearch: boolean; + features: UserServiceFeature[]; +} + +export interface UserGroup { + groupId: string; + groupName: UserGroupType | string; + description: string; + prosecutingAuthority?: string; +} + +export interface UserServiceFeature { + key: string; + title: string; + type: 'LINK' | 'SEARCH' | 'COMPONENT'; +} + +export interface UserRole { + roleId: string; + label: string; + description: string; + active?: boolean; + selectable?: boolean; + startDate?: string; + endDate?: string; + permissionIds?: string[]; + organisationId?: string; + groupIds?: string[]; + userPlacements?: UserPlacement[]; +} +export interface UserPermissions { + groups: UserGroup[]; + permissions: RolePermission[]; + switchableRoles: UserRole[]; +} + +export interface UserOrganisation { + organisationId: string; + organisationType: string; + organisationName: string; + addressLine1?: string; + addressLine2?: string; + addressLine3?: string; + addressLine4?: string; + addressPostcode?: string; + phoneNumber?: string; + email?: string; + laaContractNumbers?: string[]; +} + +export interface UserGroupWithOrganisation extends UserGroup { + category: string; + organisationId: string; + roleIds: string[]; + resultsReferenceDataGroup?: string; + documentsReferenceDataGroup?: string; +} + +export interface UserPlacement { + placementId: string; + home?: boolean; +} + +export interface UserSystemDowntimeAnnouncement { + startDate: string; + endDate: string; + startTime: string; + endTime: string; + daysInAdvance: number; +} + +export enum AnnouncementCategory { + PLANNED = 'PLANNED', + UNPLANNED = 'UNPLANNED' +} + +export enum AnnouncementType { + CRITICAL = 'CRITICAL', + WARNING = 'WARNING', + INFORMATION = 'INFORMATION' +} + +export interface SystemAnnouncement { + id?: string; + title: string; + details: string; + category: AnnouncementCategory; + type: AnnouncementType; + startDate?: string; + endDate?: string; + startTime?: string; + endTime?: string; + createdBy?: string; + createdAt?: string; +} diff --git a/projects/users-groups/src/users-groups.module.ts b/projects/users-groups/src/users-groups.module.ts new file mode 100644 index 0000000..40ae014 --- /dev/null +++ b/projects/users-groups/src/users-groups.module.ts @@ -0,0 +1,64 @@ +import { NgModule } from '@angular/core'; +import { StoreModule } from '@ngrx/store'; +import { UserDetailsGuard } from './guards/user-details.guard'; +import { UserGroupsGuard } from './guards/user-groups.guard'; +import { UserServiceExistsGuard } from './guards/user-service-exists.guard'; +import { UserServicesGuard } from './guards/user-services.guard'; +import { usersGroups } from './reducers/index'; +import { UsersGroupsService } from './services/users-groups.service'; +import { CppUserHasPermissionDirective } from './permissions/directives/cpp-user-has-permission.directive'; +import { UserOrganisationsGuard } from './guards/user-organisations.guard'; +import { UserGroupsWithOrganisationGuard } from './guards/user-groups-with-organisation.guard'; +import { UserRolesGuard } from './guards/user-roles.guard'; +import { UserFeaturesGuard } from './guards/user-features.guard'; +import { CppHasFeatureEnabledDirective } from './features/directives/cpp-user-has-feature-enabled.directive'; +import { EffectsModule } from '@ngrx/effects'; +import { UserGroupsEffects } from './effects/user-groups.effects'; +import { SystemAnnouncementsService } from './services/system-announcements.service'; +import { UserPermissionsGuard } from './guards/permissions/user-permissions.guard'; +import { UserPermissionsExistGuard } from './guards/permissions/user-permissions-exist.guard'; + +/** + * @deprecated + * This will be removed in some release moving forward but is + * left here for Backward compatilibity. + * + * To use users groups remove the module where used. + * In the app module or Bootstrap function (Standalone) or Route , + * provide users groups context using the following as per preference + * @method provideUserGroupsEnvironmentContext + * - This will provide all guards, and services inclusive of the feature store. + * @method provideUsersGroupsStore + * - You can provide just the feature store using this method in your module or route providers and import the guards you need on demand. + * + * + * PLEASE ENSURE THAT YOUR BOOTSTRAP OR APPMODULE USES THE PROVIDESTORE as the root prior to using any of the methods above mentioned. You can + * mix StoreModule.forRoot and provideStore if the application is still modular - Please refer to Ngrx docs for details + * + * Finally all Users groups directives are standalone and can be imported on demand in the modules or standalone components + * when needed. + */ +@NgModule({ + imports: [ + StoreModule.forFeature('usersGroups', usersGroups), + EffectsModule.forFeature([UserGroupsEffects]), + CppUserHasPermissionDirective, + CppHasFeatureEnabledDirective + ], + providers: [ + UserDetailsGuard, + UserGroupsGuard, + UserRolesGuard, + UserServiceExistsGuard, + UserServicesGuard, + UserOrganisationsGuard, + UserGroupsWithOrganisationGuard, + UsersGroupsService, + UserFeaturesGuard, + SystemAnnouncementsService, + UserPermissionsGuard, + UserPermissionsExistGuard + ], + exports: [CppUserHasPermissionDirective, CppHasFeatureEnabledDirective] +}) +export class UsersGroupsModule {} diff --git a/projects/users-groups/src/utils/__tests__/features-exist.spec.ts b/projects/users-groups/src/utils/__tests__/features-exist.spec.ts new file mode 100644 index 0000000..f4b0fde --- /dev/null +++ b/projects/users-groups/src/utils/__tests__/features-exist.spec.ts @@ -0,0 +1,38 @@ +import { UserService, UserServiceFeature } from '../../users-groups.interfaces'; +import { featuresExist } from '../features-exist'; + +describe('featuresExist deprecated', () => { + const userServices = [ + { features: [{ key: 'featureA' }] }, + { features: [{ key: 'featureA' }, { key: 'featureC' }] } + ] as UserService[]; + + it('should return true if one or more of the feature keys are present in the user services', () => { + expect(featuresExist(userServices, ['featureC'])).toBe(true); + expect(featuresExist(userServices, ['featureA', 'featureD'])).toBe(true); + expect(featuresExist(userServices, ['featureA', 'featureB'])).toBe(true); + }); + + it('should return false if none of the feature keys are present in the user services', () => { + expect(featuresExist(userServices, ['featureD'])).toBe(false); + expect(featuresExist(userServices, ['featureE', 'featureF'])).toBe(false); + expect(featuresExist(userServices, [])).toBe(false); + }); +}); + +describe('featuresExist', () => { + const features = [ + { key: 'feature1', title: 'feature1', type: 'COMPONENT' }, + { key: 'feature2', title: 'feature2', type: 'COMPONENT' } + ] as UserServiceFeature[]; + + it('should return true if one or more feature keys are present', () => { + expect(featuresExist(features, ['feature1'])).toBe(true); + expect(featuresExist(features, ['feature1', 'feature2'])).toBe(true); + }); + + it('should return flase if none of the feature keys are present', () => { + expect(featuresExist(features, ['feature4'])).toBe(false); + expect(featuresExist(features, ['feature5', 'feature6'])).toBe(false); + }); +}); diff --git a/projects/users-groups/src/utils/__tests__/permissions-exist.spec.ts b/projects/users-groups/src/utils/__tests__/permissions-exist.spec.ts new file mode 100644 index 0000000..fe5b3f0 --- /dev/null +++ b/projects/users-groups/src/utils/__tests__/permissions-exist.spec.ts @@ -0,0 +1,144 @@ +import { RolePermission, AggregatedRolePermission } from '../../users-groups.interfaces'; +import { permissionsExist, PermissionOperator } from '../permissions-exist'; + +describe('permissionsExist', () => { + const userPermissions = [ + { action: 'view', object: 'case', targets: ['target 123', 'target 235'], source: 'source a' }, + { action: 'view', object: 'case', targets: ['target 678'], source: 'source b' }, + { action: 'view', object: 'case', targets: ['target 345'], source: 'source c' }, + { action: 'view', object: 'case', target: undefined, source: 'source a' }, + { action: 'view', object: 'case', target: undefined } + ] as AggregatedRolePermission[]; + + it('should return true if all of the expected permissions are present in the existing user permissions', () => { + const expectedPermissionOne = { + action: 'view', + object: 'case', + target: 'target 123', + source: 'source a' + } as RolePermission; + const expectedPermissionTwo = { + action: 'view', + object: 'case', + target: 'target 678', + source: 'source b' + } as RolePermission; + const expectedPermissionThree = { + action: 'view', + object: 'case', + target: '', + source: 'source a' + } as RolePermission; + + expect( + permissionsExist(userPermissions, [ + expectedPermissionOne, + expectedPermissionTwo, + expectedPermissionThree + ]) + ).toBe(true); + }); + + it('should return false if some of the expected permissions are present in the existing user permissions', () => { + const expectedPermissionOne = { + action: 'view', + object: 'case', + target: 'target 123', + source: 'source a' + } as RolePermission; + const expectedPermissionTwo = { + action: 'view', + object: 'case', + target: 'target 678', + source: 'source b' + } as RolePermission; + const expectedPermissionThree = { + action: 'view', + object: 'case', + target: 'target 825', + source: 'source d' + } as RolePermission; + + expect( + permissionsExist(userPermissions, [ + expectedPermissionOne, + expectedPermissionTwo, + expectedPermissionThree + ]) + ).toBe(false); + }); + + it('should return false if none of the expected permissions are present in the existing user permissions', () => { + const expectedPermissionOne = { + action: 'view', + object: 'case', + target: 'target 367', + source: 'source c' + } as RolePermission; + const expectedPermissionTwo = { + action: 'view', + object: 'case', + target: 'target 123', + source: 'source d' + } as RolePermission; + const expectedPermissionThree = { + action: 'view', + object: 'case', + target: 'target 935', + source: 'source a' + } as RolePermission; + const expectedPermissionFour = { + action: 'view', + object: 'Hearing', + target: 'target 678', + source: 'source b' + } as RolePermission; + + expect( + permissionsExist(userPermissions, [ + expectedPermissionOne, + expectedPermissionTwo, + expectedPermissionThree, + expectedPermissionFour + ]) + ).toBe(false); + }); + + it('should return true, if specific target is provided separately for expected permissions and it exists in user permissions', () => { + const expectedPermissionOne = { + action: 'view', + object: 'case', + source: 'source a' + } as RolePermission; + + const specificTarget = 'target 123'; + + expect( + permissionsExist( + userPermissions, + [expectedPermissionOne], + PermissionOperator.and, + specificTarget + ) + ).toBe(true); + }); + + it('should return false, if specific target is provided separately for expected permissions and it does not exist in user permissions', () => { + const expectedPermissionOne = { + action: 'view', + object: 'case', + source: 'source a' + } as RolePermission; + + const specificTarget = 'target 678'; + + expect( + permissionsExist( + userPermissions, + [expectedPermissionOne], + PermissionOperator.and, + specificTarget + ) + ).toBe(false); + }); +}); diff --git a/projects/users-groups/src/utils/__tests__/role-permissions-aggregator.spec.ts b/projects/users-groups/src/utils/__tests__/role-permissions-aggregator.spec.ts new file mode 100644 index 0000000..d293b7f --- /dev/null +++ b/projects/users-groups/src/utils/__tests__/role-permissions-aggregator.spec.ts @@ -0,0 +1,85 @@ +import { RolePermission, AggregatedRolePermission } from '../../users-groups.interfaces'; +import { aggregateRolePermissions } from '../role-permissions-aggregator'; + +describe('aggregateRolePermissions', () => { + let permissions = [ + { action: 'view', object: 'case', target: 'target 123', source: 'source a' }, + { action: 'view', object: 'case', target: 'target 235', source: 'source a' } + ] as RolePermission[]; + + it('should accumulate target identifiers if user has same permissions with different targets', () => { + const expectedResult = [ + { action: 'view', object: 'case', targets: ['target 123', 'target 235'], source: 'source a' } + ] as AggregatedRolePermission[]; + + expect(aggregateRolePermissions(permissions)).toEqual(expectedResult); + }); + + it('should not accumulate target identifiers if user has same permissions with different targets and different sources', () => { + permissions = [ + { action: 'view', object: 'case', target: 'target 123', source: 'source a' }, + { action: 'view', object: 'case', target: 'target 235', source: 'source b' } + ] as RolePermission[]; + + const expectedResult = [ + { action: 'view', object: 'case', targets: ['target 123'], source: 'source a' }, + { action: 'view', object: 'case', targets: ['target 235'], source: 'source b' } + ] as AggregatedRolePermission[]; + + expect(aggregateRolePermissions(permissions)).toEqual(expectedResult); + }); + + it('should accumulate target identifiers if user has same permissions with different targets and same source', () => { + permissions = [ + { action: 'view', object: 'case', target: 'target 123', source: 'source a' }, + { action: 'view', object: 'case', target: 'target 235', source: 'source a' } + ] as RolePermission[]; + + const expectedResult = [ + { action: 'view', object: 'case', targets: ['target 123', 'target 235'], source: 'source a' } + ] as AggregatedRolePermission[]; + + expect(aggregateRolePermissions(permissions)).toEqual(expectedResult); + }); + + it('should resolve permissions if user has same permissions but has a target on one of the permissions', () => { + permissions = [ + { action: 'view', object: 'case', source: 'source a' }, + { action: 'view', object: 'case', target: 'target 235', source: 'source a' } + ] as RolePermission[]; + + const expectedResult = [ + { action: 'view', object: 'case', targets: undefined, source: 'source a' }, + { action: 'view', object: 'case', targets: ['target 235'], source: 'source a' } + ] as AggregatedRolePermission[]; + + expect(aggregateRolePermissions(permissions)).toEqual(expectedResult); + }); + + it('should transform target identifiers to empty strings if targets dont exist', () => { + permissions = [ + { action: 'view', object: 'case', source: 'source a' }, + { action: 'view', object: 'case', source: 'source b' } + ] as RolePermission[]; + + const expectedResult = [ + { action: 'view', object: 'case', source: 'source a' }, + { action: 'view', object: 'case', source: 'source b' } + ] as AggregatedRolePermission[]; + + expect(aggregateRolePermissions(permissions)).toEqual(expectedResult); + }); + + it('should return unique permissions if duplicated', () => { + permissions = [ + { action: 'view', object: 'case', source: 'source a' }, + { action: 'view', object: 'case', source: 'source a' } + ] as RolePermission[]; + + const expectedResult = [ + { action: 'view', object: 'case', source: 'source a' } + ] as AggregatedRolePermission[]; + + expect(aggregateRolePermissions(permissions)).toEqual(expectedResult); + }); +}); diff --git a/projects/users-groups/src/utils/features-exist.ts b/projects/users-groups/src/utils/features-exist.ts new file mode 100644 index 0000000..7f8c004 --- /dev/null +++ b/projects/users-groups/src/utils/features-exist.ts @@ -0,0 +1,32 @@ +import { UserServiceFeature, UserService } from '../users-groups.interfaces'; + +// This featureExist method has been changed to accommodate legacy userServices therefore +// making the method backwards compatible. The userService[] implementation will be removed +// once we get rid of the old endpoint. + +/**@deprecated pass in the UserServiceFeature[] instead. */ +export function featuresExist(userServices: UserService[], expectedFeatureKeys: string[]): boolean; +export function featuresExist( + features: UserServiceFeature[], + expectedFeatureKeys: string[] +): boolean; +export function featuresExist( + featureVariants: UserServiceFeature[] | UserService[], + expectedFeatureKeys: string[] +): boolean { + let allFeatureKeys: string[] = []; + if (isUserServices(featureVariants)) { + allFeatureKeys = featureVariants.reduce( + (allKeys: string[], service: UserService) => + allKeys.concat(service.features.map(({ key }) => key)), + [] + ); + } else { + allFeatureKeys = featureVariants.map(({ key }) => key); + } + return expectedFeatureKeys.some((efk) => allFeatureKeys.includes(efk)); +} + +function isUserServices(value: UserService[] | UserServiceFeature[]): value is UserService[] { + return (value as UserService[]).every((item) => 'features' in item); +} diff --git a/projects/users-groups/src/utils/index.ts b/projects/users-groups/src/utils/index.ts new file mode 100644 index 0000000..4e3fddf --- /dev/null +++ b/projects/users-groups/src/utils/index.ts @@ -0,0 +1,3 @@ +export * from './features-exist'; +export * from './role-permissions-aggregator'; +export * from './permissions-exist'; diff --git a/projects/users-groups/src/utils/permissions-exist.ts b/projects/users-groups/src/utils/permissions-exist.ts new file mode 100644 index 0000000..91141b7 --- /dev/null +++ b/projects/users-groups/src/utils/permissions-exist.ts @@ -0,0 +1,49 @@ +import { AggregatedRolePermission, RolePermission } from '../users-groups.interfaces'; + +type PermissionSourceAndTarget = Pick; +export type RequiredPermission = Pick & + Partial; +export enum PermissionOperator { + and = 'and', + or = 'or' +} +/** + * A utility function to verify user permissions consists of expected permissions + * @param userPermissions - The users existing permissions. + * @param requiredPermissions - the permissions to check against. + * @param specificTarget - an explicit specific feature identifier or attribute associated with this permission (e.g the id of a Case.). + * @param specificSource - an explicit specific source identifier of this permission (e.g the id of a user that assigned this permission to current user). + * @param operation - a determinant operator (and/or) for the expected permissions, (e.g user must have all expected permissions). + */ +export function permissionsExist( + userPermissions: AggregatedRolePermission[], + requiredPermissions: RequiredPermission[], + operation = PermissionOperator.and, + specificTarget?: string, + specificSource?: string +): boolean { + // dependent on the operator, choose a predicate function for verification + const predicateFunction = + operation === PermissionOperator.or ? requiredPermissions.some : requiredPermissions.every; + + // using the predicate function , check if the store user permissions contains + // the expected permissions (dependent on the operator) using specific conditions below. + // if specific source is provided, the expected permission's source is ignored. + // the same applies to tspecific target. + return predicateFunction.call(requiredPermissions, (expectedPerm: RequiredPermission) => + userPermissions.some( + permission => + permission.action.toLowerCase() === expectedPerm.action.toLowerCase() && + permission.source === (specificSource || expectedPerm.source) && + permission.object.toLowerCase() === expectedPerm.object.toLowerCase() && + verifyTargets(permission.targets, specificTarget || expectedPerm.target) + ) + ); +} + +function verifyTargets(existingTargets: string[] | undefined, currentTarget: string | undefined) { + if (existingTargets && currentTarget) { + return existingTargets.includes(currentTarget); + } + return existingTargets === undefined && !currentTarget; +} diff --git a/projects/users-groups/src/utils/role-permissions-aggregator.ts b/projects/users-groups/src/utils/role-permissions-aggregator.ts new file mode 100644 index 0000000..ae28142 --- /dev/null +++ b/projects/users-groups/src/utils/role-permissions-aggregator.ts @@ -0,0 +1,52 @@ +import { RolePermission, AggregatedRolePermission } from '../users-groups.interfaces'; + +export const aggregateRolePermissions = ( + permissions: RolePermission[] +): AggregatedRolePermission[] => + permissions.reduce( + (aggregatedPermissions: AggregatedRolePermission[], { target, permissionId, ...rest }) => { + if (!target) { + const permissionExists = aggregatedPermissions.some( + (perm) => + perm.action === rest.action && + perm.object === rest.object && + perm.source === rest.source && + !perm.targets + ); + return permissionExists ? aggregatedPermissions : [...aggregatedPermissions, rest]; + } + + // get permissions of the same type/family with existing targets + const existingPermissionsWithTargets = aggregatedPermissions.filter( + ({ action, object, source, targets }) => + action === rest.action && + object === rest.object && + source === rest.source && + targets && + targets.length > 0 + ); + + // where permissions of the same type do not exist, transform permissions target and add new + if (existingPermissionsWithTargets.length === 0) { + return [...aggregatedPermissions, { ...rest, targets: [target] }]; + } + + // where permissions exist, transform targets by adding to existing target collection + existingPermissionsWithTargets.forEach(({ targets }) => { + if (targets) { + if (!targets.includes(target)) { + targets.push(target); + } + } + }); + + return aggregatedPermissions; + }, + [] as AggregatedRolePermission[] + ); + +export const getPermissionsMap = (permissions: RolePermission[]): Record => + permissions.reduce((dictionary, permission) => { + const { permissionId } = permission; + return { ...dictionary, [permissionId]: permission }; + }, {} as Record); diff --git a/projects/users-groups/tsconfig.lib.json b/projects/users-groups/tsconfig.lib.json new file mode 100644 index 0000000..9258dbc --- /dev/null +++ b/projects/users-groups/tsconfig.lib.json @@ -0,0 +1,30 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "declarationMap": true, + "outDir": "../../out-tsc/lib", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "inlineSources": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "skipLibCheck": true, + "types": [], + "lib": ["dom", "es2018"], + "paths": { + "@cpp/core": ["../../dist/core"] + } + }, + "angularCompilerOptions": { + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true, + "compilationMode": "partial" + }, + "exclude": ["**/*.spec.ts"] +} diff --git a/projects/users-groups/tsconfig.lib.prod.json b/projects/users-groups/tsconfig.lib.prod.json new file mode 100644 index 0000000..2a2faa8 --- /dev/null +++ b/projects/users-groups/tsconfig.lib.prod.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/projects/users-groups/tsconfig.spec.json b/projects/users-groups/tsconfig.spec.json new file mode 100644 index 0000000..6a61a13 --- /dev/null +++ b/projects/users-groups/tsconfig.spec.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": ["jest", "node"] + }, + "include": ["**/*.spec.ts", "**/*.d.ts"] +} diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..6799df5 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,24 @@ +sonar.projectKey=uk.gov.justice.cpp.ui:ui-core +sonar.projectName=@cpp:ui.core + +sonar.projectDescription=CPP UI Core Library +sonar.links.homepage=https://github.com/hmcts/cpp-ui-core +#sonar.links.ci= +#sonar.links.issue= +sonar.links.scm=https://github.com/hmcts/cpp-ui-core +sonar.links.scm_dev=git@github.com:hmcts/cpp-ui-core.git + +sonar.sources=. +sonar.sourceEncoding=UTF-8 +sonar.exclusions=tests.bundle.ts,build/**/*,node_modules/**/*,release/**/*, dist/**/*,documentation/**, projects/**/*, scripts/**/* + +# Optional +#sonar.tests=test/**/*.js +# Tests +sonar.dependencyCheck.reportPath=build/dependency-check/dependency-check-report.xml +sonar.dependencyCheck.htmlReportPath=build/dependency-check/dependency-check-report.html +#sonar.javascript.lcov.reportPaths=build/coverage/jest/lcov.info +sonar.typescript.exclusions=**/node_modules/**,**/bower_components/**,build/**,dist/**,documentation/** +sonar.typescript.lcov.reportPaths=build/coverage/jest/lcov.info +# SonarQube 7.2+ https://docs.sonarqube.org/display/PLUG/Importing+TSLint+issues+for+TypeScript+files +sonar.typescript.tslint.jsonReportPaths=build/lint/tslint.json diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..b2fa136 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "esModuleInterop": true, + "module": "es2015", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "strict": true, + "target": "ES2020", + "typeRoots": ["node_modules/@types", "types"], + "lib": ["es2018", "dom"], + "paths": { + "@cpp/core": ["./projects/core/src"], + "@cpp/reference-data": ["./projects/reference-data/src"], + "@cpp/users-groups": ["./projects/users-groups/src"], + "@cpp/scheduling": ["./projects/scheduling/src"] + }, + "useDefineForClassFields": false + } +}