diff --git a/.eslintrc.yaml b/.eslintrc.yaml index aa20eaa8..8673249c 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -8,4 +8,4 @@ extends: parserOptions: ecmaVersion: 2018 rules: - "@typescript-eslint/no-parameter-properties": off + "@typescript-eslint/no-parameter-properties": off \ No newline at end of file diff --git a/.github/labeler.yml b/.github/labeler.yml index 48b6a92b..3de75a50 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,13 +1,59 @@ repo: - - ./* + - changed-files: + - any-glob-to-any-file: './*' + test: - - src/**/*.spec.ts - - src/**/*.ts.snap + - changed-files: + - any-glob-to-any-file: + - src/**/*.spec.ts + - src/**/*.ts.snap + documentation: - - ./**/*.md + - changed-files: + - any-glob-to-any-file: + - ./**/*.md + +content-item: + - changed-files: + - any-glob-to-any-file: + - ./src/commands/content-item/*.ts + content-repository: - - ./src/commands/content-repository/*.ts + - changed-files: + - any-glob-to-any-file: + - ./src/commands/content-repository/*.ts + content-type: - - ./src/commands/content-type/*.ts + - changed-files: + - any-glob-to-any-file: + - ./src/commands/content-type/*.ts + content-type-schema: - - ./src/commands/content-type-schema/*.ts + - changed-files: + - any-glob-to-any-file: + - ./src/commands/content-type-schema/*.ts + +events: + - changed-files: + - any-glob-to-any-file: + - ./src/commands/events/*.ts + +extension: + - changed-files: + - any-glob-to-any-file: + - ./src/commands/extension/*.ts + +hub: + - changed-files: + - any-glob-to-any-file: + - ./src/commands/hub/*.ts + +search-index: + - changed-files: + - any-glob-to-any-file: + - ./src/commands/search-index/*.ts + +settings: + - changed-files: + - any-glob-to-any-file: + - ./src/commands/settings/*.ts diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index fcfb8dab..7909ac0d 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/labeler@v2 + - uses: actions/labeler@v5 if: github.event.pull_request.head.repo.fork == false with: repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index f689a758..487d5194 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -4,35 +4,24 @@ on: [push, pull_request] jobs: build: - runs-on: ubuntu-latest strategy: matrix: - node-version: [12.x, 14.x, 16.x] + node: [20, 22, 24] steps: - - uses: actions/checkout@v1 - - - name: Cache node modules - uses: actions/cache@v1 - with: - path: node_modules - key: ${{ runner.OS }}-${{ matrix.node-version }}-build-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.OS }}-${{ matrix.node-version }}-build-${{ env.cache-name }}- - ${{ runner.OS }}-${{ matrix.node-version }}-build- - ${{ runner.OS }}-${{ matrix.node-version }}- - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - - name: npm install, build, and test - run: | - npm ci - npm run build --if-present - npm test - env: - CI: true + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + cache: 'npm' + node-version: ${{ matrix.node }} + + - name: npm install, build, and test + run: | + npm ci --ignore-scripts + npm run build --if-present + npm test + env: + CI: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ec2e2561..a059a88b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,36 +3,45 @@ on: branches: - master +permissions: + contents: write + pull-requests: write + id-token: write + name: release-please jobs: release-please: runs-on: ubuntu-latest steps: - - uses: GoogleCloudPlatform/release-please-action@v2 + - uses: googleapis/release-please-action@v4 id: release with: - token: ${{ secrets.GH_REPO_ACCESS }} + token: ${{ secrets.GH_REPO_ACCESS_PUBLIC_REPOS }} release-type: node - package-name: dc-cli - bump-minor-pre-major: true - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 if: ${{ steps.release.outputs.release_created }} - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v4 if: ${{ steps.release.outputs.release_created }} with: - node-version: 14 + cache: 'npm' + node-version-file: '.nvmrc' registry-url: 'https://registry.npmjs.org' - run: | - npm ci + npm ci --ignore-scripts npm run build --if-present if: ${{ steps.release.outputs.release_created }} - run: npm publish - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} if: ${{ steps.release.outputs.release_created }} + - run: | + npm run build:package + ./scripts/compress.sh + gh release upload ${{ steps.release.outputs.tag_name }} ./packages/*.zip + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + if: ${{ steps.release.outputs.release_created }} diff --git a/.gitignore b/.gitignore index 45b399ad..fd2b89b9 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,34 @@ coverage # Temp files temp/ + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# dc-cli outputs +exports \ No newline at end of file diff --git a/.nvmrc b/.nvmrc index 3cacc0b9..250af06b 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -12 \ No newline at end of file +24.10 \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index 0981b7cc..23f256ec 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,6 @@ { "singleQuote": true, - "printWidth": 120 + "printWidth": 120, + "trailingComma": "none", + "arrowParens": "avoid" } diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 00000000..d6931fb2 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1 @@ +{".":"0.30.0"} diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d676b40..8ce3dad4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,246 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [0.30.0](https://github.com/amplience/dc-cli/compare/v0.29.0...v0.30.0) (2025-11-14) + + +### Features + +* content item command improvements ([#239](https://github.com/amplience/dc-cli/issues/239)) ([5d02a0b](https://github.com/amplience/dc-cli/commit/5d02a0bb37824cef154663f9ad8d4016d212ec33)) +* webhooks export / import / delete ([#238](https://github.com/amplience/dc-cli/issues/238)) ([5c95d37](https://github.com/amplience/dc-cli/commit/5c95d3765d17e262bee7035478dd0f57049e6359)) + + +### Bug Fixes + +* unarchive facet bug ([#242](https://github.com/amplience/dc-cli/issues/242)) ([e1f9e70](https://github.com/amplience/dc-cli/commit/e1f9e7063ba5ac887043361509ec6695868c4072)) + +## [0.29.0](https://github.com/amplience/dc-cli/compare/v0.28.0...v0.29.0) (2025-11-11) + + +### Features + +* content sync ([#236](https://github.com/amplience/dc-cli/issues/236)) ([185eb1c](https://github.com/amplience/dc-cli/commit/185eb1cd6cfdf2c7db7718aebd8638883d254c13)) +* manage linked content repositories ([#222](https://github.com/amplience/dc-cli/issues/222)) ([f6c7151](https://github.com/amplience/dc-cli/commit/f6c71514b6b303c20ea67c7788d0b88a27da28e6)) + +## [0.28.0](https://github.com/amplience/dc-cli/compare/v0.27.0...v0.28.0) (2025-10-21) + + +### Features + +* add unpublishing support ([#232](https://github.com/amplience/dc-cli/issues/232)) ([f36eaf6](https://github.com/amplience/dc-cli/commit/f36eaf60620b5b1cc06cbdccff3290d5aaace491)) +* delete extensions ([#233](https://github.com/amplience/dc-cli/issues/233)) ([997a63f](https://github.com/amplience/dc-cli/commit/997a63fb25c1c7d5e5923f56dbdc71effe3644bf)) +* node 24 and trusted publish ([#237](https://github.com/amplience/dc-cli/issues/237)) ([a9be85b](https://github.com/amplience/dc-cli/commit/a9be85bf00234d9920524ac20f7841142e71d5e2)) +* publish queue improvements ([#226](https://github.com/amplience/dc-cli/issues/226)) ([d8750fd](https://github.com/amplience/dc-cli/commit/d8750fd0eeea5360cfa9f90d9ce146d7393cdd3a)) + + +### Bug Fixes + +* installing with ignore scripts flag ([#230](https://github.com/amplience/dc-cli/issues/230)) ([c5a9871](https://github.com/amplience/dc-cli/commit/c5a98714a4d7e8a7aa4586884b6f3210180115ab)) + +## [0.27.0](https://github.com/amplience/dc-cli/compare/v0.26.1...v0.27.0) (2025-09-16) + + +### Features + +* multiple delivery key support for import archive and unarchive ([#223](https://github.com/amplience/dc-cli/issues/223)) ([df427ee](https://github.com/amplience/dc-cli/commit/df427eeb2ae5d465fa808f113564b75881829ca2)) + +## [0.26.1](https://github.com/amplience/dc-cli/compare/v0.26.0...v0.26.1) (2025-08-05) + + +### Bug Fixes + +* using graceful fs to avoid emfile errors ([#220](https://github.com/amplience/dc-cli/issues/220)) ([030a266](https://github.com/amplience/dc-cli/commit/030a266764d2120dc6db0e3fb2e7b0ba40add483)) + +## [0.26.0](https://github.com/amplience/dc-cli/compare/v0.25.0...v0.26.0) (2025-07-29) + + +### Features + +* configurable publish limit ([#216](https://github.com/amplience/dc-cli/issues/216)) ([5d46d39](https://github.com/amplience/dc-cli/commit/5d46d391c7553fd537a467b645c9036b9fe74ef0)) +* optimise publish content items ([#218](https://github.com/amplience/dc-cli/issues/218)) ([6b4c2ca](https://github.com/amplience/dc-cli/commit/6b4c2cae1262ee2c5c0a983fc916afcfc31ec9c5)) +* publish by query ([#208](https://github.com/amplience/dc-cli/issues/208)) ([91673b7](https://github.com/amplience/dc-cli/commit/91673b739075ffedb10626cd0a21997f5d5f8b9a)) +* sync all content types ([#214](https://github.com/amplience/dc-cli/issues/214)) ([45cb604](https://github.com/amplience/dc-cli/commit/45cb604f93a646402c0c70716c442507f878fdde)) +* update to latest management sdk and default to node 22 ([#213](https://github.com/amplience/dc-cli/issues/213)) ([02c850a](https://github.com/amplience/dc-cli/commit/02c850a54333c70fdbdb995bf2c3474b1bedf504)) + +## [0.25.0](https://github.com/amplience/dc-cli/compare/v0.24.1...v0.25.0) (2025-07-02) + + +### Features + +* allow users to use PAT when adding hubs ([#204](https://github.com/amplience/dc-cli/issues/204)) ([6dd1b71](https://github.com/amplience/dc-cli/commit/6dd1b7145d9c9048ce51bb85656183e16cfdba44)) +* hub clean progress ([#211](https://github.com/amplience/dc-cli/issues/211)) ([4a02f15](https://github.com/amplience/dc-cli/commit/4a02f1594c6f52762989e3de1a86db86cf4c9c68)) +* provide progress for long running command actions ([#207](https://github.com/amplience/dc-cli/issues/207)) ([95d7f56](https://github.com/amplience/dc-cli/commit/95d7f568b370b3eedd0a921a1d0dbbecf14892ce)) +* report publish failures correctly and prompt user for continuation ([#209](https://github.com/amplience/dc-cli/issues/209)) ([3f64838](https://github.com/amplience/dc-cli/commit/3f6483862047b4ffe0db2df614fe4687a2be3e06)) + + +### Bug Fixes + +* content Item not found error on import ([#206](https://github.com/amplience/dc-cli/issues/206)) ([8efba5a](https://github.com/amplience/dc-cli/commit/8efba5a40758260aa0b381d99d418457e71d5265)) +* set default auth url ([bd0c727](https://github.com/amplience/dc-cli/commit/bd0c727649c5fb6933d04be0e727d5573a552fdc)) +* set default auth url ([cd504d1](https://github.com/amplience/dc-cli/commit/cd504d1fc2b5600aa44fd4c78327a515bf8dda53)) +* update custom http client to handle client errors ([0c2eda0](https://github.com/amplience/dc-cli/commit/0c2eda035410508a21351176b3fbbe796a0a61da)) +* update custom http client to handle client errors ([a70c8c5](https://github.com/amplience/dc-cli/commit/a70c8c52bc3d8b1da610abf7badc3c7f2f0f7f58)) + +## [0.24.1](https://github.com/amplience/dc-cli/compare/v0.24.0...v0.24.1) (2025-06-11) + + +### Bug Fixes + +* reset axios timeout on retry ([#202](https://github.com/amplience/dc-cli/issues/202)) ([2354dac](https://github.com/amplience/dc-cli/commit/2354dac08668defc6a1936a287ba7e60d86466af)) + +## [0.24.0](https://github.com/amplience/dc-cli/compare/v0.23.0...v0.24.0) (2025-06-04) + + +### Features + +* use a custom dc http client to expand retry codes ([#200](https://github.com/amplience/dc-cli/issues/200)) ([0264247](https://github.com/amplience/dc-cli/commit/0264247baef5fefaaff61709d92d126427e9c8c3)) + +## [0.23.0](https://github.com/amplience/dc-cli/compare/v0.22.0...v0.23.0) (2025-04-09) + + +### Features + +* add support for PAT ([c003017](https://github.com/amplience/dc-cli/commit/c003017a5540abc349924e5532227976b0c35dbb)) + + +### Bug Fixes + +* bad merge on test file ([650a677](https://github.com/amplience/dc-cli/commit/650a6775ff531cbb4ba225b679231147859c92b2)) + +## [0.22.0](https://github.com/amplience/dc-cli/compare/v0.21.0...v0.22.0) (2025-03-19) + + +### Features + +* support ignore schema validation for content item create and update ([#197](https://github.com/amplience/dc-cli/issues/197)) ([fbe49d0](https://github.com/amplience/dc-cli/commit/fbe49d01328b9c83be5ab73a027397b09696b5b4)) + +## [0.21.0](https://github.com/amplience/dc-cli/compare/v0.20.0...v0.21.0) (2025-03-04) + + +### Features + +* generate iso timestamp for errors ([#194](https://github.com/amplience/dc-cli/issues/194)) ([ccc7567](https://github.com/amplience/dc-cli/commit/ccc7567a8717db17fcc3f158a1bc6a2033849235)) + + +### Bug Fixes + +* log network error if response status is missing ([#192](https://github.com/amplience/dc-cli/issues/192)) ([bed6edc](https://github.com/amplience/dc-cli/commit/bed6edc7b3d144ac4dd6a7ade90f7f9d88449d40)) +* retry content hub http requests at the client layer ([#193](https://github.com/amplience/dc-cli/issues/193)) ([6b1966a](https://github.com/amplience/dc-cli/commit/6b1966a3af23e8c07c213545a45045e8b15f77fc)) + +## [0.20.0](https://github.com/amplience/dc-cli/compare/v0.19.1...v0.20.0) (2025-02-27) + + +### ⚠ BREAKING CHANGES + +* maintenance and dependency updates +* Merge pull request #189 from amplience/feature/maintenance-and-dependency-updates + +### Features + +* maintenance and dependency updates ([d170685](https://github.com/amplience/dc-cli/commit/d1706850abb78bc8a0b8260a394838f3c25ced38)) +* Merge pull request [#189](https://github.com/amplience/dc-cli/issues/189) from amplience/feature/maintenance-and-dependency-updates ([d170685](https://github.com/amplience/dc-cli/commit/d1706850abb78bc8a0b8260a394838f3c25ced38)) + + +### Bug Fixes + +* change from artifact to packages ([f1e5171](https://github.com/amplience/dc-cli/commit/f1e5171b268e4aab755705629b2fb46d5c3ecc93)) + + +### Miscellaneous Chores + +* release 0.20.0 ([aeaccf1](https://github.com/amplience/dc-cli/commit/aeaccf1616a419458304ebf7680f79104dd46478)) + +## [0.19.1](https://github.com/amplience/dc-cli/compare/v0.19.0...v0.19.1) (2023-11-14) + + +### Bug Fixes + +* **auth:** 403 errors due to expiring token (dc-management-sdk-js 1.19.1) ([7185795](https://github.com/amplience/dc-cli/commit/718579566f5fd6bfdf7b9e40a5e411e87379efe2)) +* **dc-management-sdk-js:** 1.20.0 bump - retry 429 errors ([02d92d8](https://github.com/amplience/dc-cli/commit/02d92d8838cd077bc3ab2dce6842ef374b122480)) +* **release:** set registry-url for setup-node ([2c077a3](https://github.com/amplience/dc-cli/commit/2c077a376aa13c7bb3bfa50dd7bf52be4781033b)) + +## [0.19.0](https://www.github.com/amplience/dc-cli/compare/v0.18.0...v0.19.0) (2023-02-16) + + +### Features + +* latest (1.18.0) dc-management-sdk-js ([3f8039e](https://www.github.com/amplience/dc-cli/commit/3f8039e47a130d6225dbb09f2d3729fbd5050828)) +* **search indexes:** support for async search index settings ([0e7d5e0](https://www.github.com/amplience/dc-cli/commit/0e7d5e06f498b9f197a92a9d75400bab41434b72)) + + +### Bug Fixes + +* **enrichedsearchindex:** convert the properties to their correct type ([7159361](https://www.github.com/amplience/dc-cli/commit/715936122fe1efd2642767f67ea2b92fc4f3f3d1)) +* **hub:** validateHub respects environment variables ([#163](https://www.github.com/amplience/dc-cli/issues/163)) ([5f35aaf](https://www.github.com/amplience/dc-cli/commit/5f35aafbbf5f18189175affc7680608e1e8d9ed1)) +* **search indexes:** ensuring only pojos are converted to their type ([b237f21](https://www.github.com/amplience/dc-cli/commit/b237f2140047bc9a1e8f8a920625e1370a45a39d)) + +## [0.18.0](https://www.github.com/amplience/dc-cli/compare/v0.17.1...v0.18.0) (2022-10-28) + + +### Features + +* **settings:** overwrite existing preview settings rather than ignoring updates ([#160](https://www.github.com/amplience/dc-cli/issues/160)) ([a5d8dc5](https://www.github.com/amplience/dc-cli/commit/a5d8dc564df0330c231fda1c919bd47e53553c58)) + + +### Bug Fixes + +* **event:** correctly archive events with unscheduled editions ([#159](https://www.github.com/amplience/dc-cli/issues/159)) ([8cfefda](https://www.github.com/amplience/dc-cli/commit/8cfefdab8dde4a3586663adfb071c45ad50a6208)) + +### [0.17.1](https://www.github.com/amplience/dc-cli/compare/v0.17.0...v0.17.1) (2022-10-20) + + +### Bug Fixes + +* **hub:** fix hub commands not being passed credentials ([#157](https://www.github.com/amplience/dc-cli/issues/157)) ([0521428](https://www.github.com/amplience/dc-cli/commit/05214286a573693d2cadbd55ccc2ffdac42aa0b9)) + +## [0.17.0](https://www.github.com/amplience/dc-cli/compare/v0.16.0...v0.17.0) (2022-10-19) + + +### Features + +* **hub:** add environment management commands ([#149](https://www.github.com/amplience/dc-cli/issues/149)) ([2857dac](https://www.github.com/amplience/dc-cli/commit/2857dacca0a1f0a4cebf0b9361944098986f0ee5)) + + +### Bug Fixes + +* **content-item:** enrich items when faceting for archive ([#152](https://www.github.com/amplience/dc-cli/issues/152)) ([2902877](https://www.github.com/amplience/dc-cli/commit/29028770a8fb70b2bb005885b1d2a94f8f01466a)) +* **content-item:** only assume links will be published, not references ([#150](https://www.github.com/amplience/dc-cli/issues/150)) ([56bc1b4](https://www.github.com/amplience/dc-cli/commit/56bc1b47bb0a7d63e19ef5cdc1bc83d99e0daf13)) + +## [0.16.0](https://www.github.com/amplience/dc-cli/compare/v0.15.1...v0.16.0) (2022-09-12) + + +### Features + +* concurrent publish queue with --batchPublish option ([#146](https://www.github.com/amplience/dc-cli/issues/146)) ([632033c](https://www.github.com/amplience/dc-cli/commit/632033cb2339efa4f6207189fd08aaf22a374840)) + +### [0.15.1](https://www.github.com/amplience/dc-cli/compare/v0.15.0...v0.15.1) (2022-05-26) + + +### Bug Fixes + +* **event:** fix event slots list pagination ([#141](https://www.github.com/amplience/dc-cli/issues/141)) ([d3119aa](https://www.github.com/amplience/dc-cli/commit/d3119aad92e45c6147f463ccf9a54c9608c3ffc7)) + +## [0.15.0](https://www.github.com/amplience/dc-cli/compare/v0.14.0...v0.15.0) (2022-05-16) + + +### Features + +* **event:** add event import/export commands and clone step ([#114](https://www.github.com/amplience/dc-cli/issues/114)) ([85a8889](https://www.github.com/amplience/dc-cli/commit/85a8889d7425aaa334c254d5c8204fb37e571841)) + +## [0.14.0](https://www.github.com/amplience/dc-cli/compare/v0.13.0...v0.14.0) (2022-05-05) + + +### Features + +* add regex lookup to type and schema export ([#126](https://www.github.com/amplience/dc-cli/issues/126)) ([93a0cdd](https://www.github.com/amplience/dc-cli/commit/93a0cddec309340ccf88e2abb16ae77de22435ec)) +* use facet request to reduce content fetched when facets in use ([#128](https://www.github.com/amplience/dc-cli/issues/128)) ([34e5223](https://www.github.com/amplience/dc-cli/commit/34e52237f1e84ce11badb00abfce44876ee8977b)) + + +### Bug Fixes + +* allow empty import without error, fix search index export on accounts where it is disabled ([#125](https://www.github.com/amplience/dc-cli/issues/125)) ([cce328b](https://www.github.com/amplience/dc-cli/commit/cce328b964dc581ca2fdc8df399a3a3cd5bb7bbf)) +* **search-index:** fix replica name rewriting ([#124](https://www.github.com/amplience/dc-cli/issues/124)) ([b692416](https://www.github.com/amplience/dc-cli/commit/b692416093140bb9845486fa4bc93e4e26ebd68a)) + ## [0.13.0](https://www.github.com/amplience/dc-cli/compare/v0.12.0...v0.13.0) (2022-01-06) diff --git a/HOW_TO_USE.1 b/HOW_TO_USE.1 index 72739b94..7f8ffd7c 100644 --- a/HOW_TO_USE.1 +++ b/HOW_TO_USE.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "DC\-CLI" "1" "August 2020" "" "" +.TH "DC\-CLI" "1" "January 2022" "" "" . .SH "NAME" \fBdc\-cli\fR \- (Amplience) Dynamic Content command line interface @@ -24,6 +24,35 @@ By default the configuration file is saved into the directory \fB/\.am .P See \fBdc\-cli configure \-\-help\fR for more information\. . +.SH "FACETS" +The content item export, copy, move archive and unarchive commands allow the user to provide a facet string to filter the content that the commands work on\. Multiple of these can be applied at a time, and you can even match on regex string\. Note that you will need to surround your facet in quotes if it contains a space, which will change how backslash escaping works\. +. +.IP "\(bu" 4 +\fBname\fR: Filter on content item label\. Example: \fB\-\-facet "name:exact name match"\fR +. +.IP "\(bu" 4 +\fBschema\fR: Filter on schema ids\. Example: \fB\-\-facet schema:http://example\.com/schema\.json\fR +. +.IP "\(bu" 4 +\fBlocale\fR: Filter on content item locale\. Example: \fB\-\-facet locale:en\-GB\fR +. +.IP "\(bu" 4 +\fBlastModifiedDate\fR: Filter on last modified date\. Example: \fB\-\-facet "lastModifiedDate:Last 7 days"\fR +. +.IP "" 0 +. +.P +Multiple facets can be applied at once when separated by a comma\. Example: \fB\-\-facet "schema:http://example\.com/schema\.json, name:/name regex/"\fR +. +.P +Commas can be escaped with a backslash, if they are used in your values\. The whitespace after a comma is optional\. +. +.SS "PRESET DATE RANGES" +The preset date ranges are the same as DC provides: \- \fBLast 7 days\fR \- \fBLast 14 days\fR \- \fBLast 30 days\fR \- \fBLast 60 days\fR \- \fBOver 60 days\fR +. +.SS "REGEX" +You can use regex values on string fields when filtering content\. They cannot be used on date ranges\. Regex are surronded by two forward slashes: \fB\-\-facet "name:/ends with this$/"\fR +. .SH "SEE ALSO" . .IP "\(bu" 4 diff --git a/README.md b/README.md index 331d7d49..1f1db80b 100644 --- a/README.md +++ b/README.md @@ -10,20 +10,31 @@ Run `dc-cli --help` to get a list of available commands. -- [Installation](#installation) -- [Configuration](#configuration) - - [Options](#options) -- [Command categories](#command-categories) - - [content-type-schema](#content-type-schema) - - [content-type](#content-type) - - [content-item](#content-item) - - [extension](#extension) - - [search-index](#search-index) - - [content-repository](#content-repository) - - [settings](#settings) - - [hub](#hub) -- [Building the CLI](#building-the-cli) -- [Required permissions](#required-permissions) +- [dc-cli](#dc-cli) + - [Description](#description) + - [Installation](#installation) + - [Configuration](#configuration) + - [Options](#options) + - [Examples](#examples) + - [Create/Update configuration file for single hub using client ID and secret](#createupdate-configuration-file-for-single-hub-using-client-id-and-secret) + - [Create/Update configuration file for single hub using personal access token](#createupdate-configuration-file-for-single-hub-using-personal-access-token) + - [Create/Update configuration file for two-hub usage (copy/move/clone)](#createupdate-configuration-file-for-two-hub-usage-copymoveclone) + - [Alternative Configuration using `hub` command](#alternative-configuration-using-hub-command) + - [Command categories](#command-categories) + - [content-type-schema](#content-type-schema) + - [content-type](#content-type) + - [content-item](#content-item) + - [extension](#extension) + - [search-index](#search-index) + - [content-repository](#content-repository) + - [event](#event) + - [settings](#settings) + - [hub](#hub) + - [job](#job) + - [linked-content-repository](#linked-content-repository) + - [webhook](#webhook) + - [Building the CLI](#building-the-cli) + - [Required permissions](#required-permissions) @@ -39,8 +50,13 @@ Or you can download the executable for your operating system on the [releases pa ## Configuration -**dc-cli** requires a valid set of Amplience client credentials (`--clientId` & `--clientSecret`) and hub ID (`--hubId`) to operate. -These parameters must be set using the command `dc-cli configure --clientId --clientSecret --hubId ` before using the CLI. +**dc-cli** requires a valid set of Amplience client credentials and hub ID (`--hubId`) to operate. You can authenticate using either a client ID and secret (`--clientId` & `--clientSecret`) or a personal access token (`--patToken`). + +These parameters must be set using one of the following commands before using the CLI: + +`dc-cli configure --clientId --clientSecret --hubId ` + +`dc-cli configure --patToken --hubId ` Some commands (`content-item copy`, `content-item move`, & `hub-clone`) enable the export and import of content with a single command. These take additional options for the client credentials (`--dstClientId` & `--dstSecret`) and hub ID (`--dstHubId`) of a distinct Dynamic Content hub. If no destination options are provided, the destination for these commands will be the same as the source. @@ -50,28 +66,45 @@ By default the configuration is saved to a file in the directory `/.am ### Options -| Option Name | Type | Description | -| -------------- | ---------------------------------------------------------- | ------------------------------------------------------------ | -| --version | [boolean] | Show version number | -| --clientId | [string]
[required] | Client ID for the source hub | -| --clientSecret | [string]
[required] | Client secret for the source hub | -| --hubId | [string]
[required] | Hub ID for the source hub | -| --config | [string]
[default: "~/.amplience/dc-cli-config.json"] | Path to JSON config file | -| --help | [boolean] | Show help | -| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | -| --dstHubId | [string] | Destination hub ID. If not specified, it will be the same as the source. | +| Option Name | Type | Description | +| -------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------- | +| --version | [boolean] | Show version number | +| --clientId | [string]
[required] | Client ID for the source hub | +| --clientSecret | [string]
[required] | Client secret for the source hub | +| --patToken | [string]
[required] | Personal access token for the source hub | +| --hubId | [string]
[required] | Hub ID for the source hub | +| --config | [string]
[default: "~/.amplience/dc-cli-config.json"] | Path to JSON config file | +| --help | [boolean] | Show help | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| --dstHubId | [string] | Destination hub ID. If not specified, it will be the same as the source. | | --dstClientId | [string] | Destination account's client ID. If not specified, it will be the same as the source. | -| --dstSecret | [string] | Destination account's secret. Must be used alongside dstClientId. | +| --dstSecret | [string] | Destination account's secret. Must be used alongside dstClientId. | #### Examples -##### Create/Update configuration file for single hub +##### Create/Update configuration file for single hub using client ID and secret + +`dc-cli configure --clientId foo --clientSecret bar --hubId baz` -`dc-cli configure --clientId foo --clientId bar --hubId baz` +##### Create/Update configuration file for single hub using personal access token + +`dc-cli configure --patToken foo --hubId baz` ##### Create/Update configuration file for two-hub usage (copy/move/clone) -`dc-cli configure --clientId foo --clientId bar --hubId baz --dstClientId qux --dstSecret quux --dstHubId quuz` +`dc-cli configure --clientId foo --clientSecret bar --hubId baz --dstClientId qux --dstSecret quux --dstHubId quuz` + +#### Alternative Configuration using `hub` command + +Using the [**hub**](docs/HUB.md) subcommand, you can save hub configurations for retrieval later. + +This command adds a hub with the supplied credentials: + +`dc-cli hub add --clientId --clientSecret --hubId ` + +Then, to use the hub, you can refer to it by name or part of the hub ID: + +`dc-cli hub use ` ## Command categories @@ -105,7 +138,7 @@ Before importing, copying, or moving content you must ensure that a valid [conte ### extension -This category includes interactions with Dynamic Content's UI Extensions, and can be used to export and import extensions from an individual hub. +This category includes interactions with Dynamic Content's UI Extensions, and can be used to export, import and delete extensions from an individual hub. [View commands for **extension**](docs/EXTENSION.md) @@ -119,10 +152,16 @@ This category includes interactions with Algolia search indexes for Dynamic Cont This category includes interactions with Dynamic Content's repositories. -These commands can be used to get details for a specific repository, list multiple repositories, or assign or unassign content types from a repository. +These commands can be used to get details for a specific repository, list multiple repositories, or assign or unassign content types from a repository. [View commands for **content-repository**](docs/CONTENT-REPOSITORY.md) +### event + +This category includes interactions with Dynamic Content's events and its constituent parts (Editions, Slots, and Snapshots). These commands can be used to export and import events, and to archive events. + +[View commands for **event**](docs/EVENT.md) + ### settings This category includes interactions with the supporting properties of a Dynamic Content hub. These commands can be used to export and import a hub's breakpoint settings for visualization, preview applications, workflow states, and locales. @@ -133,10 +172,32 @@ This category includes interactions with the supporting properties of a Dynamic This category includes interactions with Dynamic Content's hubs in their entirety. -These commands can be used to copy a hub's settings and content in their entirety to another hub, or to archive all parts of a hub which can be archived. +These commands can be used to copy a hub's settings and content in their entirety to another hub, or to archive all parts of a hub which can be archived. + +Additionally, these commands may be used to store and retrieve hub configurations. [View commands for **hub**](docs/HUB.md) +### job + +This category includes interactions with Dynamic Content jobs. + +[View commands for **job**](docs/JOB.md) + +### linked-content-repository + +This category includes interactions with Dynamic Content's linked content repositories. + +These commands can be used to list multiple linked content repository. + +[View commands for **linked-content-repository**](docs/LINKED-CONTENT-REPOSITORY.md) + +### webhook + +This category includes interactions with Dynamic Content's UI Webhooks, and can be used to export, import and delete webhooks from an individual hub. + +[View commands for **webhook**](docs/WEBHOOK.md) + ## Building the CLI We have included some NPM scripts to help create various installations of the CLI. @@ -147,23 +208,22 @@ We have included some NPM scripts to help create various installations of the CL Outlined below are the detailed permissions required to run each command of the CLI. To request an API key to run the CLI, please contact Amplience support. -| Command | Required ACL(s) | Required Functional Permission(s) | -| ------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------ | -| `configure` | Hub - READ | | -| `content-repositories get ` | Hub - READ | CONTENT:FUNCTIONAL:REPOSITORY:READ | -| `content-repositories list` | Hub - READ | CONTENT:FUNCTIONAL:REPOSITORY:READ | -| `content-repositories assign-content-type ` | ContentRepository - EDIT
Hub - READ | CONTENT:FUNCTIONAL:REPOSITORY:EDIT | -| `content-repositories unassign-content-type ` | ContentRepository - EDIT
Hub - READ | CONTENT:FUNCTIONAL:REPOSITORY:EDIT | -| `content-type get ` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:READ | -| `content-type list` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:READ | -| `content-type register` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:CREATE | -| `content-type sync ` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:EDIT | -| `content-type update ` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:EDIT | +| Command | Required ACL(s) | Required Functional Permission(s) | +| ------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | +| `configure` | Hub - READ | | +| `content-repositories get ` | Hub - READ | CONTENT:FUNCTIONAL:REPOSITORY:READ | +| `content-repositories list` | Hub - READ | CONTENT:FUNCTIONAL:REPOSITORY:READ | +| `content-repositories assign-content-type ` | ContentRepository - EDIT
Hub - READ | CONTENT:FUNCTIONAL:REPOSITORY:EDIT | +| `content-repositories unassign-content-type ` | ContentRepository - EDIT
Hub - READ | CONTENT:FUNCTIONAL:REPOSITORY:EDIT | +| `content-type get ` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:READ | +| `content-type list` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:READ | +| `content-type register` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:CREATE | +| `content-type sync [id]` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:EDIT | +| `content-type update ` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:EDIT | | `content-type import ` | ContentRepository - EDIT
Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:READ
CONTENT:FUNCTIONAL:CONTENT_TYPE:CREATE
CONTENT:FUNCTIONAL:CONTENT_TYPE:EDIT | -| `content-type export ` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:READ | -| `content-type-schema create` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:CREATE | -| `content-type-schema get ` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:READ | -| `content-type-schema list` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:READ | -| `content-type-schema update ` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:EDIT | +| `content-type export ` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:READ | +| `content-type-schema create` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:CREATE | +| `content-type-schema get ` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:READ | +| `content-type-schema list` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:READ | +| `content-type-schema update ` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:EDIT | | `content-type-schema import ` | Hub - READ | CONTENT:FUNCTIONAL:CONTENT_TYPE:READ
CONTENT:FUNCTIONAL:CONTENT_TYPE:CREATE
CONTENT:FUNCTIONAL:CONTENT_TYPE:EDIT | - diff --git a/docs/CONTENT-ITEM.md b/docs/CONTENT-ITEM.md index ab47861f..e13ca27e 100644 --- a/docs/CONTENT-ITEM.md +++ b/docs/CONTENT-ITEM.md @@ -16,17 +16,20 @@ Return to [README.md](../README.md) for information on other command categories. - [Common Options](#common-options) - [Useful Information](#useful-information) - - [Mapping files](#mapping-files) - - [Facets](#facets) - - [Media-link rewriting](#media-link-rewriting) + - [Mapping files](#mapping-files) + - [Facets](#facets) + - [Media-link rewriting](#media-link-rewriting) - [Commands](#commands) - - [export](#export) - - [import](#import) - - [copy](#copy) - - [move](#move) - - [archive](#archive) - - [unarchive](#unarchive) - - [tree](#tree) + - [export](#export) + - [import](#import) + - [copy](#copy) + - [move](#move) + - [archive](#archive) + - [unarchive](#unarchive) + - [tree](#tree) + - [publish](#publish) + - [unpublish](#unpublish) + - [sync](#sync) @@ -49,7 +52,7 @@ The following options are available for all **content-item** commands. When importing content with the DC CLI, this creates or references a mapping file to determine whether the imported content item should be created as new, or if an existing one within the Dynamic Content platform should be updated. -For example exporting a content item (eg `11111111-1111-1111-1111-111111111111`) from one hub then importing it to another for the first time will create a new content item with a randomly generated UUID (eg `22222222-2222-2222-2222-222222222222`). +For example exporting a content item (eg `11111111-1111-1111-1111-111111111111`) from one hub then importing it to another for the first time will create a new content item with a randomly generated UUID (eg `22222222-2222-2222-2222-222222222222`). To instruct the DC CLI on which content item to update with future actions, a mapping between the source and destination is stored in a mapping file. This mapping file will contain an array of every content item mapping identified for jobs using that mapping file. Using the previous examples: @@ -67,8 +70,8 @@ To instruct the DC CLI on which content item to update with future actions, a ma If no mapping file is specified (with the `--mapFile` argument) then a default one will be created, using the destination's resource type (hub, repository, folder) and its ID, and stored within a default location in your user directory. For example: -* Mac: `~/.amplience/imports/hub-111111111111111111111111.json` -* Windows: `%UserProfile%\.amplience\imports\hub-111111111111111111111111.json` +- Mac: `~/.amplience/imports/hub-111111111111111111111111.json` +- Windows: `%UserProfile%\.amplience\imports\hub-111111111111111111111111.json` If a mapping file does not exist at the point of import, then any imported content items will be created as new, and a new mapping file will be created. If a mapping file exists, and was provided with the `--mapFile` argument, then any items found within the mapping file will be updated. Any content items not contained in the mapping file will will be created as new, and will then be added to the mapping file. @@ -119,15 +122,15 @@ dc-cli content-item export #### Options -| Option Name | Type | Description | -| ------------------------------ | ------------------------------------------ | ------------------------------------------------------------ | -| --repoId | [string] | Export content from within a given repository.
Directory structure will start at the specified repository.
Will automatically export all contained folders. | -| --folderId | [string] | Export content from within a given folder.
Directory structure will start at the specified folder.
Can be used in addition to repoId. | +| Option Name | Type | Description | +| ------------------------------ | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| --repoId | [string] | Export content from within a given repository.
Directory structure will start at the specified repository.
Will automatically export all contained folders. | +| --folderId | [string] | Export content from within a given folder.
Directory structure will start at the specified folder.
Can be used in addition to repoId. | | --facet | [string] | Export content matching the given facets.
Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values.
A regex can be provided for text filters, surrounded with forward slashes.
For more examples, see [facets](#FACETS). | -| --schemaId
*(Deprecated)* | [string] | Export content with a given or matching Schema ID.
A regex can be provided, surrounded with forward slashes.
Can be used in combination with other filters.

Deprecated by the [--facet](#facets) option. | -| --name
*(Deprecated)* | [string] | Export content with a given or matching Name.
A regex can be provided, surrounded with forward slashes.
Can be used in combination with other filters.

Deprecated by the [--facet](#facets) option. | -| --publish | [boolean] | When available, export the last published version of a content item rather than its newest version. | -| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| --schemaId
_(Deprecated)_ | [string] | Export content with a given or matching Schema ID.
A regex can be provided, surrounded with forward slashes.
Can be used in combination with other filters.

Deprecated by the [--facet](#facets) option. | +| --name
_(Deprecated)_ | [string] | Export content with a given or matching Name.
A regex can be provided, surrounded with forward slashes.
Can be used in combination with other filters.

Deprecated by the [--facet](#facets) option. | +| --publish | [boolean] | When available, export the last published version of a content item rather than its newest version. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | #### Examples @@ -155,19 +158,20 @@ dc-cli content-item import #### Options -| Option Name | Type | Description | -| ------------------ | ------------------------------------------ | ------------------------------------------------------------ | -| --baseRepo | [string] | Import matching the given repository to the import base directory, by ID.
Folder structure will be followed and replicated from there. | -| --baseFolder | [string] | Import matching the given folder to the import base directory, by ID.
Folder structure will be followed and replicated from there. | -| --mapFile | [string] | Mapping file to use when updating content that already exists.
Updated with any new mappings that are generated. If not present, will be created.
For more information, see [mapping files](#MAPPING-FILES). | -| -f
--force | [boolean] | Overwrite content, create and assign content types, and ignore content with missing types/references without asking. | -| -v
--validate | [boolean] | Only recreate folder structure - content is validated but not imported. | -| --skipIncomplete | [boolean] | Skip any content items that has one or more missing dependancy. | -| --publish | [boolean] | Publish any content items that have an existing publish status in their JSON. | -| --republish | [boolean] | Republish content items regardless of whether the import changed them or not.
(--publish not required) | -| --excludeKeys | [boolean] | Exclude delivery keys when importing content items. | -| --media | [boolean] | Detect and rewrite media links to match assets in the target account's Content Hub. Your client must have Content Hub permissions configured. | -| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| Option Name | Type | Description | +| ------------------------ | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| --baseRepo | [string] | Import matching the given repository to the import base directory, by ID.
Folder structure will be followed and replicated from there. | +| --baseFolder | [string] | Import matching the given folder to the import base directory, by ID.
Folder structure will be followed and replicated from there. | +| --mapFile | [string] | Mapping file to use when updating content that already exists.
Updated with any new mappings that are generated. If not present, will be created.
For more information, see [mapping files](#MAPPING-FILES). | +| -f
--force | [boolean] | Overwrite content, create and assign content types, and ignore content with missing types/references without asking. | +| -v
--validate | [boolean] | Only recreate folder structure - content is validated but not imported. | +| --skipIncomplete | [boolean] | Skip any content items that has one or more missing dependancy. | +| --publish | [boolean] | Publish any content items that have an existing publish status in their JSON. | +| --republish | [boolean] | Republish content items regardless of whether the import changed them or not.
(--publish not required) | +| --excludeKeys | [boolean] | Exclude delivery keys when importing content items. | +| --media | [boolean] | Detect and rewrite media links to match assets in the target account's Content Hub. Your client must have Content Hub permissions configured. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| --ignoreSchemaValidation | [boolean]
[default: false] | Ignore content item schema validation during import | #### Examples @@ -195,27 +199,28 @@ dc-cli content-item copy #### Options -| Option Name | Type | Description | -| ------------------ | ------------------------------------------ | ------------------------------------------------------------ | -| --revertLog | [string] | Path to a log file to revert a copy for.
This will archive the most recently copied resources, and revert updated ones. | -| --srcRepo | [string] | Copy content from within a given repository.
Directory structure will start at the specified repository.
Will automatically export all contained folders. | -| --srcFolder | [string] | Copy content from within a given folder.
Directory structure will start at the specified folder.
Can be used in addition to repoId. | -| --dstRepo | [string] | Copy matching the given repository to the source base directory, by ID.
Folder structure will be followed and replicated from there. | -| --dstFolder | [string] | Copy matching the given folder to the source base directory, by ID.
Folder structure will be followed and replicated from there. | -| --dstHubId | [string] | Destination hub ID.
If not specified, it will be the same as the source. | -| --dstClientId | [string] | Destination account's client ID.
If not specified, it will be the same as the source. | -| --dstSecret | [string] | Destination account's secret.
Must be used alongside dstClientId. | -| --facet | [string] | Export content matching the given facets.
Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values.
A regex can be provided for text filters, surrounded with forward slashes.
For more examples, see [facets](#FACETS). | -| --mapFile | [string] | Mapping file to use when updating content that already exists.
Updated with any new mappings that are generated. If not present, will be created.
For more information, see [mapping files](#MAPPING-FILES). | -| -f
--force | [boolean] | Overwrite content, create and assign content types, and ignore content with missing types/references without asking. | -| -v
--validate | [boolean] | Only recreate folder structure - content is validated but not imported. | -| --skipIncomplete | [boolean] | Skip any content item that has one or more missing dependancy. | -| --lastPublish | [boolean] | When available, export the last published version of a content item rather than its newest version. | -| --publish | [boolean] | Publish any content items that have an existing publish status in their JSON. | -| --republish | [boolean] | Republish content items regardless of whether the import changed them or not.
(--publish not required) | -| --excludeKeys | [boolean] | Exclude delivery keys when importing content items. | -| --media | [boolean] | Detect and rewrite media links to match assets in the target account's DAM.
Your client must have DAM permissions configured. | -| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| Option Name | Type | Description | +| ------------------------ | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| --revertLog | [string] | Path to a log file to revert a copy for.
This will archive the most recently copied resources, and revert updated ones. | +| --srcRepo | [string] | Copy content from within a given repository.
Directory structure will start at the specified repository.
Will automatically export all contained folders. | +| --srcFolder | [string] | Copy content from within a given folder.
Directory structure will start at the specified folder.
Can be used in addition to repoId. | +| --dstRepo | [string] | Copy matching the given repository to the source base directory, by ID.
Folder structure will be followed and replicated from there. | +| --dstFolder | [string] | Copy matching the given folder to the source base directory, by ID.
Folder structure will be followed and replicated from there. | +| --dstHubId | [string] | Destination hub ID.
If not specified, it will be the same as the source. | +| --dstClientId | [string] | Destination account's client ID.
If not specified, it will be the same as the source. | +| --dstSecret | [string] | Destination account's secret.
Must be used alongside dstClientId. | +| --facet | [string] | Export content matching the given facets.
Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values.
A regex can be provided for text filters, surrounded with forward slashes.
For more examples, see [facets](#FACETS). | +| --mapFile | [string] | Mapping file to use when updating content that already exists.
Updated with any new mappings that are generated. If not present, will be created.
For more information, see [mapping files](#MAPPING-FILES). | +| -f
--force | [boolean] | Overwrite content, create and assign content types, and ignore content with missing types/references without asking. | +| -v
--validate | [boolean] | Only recreate folder structure - content is validated but not imported. | +| --skipIncomplete | [boolean] | Skip any content item that has one or more missing dependancy. | +| --lastPublish | [boolean] | When available, export the last published version of a content item rather than its newest version. | +| --publish | [boolean] | Publish any content items that have an existing publish status in their JSON. | +| --republish | [boolean] | Republish content items regardless of whether the import changed them or not.
(--publish not required) | +| --excludeKeys | [boolean] | Exclude delivery keys when importing content items. | +| --media | [boolean] | Detect and rewrite media links to match assets in the target account's DAM.
Your client must have DAM permissions configured. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| --ignoreSchemaValidation | [boolean]
[default: false] | Ignore content item schema validation during copy | #### Examples @@ -243,27 +248,28 @@ dc-cli content-item move #### Options -| Option Name | Type | Description | -| ------------------ | ------------------------------------------ | ------------------------------------------------------------ | -| --revertLog | [string] | Path to a log file to revert a copy for.
This will archive the most recently copied resources, and revert updated ones. | -| --srcRepo | [string] | Copy content from within a given repository.
Directory structure will start at the specified repository.
Will automatically export all contained folders. | -| --srcFolder | [string] | Copy content from within a given folder.
Directory structure will start at the specified folder.
Can be used in addition to repoId. | -| --dstRepo | [string] | Copy matching the given repository to the source base directory, by ID.
Folder structure will be followed and replicated from there. | -| --dstFolder | [string] | Copy matching the given folder to the source base directory, by ID.
Folder structure will be followed and replicated from there. | -| --dstHubId | [string] | Destination hub ID.
If not specified, it will be the same as the source. | -| --dstClientId | [string] | Destination account's client ID.
If not specified, it will be the same as the source. | -| --dstSecret | [string] | Destination account's secret.
Must be used alongside dstClientId. | -| --facet | [string] | Export content matching the given facets.
Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values.
A regex can be provided for text filters, surrounded with forward slashes.
For more examples, see [facets](#FACETS). | -| --mapFile | [string] | Mapping file to use when updating content that already exists.
Updated with any new mappings that are generated. If not present, will be created.
For more information, see [mapping files](#MAPPING-FILES). | -| -f
--force | [boolean] | Overwrite content, create and assign content types, and ignore content with missing types/references without asking. | -| -v
--validate | [boolean] | Only recreate folder structure - content is validated but not imported. | -| --skipIncomplete | [boolean] | Skip any content item that has one or more missing dependancy. | -| --lastPublish | [boolean] | When available, export the last published version of a content item rather than its newest version. | -| --publish | [boolean] | Publish any content items that have an existing publish status in their JSON. | -| --republish | [boolean] | Republish content items regardless of whether the import changed them or not.
(--publish not required) | -| --excludeKeys | [boolean] | Exclude delivery keys when importing content items. | -| --media | [boolean] | Detect and rewrite media links to match assets in the target account's DAM.
Your client must have DAM permissions configured. | -| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| Option Name | Type | Description | +| ------------------------ | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| --revertLog | [string] | Path to a log file to revert a copy for.
This will archive the most recently copied resources, and revert updated ones. | +| --srcRepo | [string] | Copy content from within a given repository.
Directory structure will start at the specified repository.
Will automatically export all contained folders. | +| --srcFolder | [string] | Copy content from within a given folder.
Directory structure will start at the specified folder.
Can be used in addition to repoId. | +| --dstRepo | [string] | Copy matching the given repository to the source base directory, by ID.
Folder structure will be followed and replicated from there. | +| --dstFolder | [string] | Copy matching the given folder to the source base directory, by ID.
Folder structure will be followed and replicated from there. | +| --dstHubId | [string] | Destination hub ID.
If not specified, it will be the same as the source. | +| --dstClientId | [string] | Destination account's client ID.
If not specified, it will be the same as the source. | +| --dstSecret | [string] | Destination account's secret.
Must be used alongside dstClientId. | +| --facet | [string] | Export content matching the given facets.
Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values.
A regex can be provided for text filters, surrounded with forward slashes.
For more examples, see [facets](#FACETS). | +| --mapFile | [string] | Mapping file to use when updating content that already exists.
Updated with any new mappings that are generated. If not present, will be created.
For more information, see [mapping files](#MAPPING-FILES). | +| -f
--force | [boolean] | Overwrite content, create and assign content types, and ignore content with missing types/references without asking. | +| -v
--validate | [boolean] | Only recreate folder structure - content is validated but not imported. | +| --skipIncomplete | [boolean] | Skip any content item that has one or more missing dependancy. | +| --lastPublish | [boolean] | When available, export the last published version of a content item rather than its newest version. | +| --publish | [boolean] | Publish any content items that have an existing publish status in their JSON. | +| --republish | [boolean] | Republish content items regardless of whether the import changed them or not.
(--publish not required) | +| --excludeKeys | [boolean] | Exclude delivery keys when importing content items. | +| --media | [boolean] | Detect and rewrite media links to match assets in the target account's DAM.
Your client must have DAM permissions configured. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| --ignoreSchemaValidation | [boolean]
[default: false] | Ignore content item schema validation during move | #### Examples @@ -289,18 +295,19 @@ dc-cli content-item archive [id] #### Options -| Option Name | Type | Description | -| ------------------------------- | ------------------------------------------ | ------------------------------------------------------------ | -| --repoId | [string] | The ID of a content repository to search items in to be archived. | -| --folderId | [string] | The ID of a folder to search items in to be archived. | -| --facet | [string] | Export content matching the given facets.
Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values.
A regex can be provided for text filters, surrounded with forward slashes.
For more examples, see [facets](#FACETS). | -| --name
*(Deprecated)* | [string] | The name of a Content Item to be archived.
A regex can be provided to select multiple items with similar or matching names (eg /.header/).
A single --name option may be given to match a single content item pattern.
Multiple --name options may be given to match multiple content items patterns at the same time, or even multiple regex.

Deprecated by the [--facet](#facets) option. | -| --contentType
(Deprecated) | [string] | A pattern which will only archive content items with a matching Content Type Schema ID.
A single --contentType option may be given to match a single schema id pattern.
Multiple --contentType options may be given to match multiple schema patterns at the same time.

Deprecated by the [--facet](#facets) option. | -| --revertLog | [string] | Path to a log file containing content items unarchived in a previous run of the unarchive command.
When provided, archives all content items listed as UNARCHIVE in the log file. | -| -f
--force | [boolean] | If present, there will be no confirmation prompt before archiving the found content. | -| -s
--silent | [boolean] | If present, no log file will be produced. | -| --ignoreError | [boolean] | If present, archive requests that fail will not abort the process. | -| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| Option Name | Type | Description | +| ------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| --repoId | [string] | The ID of a content repository to search items in to be archived. | +| --folderId | [string] | The ID of a folder to search items in to be archived. | +| --facet | [string] | Export content matching the given facets.
Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values.
A regex can be provided for text filters, surrounded with forward slashes.
For more examples, see [facets](#FACETS). | +| --name
_(Deprecated)_ | [string] | The name of a Content Item to be archived.
A regex can be provided to select multiple items with similar or matching names (eg /.header/).
A single --name option may be given to match a single content item pattern.
Multiple --name options may be given to match multiple content items patterns at the same time, or even multiple regex.

Deprecated by the [--facet](#facets) option. | +| --contentType
(Deprecated) | [string] | A pattern which will only archive content items with a matching Content Type Schema ID.
A single --contentType option may be given to match a single schema id pattern.
Multiple --contentType options may be given to match multiple schema patterns at the same time.

Deprecated by the [--facet](#facets) option. | +| --revertLog | [string] | Path to a log file containing content items unarchived in a previous run of the unarchive command.
When provided, archives all content items listed as UNARCHIVE in the log file. | +| -f
--force | [boolean] | If present, there will be no confirmation prompt before archiving the found content. | +| -s
--silent | [boolean] | If present, no log file will be produced. | +| --ignoreError | [boolean] | If present, archive requests that fail will not abort the process. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| --ignoreSchemaValidation | [boolean]
[default: false] | Ignore content item schema validation during archive | #### Examples @@ -326,18 +333,19 @@ dc-cli content-item unarchive [id] #### Options -| Option Name | Type | Description | -| ------------------------------- | ------------------------------------------ | ------------------------------------------------------------ | -| --repoId | [string] | The ID of a content repository to search items in to be unarchived. | -| --folderId | [string] | The ID of a folder to search items in to be unarchived. | -| --facet | [string] | Export content matching the given facets.
Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values.
A regex can be provided for text filters, surrounded with forward slashes.
For more examples, see [facets](#FACETS). | -| --name
*(Deprecated)* | [string] | The name of a Content Item to be unarchived.
A regex can be provided to select multiple items with similar or matching names (eg /.header/).
A single --name option may be given to match a single content item pattern.
Multiple --name options may be given to match multiple content items patterns at the same time, or even multiple regex.

Deprecated by the [--facet](#facets) option. | -| --contentType
(Deprecated) | [string] | A pattern which will only unarchive content items with a matching Content Type Schema ID.
A single --contentType option may be given to match a single schema id pattern.
Multiple --contentType options may be given to match multiple schema patterns at the same time.

Deprecated by the [--facet](#facets) option. | -| --revertLog | [string] | Path to a log file containing content items archived in a previous run of the archive command.
When provided, archives all content items listed as ARCHIVE in the log file. | -| -f
--force | [boolean] | If present, there will be no confirmation prompt before unarchiving the found content. | -| -s
--silent | [boolean] | If present, no log file will be produced. | -| --ignoreError | [boolean] | If present, unarchive requests that fail will not abort the process. | -| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| Option Name | Type | Description | +| ------------------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| --repoId | [string] | The ID of a content repository to search items in to be unarchived. | +| --folderId | [string] | The ID of a folder to search items in to be unarchived. | +| --facet | [string] | Export content matching the given facets.
Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values.
A regex can be provided for text filters, surrounded with forward slashes.
For more examples, see [facets](#FACETS). | +| --name
_(Deprecated)_ | [string] | The name of a Content Item to be unarchived.
A regex can be provided to select multiple items with similar or matching names (eg /.header/).
A single --name option may be given to match a single content item pattern.
Multiple --name options may be given to match multiple content items patterns at the same time, or even multiple regex.

Deprecated by the [--facet](#facets) option. | +| --contentType
(Deprecated) | [string] | A pattern which will only unarchive content items with a matching Content Type Schema ID.
A single --contentType option may be given to match a single schema id pattern.
Multiple --contentType options may be given to match multiple schema patterns at the same time.

Deprecated by the [--facet](#facets) option. | +| --revertLog | [string] | Path to a log file containing content items archived in a previous run of the archive command.
When provided, archives all content items listed as ARCHIVE in the log file. | +| -f
--force | [boolean] | If present, there will be no confirmation prompt before unarchiving the found content. | +| -s
--silent | [boolean] | If present, no log file will be produced. | +| --ignoreError | [boolean] | If present, unarchive requests that fail will not abort the process. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| --ignoreSchemaValidation | [boolean]
[default: false] | Ignore content item schema validation during unarchive | #### Examples @@ -370,3 +378,170 @@ The tree command only uses [common options](#Common Options) ##### Generate a content item tree for a filesystem directory `dc-cli content-item tree ./myDirectory/content` + +### publish + +Publishes content items to a content hub. You can publish all items or specify individual content items by ID. + +```bash +dc-cli content-item publish [id] +``` + +If no `id` is provided, all content items in all content repositories in the specified hub will be published. + +--- + +#### Positionals + +| Argument | Description | +| -------- | --------------------------------------------------------------------------------------------------------------------------- | +| `id` | The ID of a content item to be published. If omitted, all content items in all repositories will be published. _(Optional)_ | + +--- + +#### Options + +| Option | Alias | Description | +| ---------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--repoId` | | The ID of a content repository to restrict publishing scope. _(Optional)_ | +| `--folderId` | | The ID of a folder to restrict publishing scope. _(Optional)_ | +| `--facet` | | Filter content using facets. Format:
`label:example name,locale:en-GB`
Regex supported with `/pattern/`.
See README for more examples. | +| `-f`, `--force` | | Skip confirmation prompts before publishing. | +| `-s`, `--silent` | | Disable log file creation. | +| `--logFile` | | Path to write the log file.
Default: `(log_filename)` | + +--- + +#### Examples + +##### Publish a specific content item by ID + +```bash +dc-cli content-item publish ba967c23-4c22-4617-a009-0f976d77b81c +``` + +##### Publish all content in a specific repository + +```bash +dc-cli content-item publish --repoId 67d1c1cf642fa239dbe15165 +``` + +##### Use facets to publish filtered content + +```bash +dc-cli content-item publish --facet "locale:en-GB,label:homepage" +``` + +### unpublish + +Unpublishes content items to a content hub. You can unpublish all items or specify individual content items by ID. + +```bash +dc-cli content-item unpublish [id] +``` + +If no `id` is provided, all content items in all content repositories in the specified hub will be unpublished. + +--- + +#### Positionals + +| Argument | Description | +| -------- | --------------------------------------------------------------------------------------------------------------------------- | +| `id` | The ID of a content item to be published. If omitted, all content items in all repositories will be published. _(Optional)_ | + +--- + +#### Options + +| Option | Alias | Description | +| ---------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--repoId` | | The ID of a content repository to restrict unpublishing scope. _(Optional)_ | +| `--folderId` | | The ID of a folder to restrict unpublishing scope. _(Optional)_ | +| `--facet` | | Filter content using facets. Format:
`label:example name,locale:en-GB`
Regex supported with `/pattern/`.
See README for more examples. | +| `-f`, `--force` | | Skip confirmation prompts before unpublishing. | +| `-s`, `--silent` | | Disable log file creation. | +| `--logFile` | | Path to write the log file.
Default: `(log_filename)` | + +--- + +#### Examples + +##### Unpublish a specific content item by ID + +```bash +dc-cli content-item unpublish ba967c23-4c22-4617-a009-0f976d77b81c +``` + +##### Unpublish all content in a specific repository + +```bash +dc-cli content-item unpublish --repoId 67d1c1cf642fa239dbe15165 +``` + +##### Use facets to unpublish filtered content + +```bash +dc-cli content-item unpublish --facet "locale:en-GB,label:homepage" +``` + +### sync + +> **_NOTES:_** +> +> - The Content sync entitlement must be enabled on your organisation. +> - Authentication must be via PAT Token with the role associated being developer or higher. +> - Repository mapping must be setup before using this command. +> - The destination hub must have Ignore Schema Validation enabled. + +Sync content items between content hubs. You can sync all items or specify individual content items by ID. + +```bash +dc-cli content-item sync [id] --destinationHubId +``` + +If no `id` is provided, all content items in all content repositories in the specified hub will be unpublished. + +--- + +#### Positionals + +| Argument | Description | +| -------- | --------------------------------------------------------------------------------------------------------------------------- | +| `id` | The ID of a content item to be published. If omitted, all content items in all repositories will be published. _(Optional)_ | + +--- + +#### Options + +| Option | Alias | Description | +| -------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--destinationHubId` | | The destination hub ID to sync the content item with | +| `--repoId` | | The ID of a content repository to restrict sync scope. _(Optional)_ | +| `--folderId` | | The ID of a folder to restrict sync scope. _(Optional)_ | +| `--facet` | | Filter content using facets. Format:
`label:example name,locale:en-GB`
Regex supported with `/pattern/`.
See README for more examples. | +| `-f`, `--force` | | Skip confirmation prompts before sync. | +| `-s`, `--silent` | | Disable log file creation. | +| `--logFile` | | Path to write the log file.
Default: `(log_filename)` | + +--- + +#### Examples + +##### Sync a specific content item by ID + +```bash +dc-cli content-item sync ba967c23-4c22-4617-a009-0f976d77b81c --destinationHubId 1908eb70436d553464f48cb3 +``` + +##### Sync all content in a specific repository + +```bash +dc-cli content-item sync --repoId 67d1c1cf642fa239dbe15165 --destinationHubId 1908eb70436d553464f48cb3 +``` + +##### Use facets to sync filtered content + +```bash +dc-cli content-item sync --facet "locale:en-GB,label:homepage" --destinationHubId 1908eb70436d553464f48cb3 +``` diff --git a/docs/CONTENT-TYPE.md b/docs/CONTENT-TYPE.md index 12729b66..07524db9 100644 --- a/docs/CONTENT-TYPE.md +++ b/docs/CONTENT-TYPE.md @@ -54,14 +54,14 @@ dc-cli content-type archive [id] #### Options -| Option Name | Type | Description | -| ---------------- | ------------------------------------------ | ------------------------------------------------------------ | +| Option Name | Type | Description | +| ---------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | --schemaId | [string] | The Schema ID of a Content Type's Schema to be archived.
A regex can be provided to select multiple types with similar or matching schema IDs (eg /.header.\.json/).
A single --schemaId option may be given to match a single content type schema.
Multiple --schemaId options may be given to match multiple content type schemas at the same time. | -| --revertLog | [string] | Path to a log file containing content unarchived in a previous run of the unarchive command.
When provided, archives all types listed as unarchived in the log file. | -| -f
--force | [boolean] | If present, there will be no confirmation prompt before archiving the found content. | -| -s
--silent | [boolean] | If present, no log file will be produced. | -| --ignoreError | [boolean] | If present, unarchive requests that fail will not abort the process. | -| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| --revertLog | [string] | Path to a log file containing content unarchived in a previous run of the unarchive command.
When provided, archives all types listed as unarchived in the log file. | +| -f
--force | [boolean] | If present, there will be no confirmation prompt before archiving the found content. | +| -s
--silent | [boolean] | If present, no log file will be produced. | +| --ignoreError | [boolean] | If present, unarchive requests that fail will not abort the process. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | #### Examples @@ -85,12 +85,12 @@ dc-cli content-type export #### Options -| Option Name | Type | Description | -| --------------- | ------------------------------------------ | ------------------------------------------------------------ | +| Option Name | Type | Description | +| --------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | --schemaId | [string] | The Schema ID of a Content Type to be exported.
If no --schemaId option is given, all content types for the hub are exported.
A single --schemaId option may be given to export a single content type.
Multiple --schemaId options may be given to export multiple content types at the same time. | -| -f
--force | [boolean] | Overwrite content types without asking. | -| --archived | [boolean] | If present, archived content types will also be considered. | -| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| -f
--force | [boolean] | Overwrite content types without asking. | +| --archived | [boolean] | If present, archived content types will also be considered. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | #### Examples @@ -213,7 +213,7 @@ dc-cli content-type register Synchronises a content type, so that it matches the present version of its registered schema. ``` -dc-cli content-type sync +dc-cli content-type sync [id] ``` #### Options @@ -224,6 +224,10 @@ dc-cli content-type sync #### Examples +##### Synchronise all content types with their content type schemas + +`dc-cli content-type sync` + ##### Synchronise content type with ID of 'foo' with its content type schema `dc-cli content-type sync foo` @@ -238,14 +242,14 @@ dc-cli content-type unarchive [id] #### Options -| Option Name | Type | Description | -| ---------------- | ------------------------------------------ | ------------------------------------------------------------ | +| Option Name | Type | Description | +| ---------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | --schemaId | [string] | The Schema ID of a Content Type's Schema to be unarchived.
A regex can be provided to select multiple types with similar or matching schema IDs (eg /.header.\.json/).
A single --schemaId option may be given to match a single content type schema.
Multiple --schemaId options may be given to match multiple content type schemas at the same time. | -| --revertLog | [string] | Path to a log file containing content archived in a previous run of the archive command.
When provided, unarchives all types listed as archived in the log file. | -| -f
--force | [boolean] | If present, there will be no confirmation prompt before unarchiving the found content. | -| -s
--silent | [boolean] | If present, no log file will be produced. | -| --ignoreError | [boolean] | If present, unarchive requests that fail will not abort the process. | -| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| --revertLog | [string] | Path to a log file containing content archived in a previous run of the archive command.
When provided, unarchives all types listed as archived in the log file. | +| -f
--force | [boolean] | If present, there will be no confirmation prompt before unarchiving the found content. | +| -s
--silent | [boolean] | If present, no log file will be produced. | +| --ignoreError | [boolean] | If present, unarchive requests that fail will not abort the process. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | #### Examples @@ -287,4 +291,4 @@ dc-cli content-type update ##### Add a card when updating a content type -`dc-cli content-type update foo —-cards.0.label "bar" —-cards.0.templatedUri "https://schema.localhost.com/baz" —-cards.0.default true` \ No newline at end of file +`dc-cli content-type update foo —-cards.0.label "bar" —-cards.0.templatedUri "https://schema.localhost.com/baz" —-cards.0.default true` diff --git a/docs/EVENT.md b/docs/EVENT.md new file mode 100644 index 00000000..ef116615 --- /dev/null +++ b/docs/EVENT.md @@ -0,0 +1,205 @@ +# event + +## Description + +The **event** category includes interactions with Dynamic Content's events and its constituent parts (Editions, Slots, and Snapshots). These commands can be used to export and import events, and to archive events. + +Run `dc-cli event --help` to get a list of available commands. + +Return to [README.md](../README.md) for information on other command categories. + + + +- [Common Options](#common-options) +- [Useful Information](#useful-information) + - [Export & Import limitations](#export--import-limitations) + - [Mapping files](#mapping-files) + +- [Commands](#commands) + - [archive](#archive) + - [export](#export) + - [import](#import) + + + +## Common Options + +The following options are available for all **event** commands. + +| Option Name | Type | Description | +| -------------- | ---------------------------------------------------------- | -------------------------------- | +| --version | [boolean] | Show version number | +| --clientId | [string]
[required] | Client ID for the source hub | +| --clientSecret | [string]
[required] | Client secret for the source hub | +| --hubId | [string]
[required] | Hub ID for the source hub | +| --config | [string]
[default: "~/.amplience/dc-cli-config.json"] | Path to JSON config file | +| --help | [boolean] | Show help | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | + +## Useful Information + +### Export & Import limitations + +When exporting and importing events with the DC CLI, it is important to understand that these commands have some limitations in regards to the snapshot components of events. + +Events, Editions, and Slots will be exported and imported much like with the other export and import commands in the CLI. However the most granular part of an event in Dynamic Content, the Snapshot, is a representation of a content item exactly as it appears at the point when it was added to an edition using the content browser, or when it was saved to an edition in the production view. + +Due to this nature of snapshots, the event import command will not always result in an exact copy of the events exported with the event export command. Whilst the properties of the parent edition and event will match those of the source, the snapshots will be created as new. If a snapshotted content item in the source hub's exported events have been updated since the snapshot was created, then it will be the updated version of that content item which will be created as snapshots in the destination hub. + +Snapshots can still optionally be exported to your file system by passing the `--snapshots` argument with your export command, however these will not be used during import and would only be used for reference purposes. + +The below table details what will and will not be included with the export and import commands: + +| Component | Exported with `export` command? | Imported with `import` command? | +| --------- | --------------------------------------------- | ------------------------------------------------------------ | +| Events | Yes | Yes | +| Editions | Yes | Yes | +| Slots | Yes | Yes | +| Snapshots | Yes*

(With `--snapshots` argument) | No

Snapshots are always created from the latest version of content items in the destination hub. | + +If you accept the above limitations and wish use the import command, you must pass the `--acceptSnapshotLimits` argument along with any others. + +### Mapping files + +When importing events with the DC CLI, this creates or references a mapping file to determine whether the imported event should be created as new, or if an existing one within the Dynamic Content platform should be updated. + +For example exporting an event (eg `111111111111111111111111`) from one hub then importing it to another for the first time will create a new event with a randomly generated UUID (eg `222222222222222222222222`). + +To instruct the DC CLI on which event to update with future actions, a mapping between the source and destination is stored in a mapping file. This mapping file will contain an array of every event mapping identified for jobs using that mapping file, along with its constituent parts (editions, slots, and snapshots). Using the previous examples: + +``` +{ + "contentItems": [ + [ + "111111111111111111111111", + "222222222222222222222222" + ] + ], + "workflowStates": [], + "events": [ + [ + "111111111111111111111111", + "222222222222222222222222" + ] + ], + "editions": [ + [ + "111111111111111111111111", + "222222222222222222222222" + ] + ], + "slots": [ + [ + "111111111111111111111111", + "222222222222222222222222" + ] + ], + "snapshots": [ + [ + "111111111111111111111111", + "222222222222222222222222" + ] + ] +} +``` + +If no mapping file is specified (with the `--mapFile` argument) then a default one will be created or updated, using the destination's resource type (hub) and its ID, and stored within a default location in your user directory. For example: + +* Mac: `~/.amplience/imports/hub-111111111111111111111111.json` +* Windows: `%UserProfile%\.amplience\imports\hub-111111111111111111111111.json` + +If a mapping file does not exist at the point of import, then any imported events will be created as new, and a new mapping file will be created. If a mapping file exists, and was provided with the `--mapFile` argument, then any events found within the mapping file will be updated. Any events not contained in the mapping file will will be created as new, and will then be added to the mapping file. + +Content items referenced within your events' slots are not imported with the `event import` command, and will need to exist in the destination hub beforehand. Content item references will be reliant on existing mappings from a previous [content item](CONTENT-ITEM.md) import, though the command will try to look up the original content item IDs if no mapping is present (for same hub export/import use cases). + +## Commands + +### archive + +Archives events and their child edition in the targeted Dynamic Content hub, and will also unschedule them if they have not yet started. + +This command requires either an event ID or name to filter, and will not archive any events if no filter is provided. + +``` +dc-cli event archive [id] +``` + +#### Options + +| Option Name | Type | Description | +| ----------------- | --------- | ------------------------------------------------------------ | +| --name | [string] | The name of an Event to be archived.
A regex can be provided to select multiple items with similar or matching names (eg /.header/).
A single --name option may be given to match a single event pattern.
Multiple --name options may be given to match multiple events' patterns at the same time, or even multiple regex. | +| -f,
--force | [boolean] | If present, there will be no confirmation prompt before archiving the found content. | +| -s,
--silent | [boolean] | If present, no log file will be produced. | + +#### Examples + +##### Archive event with the ID of "foo" + +`dc-cli event archive foo` + +##### Archive all events with "Christmas" in their name + +`dc-cli event archive --name "/Christmas/"` + +### export + +Exports events from the targeted Dynamic Content hub into the specified filesystem location. + +We recommend reading about [snapshots and DC CLI](#snapshots-and-dc-cli) before exporting or importing events. + +``` +dc-cli event export +``` + +#### Options + +| Option Name | Type | Description | +| ----------- | --------- | ------------------------------------------------------------ | +| --id | [string] | Export a single event by ID, rather then fetching all of them. | +| --fromDate | [string] | Start date for filtering events.
Either "NOW" or in the format "\:\", example: "-7:DAYS". | +| --toDate | [string] | To date for filtering events.
Either "NOW" or in the format "\:\", example: "-7:DAYS". | +| --snapshots | [boolean] | Save content snapshots with events, in subfolder "snapshots/". | + +#### Examples + +##### Export all events from a Hub + +`dc-cli event export ./myDirectory/event` + +##### Export all events which start 7 days from now from a Hub + +`dc-cli event export ./myDirectory/event --fromDate "+7:DAYS"` + +### import + +Imports events from the specified filesystem location to the targeted Dynamic Content hub. + +We recommend reading about [snapshots and DC CLI](#snapshots-and-dc-cli) before exporting or importing events. + +Before importing events you must ensure that a valid [content item](#CONTENT-ITEM.md) exists in the destination hub for each content item contained within each event, and contains an appropriate mapping within the [mapping file](#mapping-files). + +``` +dc-cli event import +``` + +#### Options + +| Option Name | Type | Description | +| ---------------------- | --------- | ------------------------------------------------------------ | +| --acceptSnapshotLimits | [boolean] | Must be passed to use the event import command.
Only use this command if you fully understand its [limitations](#export--import-limitations). | +| --mapFile | [string] | Mapping file to use when updating content that already exists.
Updated with any new mappings that are generated.
If not present, will be created.
For more information, see [mapping files](#MAPPING-FILES). | +| -f
--force | [boolean] | Overwrite existing events, editions, slots and snapshots without asking. | +| --schedule | [boolean] | Schedule events in the destination repo if they are scheduled in the source.
If any new or updated scheduled events started in the past, they will be moved to happen at the time of import.
If they ended in the past, they will be skipped by default. | +| --catchup | [boolean] | Scheduling events that ended in the past will move to the current date, so that their publishes run. | +| --originalIds | [boolean] | Use original IDs. | + +#### Examples + +##### Import events from the filesystem + +`dc-cli event import ./myDirectory/event --acceptSnapshotLimits` + +##### Specify a mapping file when importing + +`dc-cli event import ./myDirectory/event --mapFile ./myDirectory/mappingFile.json --acceptSnapshotLimits` \ No newline at end of file diff --git a/docs/EXTENSION.md b/docs/EXTENSION.md index 4254abe7..d1c690c5 100644 --- a/docs/EXTENSION.md +++ b/docs/EXTENSION.md @@ -14,6 +14,7 @@ Return to [README.md](../README.md) for information on other command categories. - [Commands](#commands) - [export](#export) - [import](#import) + - [delete](#delete) @@ -43,10 +44,11 @@ dc-cli extension export #### Options -| Option Name | Type | Description | -| --------------- | --------- | ------------------------------------------------------------ | -| --id | [string] | The ID of an Extension to be exported.
If no --id option is given, all extensions for the hub are exported.
A single --id option may be given to export a single extension.
Multiple --id options may be given to export multiple extensions at the same time. | -| -f
--force | [boolean] | Overwrite extensions without asking. | +| Option Name | Type | Description | +| --------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| --id | [string] | The ID of an Extension to be exported.
If no --id option is given, all extensions for the hub are exported.
A single --id option may be given to export a single extension.
Multiple --id options may be given to export multiple extensions at the same time. | +| -f
--force | [boolean] | Overwrite extensions without asking. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | #### Examples @@ -76,3 +78,36 @@ The import command only uses [common options](#Common Options) `dc-cli extension import ./myDirectory/extension` +### delete + +Deletes extensions from the targeted Dynamic Content hub. + +``` +dc-cli extension delete +``` + +#### Options + +| Option Name | Type | Description | +| --------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| --id | [string] | The ID of an Extension to be deleted.
If no --id option is given, all extensions for the hub are deleted.
A single --id option may be given to delete a single extension.
Multiple --id options may be given to delete multiple extensions at the same time. | +| -f
--force | [boolean] | Delete extensions without asking. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | + +#### Examples + +##### Delete all extensions from a Hub + +`dc-cli extension delete` + +##### Delete a single extension with the ID of 'foo' + +`dc-cli extension delete foo` + +or + +`dc-cli extension delete --id foo` + +##### Delete multiple extensions with the IDs of 'foo' & 'bar' + +`dc-cli extension delete --id foo --id bar` diff --git a/docs/HUB.md b/docs/HUB.md index 17558ccd..5f451a33 100644 --- a/docs/HUB.md +++ b/docs/HUB.md @@ -4,7 +4,7 @@ The **hub** command category includes interactions with Dynamic Content's hubs in their entirety. -These commands can be used to copy a hub's settings and content in their entirety to another hub, or to archive all parts of a hub which can be archived. +These commands can be used to copy a hub's settings and content in their entirety to another hub, or to archive all parts of a hub which can be archived. Run `dc-cli hub --help` to get a list of available commands. @@ -14,11 +14,15 @@ Return to [README.md](../README.md) for information on other command categories. - [Common Options](#common-options) - [Useful Information](#useful-information) - - [Mapping files](#mapping-files) - - [Media-link rewriting](#media-link-rewriting) + - [Mapping files](#mapping-files) + - [Media-link rewriting](#media-link-rewriting) - [Commands](#commands) - - [clone](#clone) - - [clean](#clean) + - [clone](#clone) + - [clean](#clean) + - [add](#add) + - [list](#list) + - [ls](#list) + - [use](#use) @@ -26,16 +30,16 @@ Return to [README.md](../README.md) for information on other command categories. The following options are available for all **hub** commands. -| Option Name | Type | Description | -| --------------- | ---------------------------------------------------------- | ------------------------------------------------------------ | -| --version | [boolean] | Show version number | -| --clientId | [string]
[required] | Client ID for the source hub | -| --clientSecret | [string]
[required] | Client secret for the source hub | -| --hubId | [string]
[required] | Hub ID for the source hub | -| --config | [string]
[default: "~/.amplience/dc-cli-config.json"] | Path to JSON config file | -| --help | [boolean] | Show help | +| Option Name | Type | Description | +| --------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| --version | [boolean] | Show version number | +| --clientId | [string]
[required] | Client ID for the source hub | +| --clientSecret | [string]
[required] | Client secret for the source hub | +| --hubId | [string]
[required] | Hub ID for the source hub | +| --config | [string]
[default: "~/.amplience/dc-cli-config.json"] | Path to JSON config file | +| --help | [boolean] | Show help | | -f
--force | [boolean] | Overwrite content, create and assign content types, and ignore content with missing types/references without asking. | -| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | ## Useful Information @@ -43,7 +47,7 @@ The following options are available for all **hub** commands. When importing content with the DC CLI, this creates or references a mapping file to determine whether the imported content item should be created as new, or if an existing one within the Dynamic Content platform should be updated. -For example exporting a content item (eg `11111111-1111-1111-1111-111111111111`) from one hub then importing it to another for the first time will create a new content item with a randomly generated UUID (eg `22222222-2222-2222-2222-222222222222`). +For example exporting a content item (eg `11111111-1111-1111-1111-111111111111`) from one hub then importing it to another for the first time will create a new content item with a randomly generated UUID (eg `22222222-2222-2222-2222-222222222222`). To instruct the DC CLI on which content item to update with future actions, a mapping between the source and destination is stored in a mapping file. This mapping file will contain an array of every content item mapping identified for jobs using that mapping file. Using the previous examples: @@ -61,8 +65,8 @@ To instruct the DC CLI on which content item to update with future actions, a ma If no mapping file is specified (with the `--mapFile` argument) then a default one will be created or updated, using the destination's resource type (hub) and its ID, and stored within a default location in your user directory. For example: -* Mac: `~/.amplience/imports/hub-111111111111111111111111.json` -* Windows: `%UserProfile%\.amplience\imports\hub-111111111111111111111111.json` +- Mac: `~/.amplience/imports/hub-111111111111111111111111.json` +- Windows: `%UserProfile%\.amplience\imports\hub-111111111111111111111111.json` If a mapping file does not exist at the point of import, then any imported content items will be created as new, and a new mapping file will be created. If a mapping file exists, and was provided with the `--mapFile` argument, then any items found within the mapping file will be updated. Any content items not contained in the mapping file will will be created as new, and will then be added to the mapping file. @@ -78,12 +82,13 @@ This functionality requires additional Content Hub-specific permissions granting Exports all of the following (where applicable) from the source hub, then imports them into the destination hub: -* Hub Settings -* Extensions -* Content Type Schemas -* Content Types -* Content Items -* Search Indexes +- Hub Settings +- Extensions +- Content Type Schemas +- Content Types +- Content Items +- Search Indexes +- Events (requires `--acceptSnapshotLimits` argument, due to some [limitations](EVENT.md#export--import-limitations)) ``` dc-cli hub clone @@ -91,21 +96,23 @@ dc-cli hub clone #### Options -| Option Name | Type | Description | -| ------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | -| --dstHubId | [string] | Destination hub ID.
If not specified, it will be the same as the source. | -| --dstClientId | [string] | Destination account's client ID.
If not specified, it will be the same as the source. | -| --dstSecret | [string] | Destination account's secret.
Must be used alongside dstClientId. | -| --mapFile | [string] | Mapping file to use when updating content that already exists.
Updated with any new mappings that are generated. If not present, will be created. | -| -v
--validate | [boolean] | Only recreate folder structure.
Content is validated but not imported. | -| --skipIncomplete | [boolean] | Skip any content item that has one or more missing dependancy. | -| --lastPublish | [boolean] | When available, export the last published version of a content item rather than its newest version. | -| --publish | [boolean] | Publish any content items that have an existing publish status in their JSON. | -| --republish | [boolean] | Republish content items regardless of whether the import changed them or not.
(--publish not required) | -| --excludeKeys | [boolean] | Exclude delivery keys when importing content items. | -| --media | [boolean] | Detect and rewrite media links to match assets in the target account's DAM.
Your client must have DAM permissions configured. | -| --revertLog | [string] | Revert a previous clone using a given revert log and given directory.
Reverts steps in reverse order, starting at the specified one. | -| --step | [string]
[choices: "settings", "schema", "type", "content"] | Start at a specific step.
Steps after the one you specify will also run. | +| Option Name | Type | Description | +| ------------------------ | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| --acceptSnapshotLimits | [boolean] | Must be passed to use the event clone step.
Only use this command if you fully understand its [limitations](EVENT.md#export--import-limitations). | +| --dstHubId | [string] | Destination hub ID.
If not specified, it will be the same as the source. | +| --dstClientId | [string] | Destination account's client ID.
If not specified, it will be the same as the source. | +| --dstSecret | [string] | Destination account's secret.
Must be used alongside dstClientId. | +| --mapFile | [string] | Mapping file to use when updating content that already exists.
Updated with any new mappings that are generated. If not present, will be created. | +| -v
--validate | [boolean] | Only recreate folder structure.
Content is validated but not imported. | +| --skipIncomplete | [boolean] | Skip any content item that has one or more missing dependancy. | +| --lastPublish | [boolean] | When available, export the last published version of a content item rather than its newest version. | +| --publish | [boolean] | Publish any content items that have an existing publish status in their JSON. | +| --republish | [boolean] | Republish content items regardless of whether the import changed them or not.
(--publish not required) | +| --excludeKeys | [boolean] | Exclude delivery keys when importing content items. | +| --media | [boolean] | Detect and rewrite media links to match assets in the target account's DAM.
Your client must have DAM permissions configured. | +| --revertLog | [string] | Revert a previous clone using a given revert log and given directory.
Reverts steps in reverse order, starting at the specified one. | +| --step | [string]
[choices: "settings", "schema", "type", "content"] | Start at a specific step.
Steps after the one you specify will also run. | +| --ignoreSchemaValidation | [boolean]
[default: false] | Ignore content item schema validation during clone | #### Examples @@ -113,6 +120,10 @@ dc-cli hub clone `dc-cli hub clone ./myDirectory/hub` +##### Clone hub with events + +`dc-cli hub clone ./myDirectory/hub --acceptSnapshotLimits` + ##### Resume a hub clone from the content item step `dc-cli hub clone ./myDirectory/hub --step content` @@ -121,10 +132,10 @@ dc-cli hub clone Archives all of the following (where applicable) from the source hub: -* Hub Settings -* Content Type Schemas -* Content Types -* Content Items +- Hub Settings +- Content Type Schemas +- Content Types +- Content Items ``` dc-cli hub clean @@ -132,9 +143,10 @@ dc-cli hub clean #### Options -| Option Name | Type | Description | -| ----------- | ---------------------------------------------------- | ------------------------------------------------------------ | -| --step | [string]
[choices: "content", "type", "schema"] | Start at a specific step.
Steps after the one you specify will also run. | +| Option Name | Type | Description | +| ------------------------ | ---------------------------------------------------- | ----------------------------------------------------------------------------- | +| --step | [string]
[choices: "content", "type", "schema"] | Start at a specific step.
Steps after the one you specify will also run. | +| --ignoreSchemaValidation | [boolean]
[default: false] | Ignore content item schema validation during clean | #### Examples @@ -144,4 +156,68 @@ dc-cli hub clean ##### Resume the clean hub process from the content item step -`dc-cli hub clean --step content` \ No newline at end of file +`dc-cli hub clean --step content` + +### add + +Saves a hub configuration for later use. A hub configuration consists of either: + +- client id +- client secret +- hub id + +or: + +- PAT token +- hub id + +Once you enter the `dc-cli hub add` command you will be prompted with a yes/no choice question as to whether you would like to use a PAT Token or not. + +These can subsequently be used with `dc-cli hub use`. + +``` +dc-cli hub add +``` + +### list + +Lists the hubs that have been configured. + +``` +dc-cli hub list +``` + +### ls + +Alias for `dc-cli hub list`. + +### use + +Retrieves a hub configuration to be used by `dc-cli`. Under the covers, this uses `dc-cli configure`. The `filter` parameter is optional; if provided, it will filter the list of configured hubs to those that match `filter` with either their `name` or `hubId`. If more than one hub matches `filter` (or if `filter` is not provided) the user will be prompted to disambiguate between configurations. + +``` +dc-cli hub use [filter] +``` + +#### Options + +| Option Name | Type | Description | +| -------------- | -------- | -------------------------------------------------------------------- | +| filter | [string] | Either part of the hub name or part of the hub id. | +| --clientId | [string] | Client ID for the source hub, instead of entering when prompted. | +| --clientSecret | [string] | Client secret for the source hub, instead of entering when prompted. | +| --hubId | [string] | Hub ID for the source hub, instead of entering when prompted. | + +#### Examples + +##### Select a hub from the full list of configured hubs + +`dc-cli hub use` + +##### Use a hub named 'index01' + +`dc-cli hub use index01` + +##### Use the hub with ID ending in e510 + +`dc-cli hub use e510` diff --git a/docs/JOB.md b/docs/JOB.md new file mode 100644 index 00000000..4586ab6c --- /dev/null +++ b/docs/JOB.md @@ -0,0 +1,58 @@ +# job + +## Description + +This category includes interactions with Dynamic Content jobs + +Run `dc-cli job --help` to get a list of available commands. + +Return to [README.md](../README.md) for information on other command categories. + + + +- [job](#job) + - [Description](#description) + - [Common Options](#common-options) + - [Commands](#commands) + - [get](#get) + - [Options](#options) + - [Examples](#examples) + - [Get a job by ID](#get-a-job-by-id) + + + +## Common Options + +The following options are available for all **job** commands. + +| Option Name | Type | Description | +| -------------- | ---------------------------------------------------------- | -------------------------------- | +| --version | [boolean] | Show version number | +| --clientId | [string]
[required] | Client ID for the source hub | +| --clientSecret | [string]
[required] | Client secret for the source hub | +| --patToken | [string]
[required] | PAT for the source hub | +| --hubId | [string]
[required] | Hub ID for the source hub | +| --config | [string]
[default: "~/.amplience/dc-cli-config.json"] | Path to JSON config file | +| --help | [boolean] | Show help | + +## Commands + +### get + +Get a job by ID. + +``` +dc-cli job get +``` + +#### Options + +| Option Name | Type | Description | +| ----------- | ------------------------------- | --------------------- | +| --json | [boolean]
[default: false] | Render output as JSON | + +#### Examples + +##### Get a job by ID + +`dc-cli job get abc67c23-4c22-4617-a009-0f976d77b789` diff --git a/docs/LINKED-CONTENT-REPOSITORY.md b/docs/LINKED-CONTENT-REPOSITORY.md new file mode 100644 index 00000000..f2a57715 --- /dev/null +++ b/docs/LINKED-CONTENT-REPOSITORY.md @@ -0,0 +1,140 @@ +# linked-content-repository + +## Description + +The **linked-content-repository** command category includes a number of interactions with linked content respositories. + +Run `dc-cli linked-content-repository --help` to get a list of available commands. + +Return to [README.md](../README.md) for information on other command categories. + + + +- [linked-content-repository](#linked-content-repository) + - [Description](#description) + - [Common Options](#common-options) + - [Commands](#commands) + - [list](#list) + - [Options](#options) + - [Examples](#examples) + - [List all linked content repositories](#list-all-linked-content-repositories) + - [create](#create) + - [Options](#options-1) + - [Examples](#examples-1) + - [Create a linked content repository](#create-a-linked-content-repository) + - [update](#update) + - [Options](#options-1) + - [Examples](#examples-1) + - [Update a linked content repository](#update-a-linked-content-repository) + - [delete](#delete) + - [Options](#options-2) + - [Examples](#examples-2) + - [Delete a linked content repository](#delete-a-linked-content-repository) + + + +## Common Options + +The following options are available for all **linked-content-repository** commands. + +| Option Name | Type | Description | +| ----------- | ---------------------------------------------------------- | ------------------------- | +| --version | [boolean] | Show version number | +| --patToken | [string]
[required] | PAT for the source hub | +| --hubId | [string]
[required] | Hub ID for the source hub | +| --config | [string]
[default: "~/.amplience/dc-cli-config.json"] | Path to JSON config file | +| --help | [boolean] | Show help | + +## Commands + +### list + +List linked content repositories that exist in the target hubs Organization. + +``` +dc-cli linked-content-repository list +``` + +#### Options + +| Option Name | Type | Description | +| ----------- | ------------------------------- | --------------------------------------------------------- | +| --sort | [string] | How to order the list e.g "\,\..." | +| --json | [boolean]
[default: false] | Render output as JSON | + +#### Examples + +##### List all linked content repositories + +``` +dc-cli linked-content-repository list +``` + +### create + +Creates a linked content repository. + +``` +dc-cli linked-content-repository create +``` + +#### Options + +| Option Name | Type | Description | +| ----------- | ------------------------------- | ----------------------------------------------------- | +| --file | [string]
[required] | Path to file containing link content respository JSON | +| --json | [boolean]
[default: false] | Render output as JSON | + +#### Examples + +##### Create a linked content repository + +``` +dc-cli linked-content-repository create --file '/User/Ampy/my-linked-content-repository-to-create.json' +``` + +### update + +Updates a linked content repository. + +``` +dc-cli linked-content-repository update +``` + +#### Options + +| Option Name | Type | Description | +| ----------- | ------------------------------- | ----------------------------------------------------- | +| --file | [string]
[required] | Path to file containing link content respository JSON | +| --json | [boolean]
[default: false] | Render output as JSON | + +#### Examples + +##### Update a linked content repository + +``` +dc-cli linked-content-repository update --file '/User/Ampy/my-linked-content-repository-to-update.json' +``` + +### delete + +Deletes a linked content repository. + +``` +dc-cli linked-content-repository delete +``` + +#### Options + +| Option Name | Type | Description | +| ----------- | ------------------------------- | ----------------------------------------------------- | +| --file | [string]
[required] | Path to file containing link content respository JSON | +| --json | [boolean]
[default: false] | Render output as JSON | + +#### Examples + +##### Delete a linked content repository + +``` +dc-cli linked-content-repository delete --file '/User/Ampy/my-linked-content-repository-to-delete.json' +``` diff --git a/docs/SETTINGS.md b/docs/SETTINGS.md index 45059928..40aaddd7 100644 --- a/docs/SETTINGS.md +++ b/docs/SETTINGS.md @@ -96,6 +96,7 @@ dc-cli settings import | Option Name | Type | Description | | --------------- | --------- | ------------------------------------------------------------ | +| --allowDelete | [boolean] | Allows removal of settings that are not in the imported json when possible, such as previews. | | --mapFile | [string] | Mapping file to use when updating workflow states that already exists.
Updated with any new mappings that are generated.
If not present, will be created.
For more information, see [mapping files](#MAPPING-FILES). | | -f
--force | [boolean] | Overwrite workflow states on import without asking. | diff --git a/docs/WEBHOOK.md b/docs/WEBHOOK.md new file mode 100644 index 00000000..2fe4ec75 --- /dev/null +++ b/docs/WEBHOOK.md @@ -0,0 +1,144 @@ +# webhook + +## Description + +The **webhook** command category includes a number of interactions with webhooks. + +These commands can be used to export, import and delete webhooks from an individual hub. + +Run `dc-cli webhook --help` to get a list of available commands. + +Return to [README.md](../README.md) for information on other command categories. + + + +- [Common Options](#common-options) +- [Commands](#commands) + - [export](#export) + - [import](#import) + - [delete](#delete) + + + +## Common Options + +The following options are available for all **webhook** commands. + +| Option Name | Type | Description | +| -------------- | ---------------------------------------------------------- | -------------------------------- | +| --version | [boolean] | Show version number | +| --clientId | [string]
[required] | Client ID for the source hub | +| --clientSecret | [string]
[required] | Client secret for the source hub | +| --hubId | [string]
[required] | Hub ID for the source hub | +| --config | [string]
[default: "~/.amplience/dc-cli-config.json"] | Path to JSON config file | +| --help | [boolean] | Show help | + +## Commands + +### export + +Exports webhooks from the targeted Dynamic Content hub into a folder called **exported_webhooks** at the user specified file path. + +**Note**: No secret or auth header values will be exported. + +``` +dc-cli webhook export +``` + +#### Options + +| Option Name | Type | Description | +| ---------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| --id | [string] | The ID of the webhook to be exported.
If no --id option is given, all webhooks for the hub are exported.
A single --id option may be given to export a single webhook.
Multiple --id options may be given to export multiple webhooks at the same time. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| -s
--silent | [boolean] | If present, no log file will be produced. | +| -f
--force | [boolean] | Export webhooks without asking. | + +#### Examples + +##### Export all webhooks from a hub + +`dc-cli webhook export ./myDirectory/content` + +##### Export a single webhook from a hub + +`dc-cli webhook export ./myDirectory/content --id 1111111111` + +##### Export multiple webhooks from a hub + +`dc-cli webhook export ./myDirectory/content --id 1111111111 --id 2222222222` + +### import + +Imports webhooks from the specified filesystem location to the targeted Dynamic Content hub. + +**Note**: The following values will be stripped out / not included during the import: + +- **secret** - this will be recreated for the webhook in the destination hub during import. +- **createdDate** - this will be assigned during import (if webhook is being created). +- **lastModifiedDate** - this will be assigned during import (if webhook is being updated). +- **any header objects that are secrets** - these need to be manually assigned for the webhook in the destination hub. + +Please see [the content-management API reference for Webhooks](https://amplience.com/developers/docs/apis/content-management-reference/#tag/Webhooks) for more information. + +For any **customPayload** the following property values will be replaced by those in the destination hub: + +- account +- stagingEnvironment + +``` +dc-cli webhook import +``` + +#### Options + +| Option Name | Type | Description | +| ---------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| --mapFile | [string] | Mapping file to use when updating content that already exists.
Updated with any new mappings that are generated. If not present, will be created.
For more information, see [mapping files](#MAPPING-FILES). | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | +| -s
--silent | [boolean] | If present, no log file will be produced. | +| -f
--force | [boolean] | Overwrite webhooks without asking. | + +#### Examples + +##### Import content from the filesystem + +`dc-cli webhook import ./myDirectory/webhooks` + +##### Specify a mapping file when importing + +`dc-cli webhook import ./myDirectory/webhooks --mapFile ./myDirectory/mappingFile.json` + +### delete + +Deletes webhooks from the targeted Dynamic Content hub. + +``` +dc-cli webhook delete +``` + +#### Options + +| Option Name | Type | Description | +| --------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| --id | [string] | The ID of an Webhook to be deleted.
If no --id option is given, all webhooks for the hub are deleted.
A single --id option may be given to delete a single webhook.
Multiple --id options may be given to delete multiple webhooks at the same time. | +| -f
--force | [boolean] | Delete webhooks without asking. | +| --logFile | [string]
[default: (generated-value)] | Path to a log file to write to. | + +#### Examples + +##### Delete all webhooks from a Hub + +`dc-cli webhook delete` + +##### Delete a single webhook with the ID of 'foo' + +`dc-cli webhook delete foo` + +or + +`dc-cli webhook delete --id foo` + +##### Delete multiple webhooks with the IDs of 'foo' & 'bar' + +`dc-cli webhook delete --id foo --id bar` diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..a51a8cd7 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,35 @@ +import globals from 'globals'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import js from '@eslint/js'; +import { FlatCompat } from '@eslint/eslintrc'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all +}); + +export default [ + ...compat.extends('plugin:@typescript-eslint/recommended', 'prettier'), + { + languageOptions: { + globals: { + ...globals.node + }, + + ecmaVersion: 2018, + sourceType: 'commonjs' + }, + + rules: { + '@typescript-eslint/no-parameter-properties': 'off', + '@typescript-eslint/no-require-imports': 'off', + '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/no-unused-expressions': 'warn', + '@typescript-eslint/no-empty-object-type': 'warn' + } + } +]; diff --git a/jest.config.js b/jest.config.js index a7a85dd0..9d4abf13 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,12 +1,15 @@ module.exports = { - testEnvironment: "node", + testEnvironment: 'node', roots: ['/src'], transform: { '^.+\\.ts?$': 'ts-jest' }, preset: 'ts-jest', - coveragePathIgnorePatterns: [ - '^.+\\.mocks\.ts?$' - ], - setupFilesAfterEnv: ['/jest.global.js'] + coveragePathIgnorePatterns: ['^.+\\.mocks.ts?$'], + setupFilesAfterEnv: ['/jest.global.js'], + snapshotFormat: { + escapeString: true, + printBasicPrototype: true + }, + prettierPath: null }; diff --git a/package-lock.json b/package-lock.json index 259f63df..c9698776 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,377 +1,325 @@ { "name": "@amplience/dc-cli", - "version": "0.13.0", - "lockfileVersion": 2, + "version": "0.30.0", + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@amplience/dc-cli", - "version": "0.13.0", + "version": "0.30.0", "license": "Apache-2.0", "dependencies": { - "ajv": "^6.12.3", - "axios": "^0.21.1", - "chalk": "^2.4.2", - "dc-management-sdk-js": "^1.14.0", - "lodash": "^4.17.21", - "node-fetch": "^2.6.1", - "promise-retry": "^2.0.1", - "rimraf": "^3.0.0", - "sanitize-filename": "^1.6.3", - "table": "^5.4.6", - "url-template": "^2.0.8", - "yargs": "^14.0.0" + "ajv": "6.12.6", + "axios": "1.12.2", + "axios-retry": "4.5.0", + "bottleneck": "2.19.5", + "chalk": "2.4.2", + "cli-progress": "3.12.0", + "dc-management-sdk-js": "3.2.0", + "enquirer": "2.3.6", + "fs-extra": "10.1.0", + "graceful-fs": "4.2.11", + "lodash": "4.17.21", + "node-fetch": "2.7.0", + "rimraf": "3.0.2", + "sanitize-filename": "1.6.3", + "table": "5.4.6", + "url-template": "2.0.8", + "yargs": "14.2.3" }, "bin": { "dc-cli": "dist/index.js" }, "devDependencies": { - "@commitlint/cli": "^13.1.0", - "@commitlint/config-conventional": "^8.2.0", - "@types/chalk": "^2.2.0", - "@types/jest": "^24.0.18", - "@types/lodash": "^4.14.144", - "@types/node-fetch": "^2.5.7", - "@types/promise-retry": "^1.1.3", - "@types/rimraf": "^3.0.0", - "@types/table": "^4.0.7", - "@types/url-template": "^2.0.28", - "@typescript-eslint/eslint-plugin": "^2.34.0", - "@typescript-eslint/parser": "^2.34.0", - "adm-zip": "^0.4.13", - "axios-mock-adapter": "^1.19.0", - "commitizen": "^4.2.4", - "cz-conventional-changelog": "^3.0.2", - "eslint": "^6.4.0", - "eslint-config-prettier": "^6.3.0", - "eslint-plugin-prettier": "^3.1.1", - "husky": "^3.0.5", - "jest": "^27.0.6", - "nock": "^12.0.3", - "pkg": "^5.3.1", - "prettier": "^1.18.2", - "standard-version": "^9.3.1", - "ts-jest": "^27.0.4", - "ts-node": "^8.4.1", - "typescript": "^3.9.10" - }, - "engines": { - "node": ">12" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "@commitlint/cli": "19.7.1", + "@commitlint/config-conventional": "19.7.1", + "@eslint/eslintrc": "3.3.1", + "@eslint/js": "9.32.0", + "@types/cli-progress": "3.11.6", + "@types/fs-extra": "9.0.13", + "@types/graceful-fs": "4.1.9", + "@types/jest": "30.0.0", + "@types/lodash": "4.14.144", + "@types/node": "20.17.19", + "@types/node-fetch": "2.5.7", + "@types/rimraf": "3.0.0", + "@types/table": "4.0.7", + "@types/url-template": "2.0.28", + "@types/yargs": "16.0.4", + "@typescript-eslint/eslint-plugin": "8.24.1", + "@typescript-eslint/parser": "8.24.1", + "@yao-pkg/pkg": "6.5.1", + "axios-mock-adapter": "1.19.0", + "commitizen": "4.3.1", + "cz-conventional-changelog": "3.3.0", + "eslint": "9.32.0", + "eslint-config-prettier": "10.0.1", + "eslint-plugin-prettier": "5.2.3", + "globals": "15.15.0", + "husky": "3.0.5", + "jest": "30.0.5", + "nock": "12.0.3", + "prettier": "3.5.1", + "ts-jest": "29.4.1", + "ts-node": "10.9.1", + "typescript": "5.7.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@babel/highlight": "^7.0.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz", - "integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.0", - "@babel/helper-module-transforms": "^7.15.0", - "@babel/helpers": "^7.14.8", - "@babel/parser": "^7.15.0", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "node": ">=6.0.0" } }, - "node_modules/@babel/core/node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "node_modules/@ampproject/remapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@babel/core/node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" } }, - "node_modules/@babel/generator": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", - "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "node_modules/@babel/core": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", + "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.3", + "@babel/parser": "^7.28.3", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2", + "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/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", - "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", - "semver": "^6.3.0" + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", - "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-get-function-arity": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", - "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.14.5" + "@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-hoist-variables": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", - "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", - "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "dev": true, - "dependencies": { - "@babel/types": "^7.15.0" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", - "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.14.5" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", - "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.0", - "@babel/helper-simple-access": "^7.14.8", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", - "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.14.5" }, - "engines": { - "node": ">=6.9.0" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", - "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", - "dev": true, - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.15.0", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", - "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, - "dependencies": { - "@babel/types": "^7.14.8" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", - "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, - "dependencies": { - "@babel/types": "^7.14.5" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.3.tgz", - "integrity": "sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", + "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", - "dev": true, - "dependencies": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, "node_modules/@babel/parser": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.3.tgz", - "integrity": "sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", + "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -384,6 +332,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -396,6 +345,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -408,6 +358,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -415,11 +366,44 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "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-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "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-meta": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -432,6 +416,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -439,11 +424,28 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "license": "MIT", + "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://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -456,6 +458,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -468,6 +471,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -480,6 +484,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -492,6 +497,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -504,6 +510,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -511,11 +518,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { + "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -526,11 +534,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-typescript": { + "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", - "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -541,100 +550,65 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/template": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", - "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" - } - }, - "node_modules/@babel/template/node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.14.5" }, - "engines": { - "node": ">=6.9.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/template/node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@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.15.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", - "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.15.0", - "@babel/types": "^7.15.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", + "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.3", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", - "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.14.9", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -644,38 +618,29 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@commitlint/cli": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-13.1.0.tgz", - "integrity": "sha512-xN/uNYWtGTva5OMSd+xA6e6/c2jk8av7MUbdd6w2cw89u6z3fAWoyiH87X0ewdSMNYmW/6B3L/2dIVGHRDID5w==", - "dev": true, - "dependencies": { - "@commitlint/format": "^13.1.0", - "@commitlint/lint": "^13.1.0", - "@commitlint/load": "^13.1.0", - "@commitlint/read": "^13.1.0", - "@commitlint/types": "^13.1.0", - "lodash": "^4.17.19", - "resolve-from": "5.0.0", - "resolve-global": "1.0.0", + "version": "19.7.1", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.7.1.tgz", + "integrity": "sha512-iObGjR1tE/PfDtDTEfd+tnRkB3/HJzpQqRTyofS2MPPkDn1mp3DBC8SoPDayokfAy+xKhF8+bwRCJO25Nea0YQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/format": "^19.5.0", + "@commitlint/lint": "^19.7.1", + "@commitlint/load": "^19.6.1", + "@commitlint/read": "^19.5.0", + "@commitlint/types": "^19.5.0", + "tinyexec": "^0.3.0", "yargs": "^17.0.0" }, "bin": { "commitlint": "cli.js" }, "engines": { - "node": ">=v12" - } - }, - "node_modules/@commitlint/cli/node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">=v18" } }, "node_modules/@commitlint/cli/node_modules/ansi-styles": { @@ -694,14 +659,17 @@ } }, "node_modules/@commitlint/cli/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/@commitlint/cli/node_modules/color-convert": { @@ -722,57 +690,13 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@commitlint/cli/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/@commitlint/cli/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/cli/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/@commitlint/cli/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/cli/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@commitlint/cli/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -805,311 +729,276 @@ } }, "node_modules/@commitlint/cli/node_modules/yargs": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.0.tgz", - "integrity": "sha512-SQr7qqmQ2sNijjJGHL4u7t8vyDZdZ3Ahkmo4sc1w5xI9TBX0QDdG/g4SFnxtWOsGLjwHQue57eFALfwFCnixgg==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { "node": ">=12" } }, - "node_modules/@commitlint/config-conventional": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-8.2.0.tgz", - "integrity": "sha512-HuwlHQ3DyVhpK9GHgTMhJXD8Zp8PGIQVpQGYh/iTrEU6TVxdRC61BxIDZvfWatCaiG617Z/U8maRAFrqFM4TqA==", - "dev": true - }, - "node_modules/@commitlint/ensure": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-13.1.0.tgz", - "integrity": "sha512-NRGyjOdZQnlYwm9it//BZJ2Vm+4x7G9rEnHpLCvNKYY0c6RA8Qf7hamLAB8dWO12RLuFt06JaOpHZoTt/gHutA==", + "node_modules/@commitlint/cli/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "dependencies": { - "@commitlint/types": "^13.1.0", - "lodash": "^4.17.19" - }, "engines": { - "node": ">=v12" + "node": ">=12" } }, - "node_modules/@commitlint/ensure/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/@commitlint/execute-rule": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-13.0.0.tgz", - "integrity": "sha512-lBz2bJhNAgkkU/rFMAw3XBNujbxhxlaFHY3lfKB/MxpAa+pIfmWB3ig9i1VKe0wCvujk02O0WiMleNaRn2KJqw==", + "node_modules/@commitlint/config-conventional": { + "version": "19.7.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-19.7.1.tgz", + "integrity": "sha512-fsEIF8zgiI/FIWSnykdQNj/0JE4av08MudLTyYHm4FlLWemKoQvPNUYU2M/3tktWcCEyq7aOkDDgtjrmgWFbvg==", "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.5.0", + "conventional-changelog-conventionalcommits": "^7.0.2" + }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, - "node_modules/@commitlint/format": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-13.1.0.tgz", - "integrity": "sha512-n46rYvzf+6Sm99TJjTLjJBkjm6JVcklt31lDO5Q+pCIV0NnJ4qIUcwa6wIL9a9Vqb1XzlMgtp27E0zyYArkvSg==", + "node_modules/@commitlint/config-validator": { + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.5.0.tgz", + "integrity": "sha512-CHtj92H5rdhKt17RmgALhfQt95VayrUo2tSqY9g2w+laAXyk7K/Ef6uPm9tn5qSIwSmrLjKaXK9eiNuxmQrDBw==", "dev": true, + "license": "MIT", "dependencies": { - "@commitlint/types": "^13.1.0", - "chalk": "^4.0.0" + "@commitlint/types": "^19.5.0", + "ajv": "^8.11.0" }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, - "node_modules/@commitlint/format/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@commitlint/config-validator/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@commitlint/format/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@commitlint/config-validator/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } + "license": "MIT" }, - "node_modules/@commitlint/format/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@commitlint/ensure": { + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-19.5.0.tgz", + "integrity": "sha512-Kv0pYZeMrdg48bHFEU5KKcccRfKmISSm9MvgIgkpI6m+ohFTB55qZlBW6eYqh/XDfRuIO0x4zSmvBjmOwWTwkg==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@commitlint/types": "^19.5.0", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=v18" } }, - "node_modules/@commitlint/format/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@commitlint/format/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@commitlint/execute-rule": { + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.5.0.tgz", + "integrity": "sha512-aqyGgytXhl2ejlk+/rfgtwpPexYyri4t8/n4ku6rRJoRhGZpLFMqrZ+YaubeGysCP6oz4mMA34YSTaSOKEeNrg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=v18" } }, - "node_modules/@commitlint/format/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@commitlint/format": { + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.5.0.tgz", + "integrity": "sha512-yNy088miE52stCI3dhG/vvxFo9e4jFkU1Mj3xECfzp/bIS/JUay4491huAlVcffOoMK1cd296q0W92NlER6r3A==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@commitlint/types": "^19.5.0", + "chalk": "^5.3.0" }, "engines": { - "node": ">=8" + "node": ">=v18" } }, - "node_modules/@commitlint/is-ignored": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-13.1.0.tgz", - "integrity": "sha512-P6zenLE5Tn3FTNjRzmL9+/KooTXEI0khA2TmUbuei9KiycemeO4q7Xk7w7aXwFPNAbN0O9oI7z3z7cFpzKJWmQ==", + "node_modules/@commitlint/format/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", "dev": true, - "dependencies": { - "@commitlint/types": "^13.1.0", - "semver": "7.3.5" - }, + "license": "MIT", "engines": { - "node": ">=v12" + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@commitlint/is-ignored/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@commitlint/is-ignored": { + "version": "19.7.1", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-19.7.1.tgz", + "integrity": "sha512-3IaOc6HVg2hAoGleRK3r9vL9zZ3XY0rf1RsUf6jdQLuaD46ZHnXBiOPTyQ004C4IvYjSWqJwlh0/u2P73aIE3g==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "@commitlint/types": "^19.5.0", + "semver": "^7.6.0" }, "engines": { - "node": ">=10" + "node": ">=v18" } }, "node_modules/@commitlint/lint": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-13.1.0.tgz", - "integrity": "sha512-qH9AYSQDDTaSWSdtOvB3G1RdPpcYSgddAdFYqpFewlKQ1GJj/L+sM7vwqCG7/ip6AiM04Sry1sgmFzaEoFREUA==", + "version": "19.7.1", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-19.7.1.tgz", + "integrity": "sha512-LhcPfVjcOcOZA7LEuBBeO00o3MeZa+tWrX9Xyl1r9PMd5FWsEoZI9IgnGqTKZ0lZt5pO3ZlstgnRyY1CJJc9Xg==", "dev": true, + "license": "MIT", "dependencies": { - "@commitlint/is-ignored": "^13.1.0", - "@commitlint/parse": "^13.1.0", - "@commitlint/rules": "^13.1.0", - "@commitlint/types": "^13.1.0" + "@commitlint/is-ignored": "^19.7.1", + "@commitlint/parse": "^19.5.0", + "@commitlint/rules": "^19.6.0", + "@commitlint/types": "^19.5.0" }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, "node_modules/@commitlint/load": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-13.1.0.tgz", - "integrity": "sha512-zlZbjJCWnWmBOSwTXis8H7I6pYk6JbDwOCuARA6B9Y/qt2PD+NCo0E/7EuaaFoxjHl+o56QR5QttuMBrf+BJzg==", + "version": "19.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.6.1.tgz", + "integrity": "sha512-kE4mRKWWNju2QpsCWt428XBvUH55OET2N4QKQ0bF85qS/XbsRGG1MiTByDNlEVpEPceMkDr46LNH95DtRwcsfA==", "dev": true, + "license": "MIT", "dependencies": { - "@commitlint/execute-rule": "^13.0.0", - "@commitlint/resolve-extends": "^13.0.0", - "@commitlint/types": "^13.1.0", - "chalk": "^4.0.0", - "cosmiconfig": "^7.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0" + "@commitlint/config-validator": "^19.5.0", + "@commitlint/execute-rule": "^19.5.0", + "@commitlint/resolve-extends": "^19.5.0", + "@commitlint/types": "^19.5.0", + "chalk": "^5.3.0", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^6.1.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, - "node_modules/@commitlint/load/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@commitlint/load/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } + "license": "Python-2.0" }, "node_modules/@commitlint/load/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@commitlint/load/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@commitlint/load/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/@commitlint/load/node_modules/cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, + "license": "MIT", + "peer": 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" + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" }, "engines": { - "node": ">=10" - } - }, - "node_modules/@commitlint/load/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@commitlint/load/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/@commitlint/load/node_modules/cosmiconfig-typescript-loader": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.1.0.tgz", + "integrity": "sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==", "dev": true, + "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "jiti": "^2.4.1" }, "engines": { - "node": ">=6" + "node": ">=v18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=9", + "typescript": ">=5" } }, - "node_modules/@commitlint/load/node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/@commitlint/load/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "engines": { - "node": ">=4" + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@commitlint/load/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "node_modules/@commitlint/load/node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -1123,483 +1012,615 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/load/node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/load/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/load/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@commitlint/message": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-13.0.0.tgz", - "integrity": "sha512-W/pxhesVEk8747BEWJ+VGQ9ILHmCV27/pEwJ0hGny1wqVquUR8SxvScRCbUjHCB1YtWX4dEnOPXOS9CLH/CX7A==", + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-19.5.0.tgz", + "integrity": "sha512-R7AM4YnbxN1Joj1tMfCyBryOC5aNJBdxadTZkuqtWi3Xj0kMdutq16XQwuoGbIzL2Pk62TALV1fZDCv36+JhTQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=v12" + "node": ">=v18" } }, "node_modules/@commitlint/parse": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-13.1.0.tgz", - "integrity": "sha512-xFybZcqBiKVjt6vTStvQkySWEUYPI0AcO4QQELyy29o8EzYZqWkhUfrb7K61fWiHsplWL1iL6F3qCLoxSgTcrg==", + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-19.5.0.tgz", + "integrity": "sha512-cZ/IxfAlfWYhAQV0TwcbdR1Oc0/r0Ik1GEessDJ3Lbuma/MRO8FRQX76eurcXtmhJC//rj52ZSZuXUg0oIX0Fw==", "dev": true, + "license": "MIT", "dependencies": { - "@commitlint/types": "^13.1.0", - "conventional-changelog-angular": "^5.0.11", - "conventional-commits-parser": "^3.0.0" + "@commitlint/types": "^19.5.0", + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-parser": "^5.0.0" }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, "node_modules/@commitlint/read": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-13.1.0.tgz", - "integrity": "sha512-NrVe23GMKyL6i1yDJD8IpqCBzhzoS3wtLfDj8QBzc01Ov1cYBmDojzvBklypGb+MLJM1NbzmRM4PR5pNX0U/NQ==", + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.5.0.tgz", + "integrity": "sha512-TjS3HLPsLsxFPQj6jou8/CZFAmOP2y+6V4PGYt3ihbQKTY1Jnv0QG28WRKl/d1ha6zLODPZqsxLEov52dhR9BQ==", "dev": true, + "license": "MIT", "dependencies": { - "@commitlint/top-level": "^13.0.0", - "@commitlint/types": "^13.1.0", - "fs-extra": "^10.0.0", - "git-raw-commits": "^2.0.0" + "@commitlint/top-level": "^19.5.0", + "@commitlint/types": "^19.5.0", + "git-raw-commits": "^4.0.0", + "minimist": "^1.2.8", + "tinyexec": "^0.3.0" }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, - "node_modules/@commitlint/read/node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "node_modules/@commitlint/read/node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@commitlint/read/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "node_modules/@commitlint/resolve-extends": { + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.5.0.tgz", + "integrity": "sha512-CU/GscZhCUsJwcKTJS9Ndh3AKGZTNFIOoQB2n8CmFnizE0VnEuJoum+COW+C1lNABEeqk6ssfc1Kkalm4bDklA==", "dev": true, + "license": "MIT", "dependencies": { - "universalify": "^2.0.0" + "@commitlint/config-validator": "^19.5.0", + "@commitlint/types": "^19.5.0", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "engines": { + "node": ">=v18" } }, - "node_modules/@commitlint/read/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "node_modules/@commitlint/resolve-extends/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 10.0.0" + "node": ">=8" } }, - "node_modules/@commitlint/resolve-extends": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-13.0.0.tgz", - "integrity": "sha512-1SyaE+UOsYTkQlTPUOoj4NwxQhGFtYildVS/d0TJuK8a9uAJLw7bhCLH2PEeH5cC2D1do4Eqhx/3bLDrSLH3hg==", + "node_modules/@commitlint/rules": { + "version": "19.6.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-19.6.0.tgz", + "integrity": "sha512-1f2reW7lbrI0X0ozZMesS/WZxgPa4/wi56vFuJENBmed6mWq5KsheN/nxqnl/C23ioxpPO/PL6tXpiiFy5Bhjw==", "dev": true, + "license": "MIT", "dependencies": { - "import-fresh": "^3.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0", - "resolve-global": "^1.0.0" + "@commitlint/ensure": "^19.5.0", + "@commitlint/message": "^19.5.0", + "@commitlint/to-lines": "^19.5.0", + "@commitlint/types": "^19.5.0" }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, - "node_modules/@commitlint/resolve-extends/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/@commitlint/resolve-extends/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "node_modules/@commitlint/to-lines": { + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-19.5.0.tgz", + "integrity": "sha512-R772oj3NHPkodOSRZ9bBVNq224DOxQtNef5Pl8l2M8ZnkkzQfeSTr4uxawV2Sd3ui05dUVzvLNnzenDBO1KBeQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=v18" } }, - "node_modules/@commitlint/rules": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-13.1.0.tgz", - "integrity": "sha512-b6F+vBqEXsHVghrhomG0Y6YJimHZqkzZ0n5QEpk03dpBXH2OnsezpTw5e+GvbyYCc7PutGbYVQkytuv+7xCxYA==", + "node_modules/@commitlint/top-level": { + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-19.5.0.tgz", + "integrity": "sha512-IP1YLmGAk0yWrImPRRc578I3dDUI5A2UBJx9FbSOjxe9sTlzFiwVJ+zeMLgAtHMtGZsC8LUnzmW1qRemkFU4ng==", "dev": true, + "license": "MIT", "dependencies": { - "@commitlint/ensure": "^13.1.0", - "@commitlint/message": "^13.0.0", - "@commitlint/to-lines": "^13.0.0", - "@commitlint/types": "^13.1.0", - "execa": "^5.0.0" + "find-up": "^7.0.0" }, "engines": { - "node": ">=v12" + "node": ">=v18" } }, - "node_modules/@commitlint/rules/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/@commitlint/top-level/node_modules/find-up": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", + "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", "dev": true, + "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" }, "engines": { - "node": ">= 8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/rules/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/@commitlint/top-level/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, + "license": "MIT", "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" + "p-locate": "^6.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/rules/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/@commitlint/top-level/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/rules/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/@commitlint/top-level/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/rules/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/@commitlint/top-level/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/@commitlint/rules/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/@commitlint/types": { + "version": "19.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.5.0.tgz", + "integrity": "sha512-DSHae2obMSMkAtTBSOulg5X7/z+rGLxcXQIkg3OmWvY6wifojge5uVMydfhUvs7yQj+V7jNmRZ2Xzl8GJyqRgg==", "dev": true, + "license": "MIT", "dependencies": { - "path-key": "^3.0.0" + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" }, "engines": { - "node": ">=8" + "node": ">=v18" } }, - "node_modules/@commitlint/rules/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, + "license": "MIT", "engines": { - "node": ">=6" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@commitlint/rules/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/@commitlint/rules/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/@emnapi/core": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", + "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "shebang-regex": "^3.0.0" + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">=8" + "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/@commitlint/rules/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@commitlint/rules/node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "node_modules/@commitlint/rules/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" }, "engines": { - "node": ">= 8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@commitlint/to-lines": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-13.0.0.tgz", - "integrity": "sha512-mzxWwCio1M4/kG9/69TTYqrraQ66LmtJCYTzAZdZ2eJX3I5w52pSjyP/DJzAUVmmJCYf2Kw3s+RtNVShtnZ+Rw==", + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=v12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@commitlint/top-level": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-13.0.0.tgz", - "integrity": "sha512-baBy3MZBF28sR93yFezd4a5TdHsbXaakeladfHK9dOcGdXo9oQe3GS5hP3BmlN680D6AiQSN7QPgEJgrNUWUCg==", + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "find-up": "^5.0.0" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">=v12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@commitlint/top-level/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, + "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.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": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@commitlint/top-level/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, + "license": "Python-2.0" + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/top-level/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "argparse": "^2.0.1" }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/js": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://eslint.org/donate" } }, - "node_modules/@commitlint/top-level/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "p-limit": "^3.0.2" + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@commitlint/top-level/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=8" + "node": ">=18.18.0" } }, - "node_modules/@commitlint/types": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-13.1.0.tgz", - "integrity": "sha512-zcVjuT+OfKt8h91vhBxt05RMcTGEx6DM7Q9QZeuMbXFk6xgbsSEDMMapbJPA1bCZ81fa/1OQBijSYPrKvtt06g==", + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "chalk": "^4.0.0" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" }, "engines": { - "node": ">=v12" + "node": ">=18.18.0" } }, - "node_modules/@commitlint/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=8" + "node": ">=18.18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@commitlint/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "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": ">=10" + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@commitlint/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@commitlint/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@commitlint/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@commitlint/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@hutson/parse-repository-url": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", - "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, "engines": { - "node": ">=6.9.0" + "node": ">=18.0.0" } }, "node_modules/@istanbuljs/load-nyc-config": { @@ -1607,6 +1628,7 @@ "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -1623,6 +1645,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -1636,6 +1659,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -1648,6 +1672,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -1660,6 +1685,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1669,6 +1695,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1678,25 +1705,27 @@ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/console": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.0.6.tgz", - "integrity": "sha512-fMlIBocSHPZ3JxgWiDNW/KPj6s+YRd0hicb33IrmelCcjXo/pXPwvuiKFmZz+XuqI/1u7nbUK10zSsWL/1aegg==", + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.0.5.tgz", + "integrity": "sha512-xY6b0XiL0Nav3ReresUarwl2oIz1gTnxGbGpho9/rbUWsLH0f1OD/VT84xs8c7VmH7MChnLb0pag6PhZhAdDiA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^27.0.6", + "@jest/types": "30.0.5", "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.0.6", - "jest-util": "^27.0.6", + "chalk": "^4.1.2", + "jest-message-util": "30.0.5", + "jest-util": "30.0.5", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/console/node_modules/ansi-styles": { @@ -1704,6 +1733,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -1719,6 +1749,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1730,11 +1761,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@jest/console/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/console/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -1746,99 +1794,196 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/console/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/@jest/console/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@jest/console/node_modules/jest-message-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.5.tgz", + "integrity": "sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.0.5", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.0.5", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/core": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.0.6.tgz", - "integrity": "sha512-SsYBm3yhqOn5ZLJCtccaBcvD/ccTLCeuDv8U41WJH/V1MW5eKUkeMHT9U+Pw/v1m1AIWlnIW/eM2XzQr0rEmow==", + "node_modules/@jest/console/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/console": "^27.0.6", - "@jest/reporters": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", + "@jest/types": "30.0.5", "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.0.6", - "jest-config": "^27.0.6", - "jest-haste-map": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-resolve-dependencies": "^27.0.6", - "jest-runner": "^27.0.6", - "jest-runtime": "^27.0.6", - "jest-snapshot": "^27.0.6", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "jest-watcher": "^27.0.6", - "micromatch": "^4.0.4", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/core/node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "node_modules/@jest/console/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@jest/core/node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "node_modules/@jest/console/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/console/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.0.5.tgz", + "integrity": "sha512-fKD0OulvRsXF1hmaFgHhVJzczWzA1RXMMo9LTPuFXo9q/alDbME3JIyWYqovWsUBWSoBcsHaGPSLF9rz4l9Qeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.0.5", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.0.5", + "@jest/test-result": "30.0.5", + "@jest/transform": "30.0.5", + "@jest/types": "30.0.5", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.0.5", + "jest-config": "30.0.5", + "jest-haste-map": "30.0.5", + "jest-message-util": "30.0.5", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.0.5", + "jest-resolve-dependencies": "30.0.5", + "jest-runner": "30.0.5", + "jest-runtime": "30.0.5", + "jest-snapshot": "30.0.5", + "jest-util": "30.0.5", + "jest-validate": "30.0.5", + "jest-watcher": "30.0.5", + "micromatch": "^4.0.8", + "pretty-format": "30.0.5", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.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/@jest/transform": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.5.tgz", + "integrity": "sha512-Vk8amLQCmuZyy6GbBht1Jfo9RSdBtg7Lks+B0PecnjI8J+PCLQPGh7uI8Q/2wwpW2gLdiAfiHNsmekKlywULqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.0.5", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.0", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.0.5", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/core/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@jest/core/node_modules/ansi-styles": { @@ -1846,6 +1991,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -1861,6 +2007,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1872,11 +2019,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@jest/core/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/core/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -1888,33 +2052,155 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/core/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/core/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/@jest/core/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "node_modules/@jest/core/node_modules/jest-haste-map": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.5.tgz", + "integrity": "sha512-dkmlWNlsTSR0nH3nRfW5BKbqHefLZv0/6LCccG0xFCTWcJu8TuEwG+5Cm75iBfjVoockmO6J35o5gxtFSn5xeg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.0" + "@jest/types": "30.0.5", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "jest-worker": "30.0.5", + "micromatch": "^4.0.8", + "walker": "^1.0.8" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" + } + }, + "node_modules/@jest/core/node_modules/jest-message-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.5.tgz", + "integrity": "sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.0.5", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.0.5", + "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/core/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.0.5", + "@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/core/node_modules/jest-worker": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.0.5.tgz", + "integrity": "sha512-ojRXsWzEP16NdUuBw/4H/zkZdHOa7MMYCk4E430l+8fELeLg/mqmMlRhjL7UNZvQrDmnovWZV4DxX03fZF48fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.0.5", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", + "dev": true, + "license": "MIT", + "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/@jest/core/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/@jest/core/node_modules/supports-color": { @@ -1922,6 +2208,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -1929,112 +2216,88 @@ "node": ">=8" } }, - "node_modules/@jest/core/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/environment": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.0.6.tgz", - "integrity": "sha512-4XywtdhwZwCpPJ/qfAkqExRsERW+UaoSRStSHCCiQTUpoYdLukj+YJbQSFrZjhlUDRZeNiU9SFH0u7iNimdiIg==", + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.0.5.tgz", + "integrity": "sha512-aRX7WoaWx1oaOkDQvCWImVQ8XNtdv5sEWgk4gxR6NXb7WBUnL5sRak4WRzIQRZ1VTWPvV4VI4mgGjNL9TeKMYA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/fake-timers": "^27.0.6", - "@jest/types": "^27.0.6", + "@jest/fake-timers": "30.0.5", + "@jest/types": "30.0.5", "@types/node": "*", - "jest-mock": "^27.0.6" + "jest-mock": "30.0.5" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/fake-timers": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.0.6.tgz", - "integrity": "sha512-sqd+xTWtZ94l3yWDKnRTdvTeZ+A/V7SSKrxsrOKSqdyddb9CeNRF8fbhAU0D7ZJBpTTW2nbp6MftmKJDZfW2LQ==", + "node_modules/@jest/expect": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.0.5.tgz", + "integrity": "sha512-6udac8KKrtTtC+AXZ2iUN/R7dp7Ydry+Fo6FPFnDG54wjVMnb6vW/XNlf7Xj8UDjAE3aAVAsR4KFyKk3TCXmTA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^27.0.6", - "@sinonjs/fake-timers": "^7.0.2", - "@types/node": "*", - "jest-message-util": "^27.0.6", - "jest-mock": "^27.0.6", - "jest-util": "^27.0.6" + "expect": "30.0.5", + "jest-snapshot": "30.0.5" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/globals": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.0.6.tgz", - "integrity": "sha512-DdTGCP606rh9bjkdQ7VvChV18iS7q0IMJVP1piwTWyWskol4iqcVwthZmoJEf7obE1nc34OpIyoVGPeqLC+ryw==", + "node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/environment": "^27.0.6", - "@jest/types": "^27.0.6", - "expect": "^27.0.6" + "@jest/get-type": "30.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/reporters": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.0.6.tgz", - "integrity": "sha512-TIkBt09Cb2gptji3yJXb3EE+eVltW6BjO7frO7NEfjI9vSIYoISi5R3aI3KpEDXlB1xwB+97NXIqz84qYeYsfA==", + "node_modules/@jest/expect-utils/node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect/node_modules/@jest/expect-utils": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.0.5.tgz", + "integrity": "sha512-F3lmTT7CXWYywoVUGTCmom0vXq3HTTkaZyTAzIy+bXSBizB7o5qzlC9VCtq0arOa8GqmNsbg/cE9C6HLn7Szew==", "dev": true, + "license": "MIT", "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-util": "^27.0.6", - "jest-worker": "^27.0.6", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.0.0" + "@jest/get-type": "30.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/reporters/node_modules/ansi-styles": { + "node_modules/@jest/expect/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2045,11 +2308,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/reporters/node_modules/chalk": { + "node_modules/@jest/expect/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2061,11 +2325,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/reporters/node_modules/color-convert": { + "node_modules/@jest/expect/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/expect/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2073,190 +2354,159 @@ "node": ">=7.0.0" } }, - "node_modules/@jest/reporters/node_modules/color-name": { + "node_modules/@jest/expect/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/reporters/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@jest/expect/node_modules/expect": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.0.5.tgz", + "integrity": "sha512-P0te2pt+hHI5qLJkIR+iMvS+lYUZml8rKKsohVHAGY+uClp9XVbdyYNJOIjSRpHVp8s8YqxJCiHUkSYZGr8rtQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@jest/expect-utils": "30.0.5", + "@jest/get-type": "30.0.1", + "jest-matcher-utils": "30.0.5", + "jest-message-util": "30.0.5", + "jest-mock": "30.0.5", + "jest-util": "30.0.5" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/source-map": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", - "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", + "node_modules/@jest/expect/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, + "license": "MIT", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8" } }, - "node_modules/@jest/source-map/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "node_modules/@jest/test-result": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.0.6.tgz", - "integrity": "sha512-ja/pBOMTufjX4JLEauLxE3LQBPaI2YjGFtXexRAjt1I/MbfNlMx0sytSX3tn5hSLzQsR3Qy2rd0hc1BWojtj9w==", + "node_modules/@jest/expect/node_modules/jest-diff": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.0.5.tgz", + "integrity": "sha512-1UIqE9PoEKaHcIKvq2vbibrCog4Y8G0zmOxgQUVEiTqwR5hJVMCoDsN1vFvI5JvwD37hjueZ1C4l2FyGnfpE0A==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/console": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.0.1", + "chalk": "^4.1.2", + "pretty-format": "30.0.5" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/test-sequencer": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.0.6.tgz", - "integrity": "sha512-bISzNIApazYOlTHDum9PwW22NOyDa6VI31n6JucpjTVM0jD6JDgqEZ9+yn575nDdPF0+4csYDxNNW13NvFQGZA==", + "node_modules/@jest/expect/node_modules/jest-matcher-utils": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.0.5.tgz", + "integrity": "sha512-uQgGWt7GOrRLP1P7IwNWwK1WAQbq+m//ZY0yXygyfWp0rJlksMSLQAA4wYQC3b6wl3zfnchyTx+k3HZ5aPtCbQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/test-result": "^27.0.6", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.0.6", - "jest-runtime": "^27.0.6" + "@jest/get-type": "30.0.1", + "chalk": "^4.1.2", + "jest-diff": "30.0.5", + "pretty-format": "30.0.5" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/test-sequencer/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "node_modules/@jest/transform": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.0.6.tgz", - "integrity": "sha512-rj5Dw+mtIcntAUnMlW/Vju5mr73u8yg+irnHwzgtgoeI6cCPOvUwQ0D1uQtc/APmWgvRweEb1g05pkUpxH3iCA==", + "node_modules/@jest/expect/node_modules/jest-message-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.5.tgz", + "integrity": "sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.0.6", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-util": "^27.0.6", - "micromatch": "^4.0.4", - "pirates": "^4.0.1", + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.0.5", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.0.5", "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "stack-utils": "^2.0.6" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/transform/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@jest/expect/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@jest/expect/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@jest/transform/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@jest/expect/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": ">=7.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/transform/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/transform/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "node_modules/@jest/transform/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@jest/expect/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/transform/node_modules/supports-color": { + "node_modules/@jest/expect/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -2264,27 +2514,30 @@ "node": ">=8" } }, - "node_modules/@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "node_modules/@jest/fake-timers": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.0.5.tgz", + "integrity": "sha512-ZO5DHfNV+kgEAeP3gK3XlpJLL4U3Sz6ebl/n68Uwt64qFFs5bv4bfEEjyRGK5uM0C90ewooNgFuKMdkbEoMEXw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@jest/types": "30.0.5", + "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "jest-message-util": "30.0.5", + "jest-mock": "30.0.5", + "jest-util": "30.0.5" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/types/node_modules/ansi-styles": { + "node_modules/@jest/fake-timers/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2295,11 +2548,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/types/node_modules/chalk": { + "node_modules/@jest/fake-timers/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2311,11 +2565,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", + "node_modules/@jest/fake-timers/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/fake-timers/node_modules/color-convert": { + "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2323,822 +2594,893 @@ "node": ">=7.0.0" } }, - "node_modules/@jest/types/node_modules/color-name": { + "node_modules/@jest/fake-timers/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/@jest/types/node_modules/has-flag": { + "node_modules/@jest/fake-timers/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@jest/fake-timers/node_modules/jest-message-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.5.tgz", + "integrity": "sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.0.5", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.0.5", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@jest/fake-timers/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" }, "engines": { - "node": ">= 8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@jest/fake-timers/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@jest/fake-timers/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", "dev": true, + "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": ">= 8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "node_modules/@jest/fake-timers/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "type-detect": "4.0.8" + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", - "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "node_modules/@jest/fake-timers/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "@sinonjs/commons": "^1.7.0" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "node_modules/@jest/get-type": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.0.1.tgz", + "integrity": "sha512-AyYdemXCptSRFirI5EPazNxyPwAL0jXt3zceFjaj8NFiKP9pOi0bfXonf6qkf82z2t3QWPeLCWWw4stPBzctLw==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@types/babel__core": { - "version": "7.1.15", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz", - "integrity": "sha512-bxlMKPDbY8x5h6HBwVzEOk2C8fb6SLfYQ5Jw3uBYuYF1lfWk/kbLd81la82vrIkBb0l+JdmrZaDikPrNxpS/Ew==", + "node_modules/@jest/globals": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.0.5.tgz", + "integrity": "sha512-7oEJT19WW4oe6HR7oLRvHxwlJk2gev0U9px3ufs8sX9PoD1Eza68KF0/tlN7X0dq/WVsBScXQGgCldA1V9Y/jA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "@jest/environment": "30.0.5", + "@jest/expect": "30.0.5", + "@jest/types": "30.0.5", + "jest-mock": "30.0.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@types/babel__generator": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", - "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.0.0" + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "node_modules/@jest/reporters": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.0.5.tgz", + "integrity": "sha512-mafft7VBX4jzED1FwGC1o/9QUM2xebzavImZMeqnsklgcyxBto8mV4HzNSzUrryJ+8R9MFOM3HgYuDradWR+4g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.0.5", + "@jest/test-result": "30.0.5", + "@jest/transform": "30.0.5", + "@jest/types": "30.0.5", + "@jridgewell/trace-mapping": "^0.3.25", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.0.5", + "jest-util": "30.0.5", + "jest-worker": "30.0.5", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "node_modules/@jest/reporters/node_modules/@jest/transform": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.5.tgz", + "integrity": "sha512-Vk8amLQCmuZyy6GbBht1Jfo9RSdBtg7Lks+B0PecnjI8J+PCLQPGh7uI8Q/2wwpW2gLdiAfiHNsmekKlywULqg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.3.0" + "@babel/core": "^7.27.4", + "@jest/types": "30.0.5", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.0", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.0.5", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@types/chalk": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/chalk/-/chalk-2.2.0.tgz", - "integrity": "sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw==", - "deprecated": "This is a stub types definition for chalk (https://github.com/chalk/chalk). chalk provides its own type definitions, so you don't need @types/chalk installed!", + "node_modules/@jest/reporters/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "*" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@types/eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", - "dev": true - }, - "node_modules/@types/events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", - "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", - "dev": true - }, - "node_modules/@types/glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", - "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*" + "balanced-match": "^1.0.0" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "*" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "node_modules/@jest/reporters/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/@types/jest": { - "version": "24.0.18", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.18.tgz", - "integrity": "sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ==", + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/jest-diff": "*" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@types/jest-diff": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz", - "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", - "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", - "dev": true - }, - "node_modules/@types/lodash": { - "version": "4.14.144", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz", - "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" }, - "node_modules/@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "dev": true + "node_modules/@jest/reporters/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "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/@types/node": { - "version": "12.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz", - "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==", - "dev": true + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/@types/node-fetch": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz", - "integrity": "sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==", + "node_modules/@jest/reporters/node_modules/jest-haste-map": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.5.tgz", + "integrity": "sha512-dkmlWNlsTSR0nH3nRfW5BKbqHefLZv0/6LCccG0xFCTWcJu8TuEwG+5Cm75iBfjVoockmO6J35o5gxtFSn5xeg==", "dev": true, + "license": "MIT", "dependencies": { + "@jest/types": "30.0.5", "@types/node": "*", - "form-data": "^3.0.0" + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "jest-worker": "30.0.5", + "micromatch": "^4.0.8", + "walker": "^1.0.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" } }, - "node_modules/@types/node-fetch/node_modules/form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "node_modules/@jest/reporters/node_modules/jest-message-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.5.tgz", + "integrity": "sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA==", "dev": true, + "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.0.5", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.0.5", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" }, "engines": { - "node": ">= 6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.2.tgz", - "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", - "dev": true - }, - "node_modules/@types/promise-retry": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@types/promise-retry/-/promise-retry-1.1.3.tgz", - "integrity": "sha512-LxIlEpEX6frE3co3vCO2EUJfHIta1IOmhDlcAsR4GMMv9hev1iTI9VwberVGkePJAuLZs5rMucrV8CziCfuJMw==", + "node_modules/@jest/reporters/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", "dependencies": { - "@types/retry": "*" + "@jest/types": "30.0.5", + "@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/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true - }, - "node_modules/@types/rimraf": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.0.tgz", - "integrity": "sha512-7WhJ0MdpFgYQPXlF4Dx+DhgvlPCfz/x5mHaeDQAKhcenvQP1KCpLQ18JklAqeGMYSAT2PxLpzd0g2/HE7fj7hQ==", + "node_modules/@jest/reporters/node_modules/jest-worker": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.0.5.tgz", + "integrity": "sha512-ojRXsWzEP16NdUuBw/4H/zkZdHOa7MMYCk4E430l+8fELeLg/mqmMlRhjL7UNZvQrDmnovWZV4DxX03fZF48fQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/glob": "*", - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/table": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@types/table/-/table-4.0.7.tgz", - "integrity": "sha512-HKtXvBxU8U8evZCSlUi9HbfT/SFW7nSGCoiBEheB06jAhXeW6JbGh8biEAqIFG5rZo9f8xeJVdIn455sddmIcw==", - "dev": true - }, - "node_modules/@types/url-template": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/@types/url-template/-/url-template-2.0.28.tgz", - "integrity": "sha512-1i/YtOhvlWDbMDTWhCfvhyUwBS9vNFs78sJOyahoruJCcDbwaSH73AlnuCp7luKPm6qqdCg4VKq/IHUncl6gZA==", - "dev": true + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.0.5", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } }, - "node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "node_modules/@jest/reporters/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { - "@types/yargs-parser": "*" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", - "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { - "@typescript-eslint/experimental-utils": "2.34.0", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.0.0", - "tsutils": "^3.17.1" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": ">=16 || 14 >=14.17" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^2.0.0", - "eslint": "^5.0.0 || ^6.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "node_modules/@jest/reporters/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", - "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", + "node_modules/@jest/reporters/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.34.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "node": ">=8" } }, - "node_modules/@typescript-eslint/parser": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", - "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.34.0", - "@typescript-eslint/typescript-estree": "2.34.0", - "eslint-visitor-keys": "^1.1.0" + "@sinclair/typebox": "^0.34.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.0.5.tgz", + "integrity": "sha512-XcCQ5qWHLvi29UUrowgDFvV4t7ETxX91CbDczMnoqXPOIcZOxyNdSjm6kV5XMc8+HkxfRegU/MUmnTbJRzGrUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.0.5", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", - "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", + "node_modules/@jest/snapshot-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.1.1", - "eslint-visitor-keys": "^1.1.0", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "color-convert": "^2.0.1" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "node_modules/@jest/snapshot-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "*" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@jest/snapshot-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "color-name": "~1.1.4" }, "engines": { - "node": ">=10" + "node": ">=7.0.0" } }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true + "node_modules/@jest/snapshot-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/@jest/snapshot-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, + "license": "MIT", "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "node_modules/@jest/snapshot-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/acorn-jsx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", - "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", + "node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0" + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "node_modules/@jest/source-map/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, - "engines": { - "node": ">=0.4.0" + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/add-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", - "integrity": "sha1-anmQQ3ynNtXhKI25K9MmbV9csqo=", - "dev": true - }, - "node_modules/adm-zip": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.13.tgz", - "integrity": "sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==", + "node_modules/@jest/test-result": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.0.5.tgz", + "integrity": "sha512-wPyztnK0gbDMQAJZ43tdMro+qblDHH1Ru/ylzUo21TBKqt88ZqnKKK2m30LKmLLoKtR2lxdpCC/P3g1vfKcawQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.0.5", + "@jest/types": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" + }, "engines": { - "node": ">=0.3.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "node_modules/@jest/test-sequencer": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.0.5.tgz", + "integrity": "sha512-Aea/G1egWoIIozmDD7PBXUOxkekXl7ueGzrsGGi1SbeKgQqCYCIf+wfbflEbf2LiPxL8j2JZGLyrzZagjvW4YQ==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "4" + "@jest/test-result": "30.0.5", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.0.5", + "slash": "^3.0.0" }, "engines": { - "node": ">= 6.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/ajv": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", - "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "node_modules/@jest/test-sequencer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", "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" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "node_modules/@jest/test-sequencer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "node_modules/@jest/test-sequencer/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@jest/test-sequencer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=4" + "node": ">=7.0.0" } }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "node_modules/@jest/test-sequencer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/test-sequencer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/test-sequencer/node_modules/jest-haste-map": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.5.tgz", + "integrity": "sha512-dkmlWNlsTSR0nH3nRfW5BKbqHefLZv0/6LCccG0xFCTWcJu8TuEwG+5Cm75iBfjVoockmO6J35o5gxtFSn5xeg==", "dev": true, + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "@jest/types": "30.0.5", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "jest-worker": "30.0.5", + "micromatch": "^4.0.8", + "walker": "^1.0.8" }, "engines": { - "node": ">= 8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" } }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "node_modules/are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "node_modules/@jest/test-sequencer/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "@jest/types": "30.0.5", + "@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/are-we-there-yet/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "node_modules/@jest/test-sequencer/node_modules/jest-worker": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.0.5.tgz", + "integrity": "sha512-ojRXsWzEP16NdUuBw/4H/zkZdHOa7MMYCk4E430l+8fELeLg/mqmMlRhjL7UNZvQrDmnovWZV4DxX03fZF48fQ==", "dev": true, + "license": "MIT", "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/are-we-there-yet/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/are-we-there-yet/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.0.5", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/arg": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz", - "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@jest/test-sequencer/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "node_modules/@jest/test-sequencer/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "node_modules/@jest/test-sequencer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/axios": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.2.tgz", - "integrity": "sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg==", + "license": "MIT", "dependencies": { - "follow-redirects": "^1.14.0" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/axios-mock-adapter": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.19.0.tgz", - "integrity": "sha512-D+0U4LNPr7WroiBDvWilzTMYPYTuZlbo6BI8YHZtj7wYQS8NkARlP9KBt8IWWHTQJ0q/8oZ0ClPBtKCCkx8cQg==", + "node_modules/@jest/types": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz", + "integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==", "dev": true, + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3", - "is-buffer": "^2.0.3" + "@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" }, - "peerDependencies": { - "axios": ">= 0.9.0" - } - }, - "node_modules/axios-mock-adapter/node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "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" - } - ], "engines": { - "node": ">=4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/babel-jest": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.0.6.tgz", - "integrity": "sha512-iTJyYLNc4wRofASmofpOc5NK9QunwMk+TLFgGXsTFS8uEqmd8wdI7sga0FPe2oVH3b5Agt/EAK1QjPEuKL8VfA==", + "node_modules/@jest/types/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.0.6", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" + "@types/yargs-parser": "*" } }, - "node_modules/babel-jest/node_modules/ansi-styles": { + "node_modules/@jest/types/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3149,11 +3491,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/babel-jest/node_modules/chalk": { + "node_modules/@jest/types/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3165,11 +3508,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/babel-jest/node_modules/color-convert": { + "node_modules/@jest/types/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3177,32 +3521,29 @@ "node": ">=7.0.0" } }, - "node_modules/babel-jest/node_modules/color-name": { + "node_modules/@jest/types/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/babel-jest/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/babel-jest/node_modules/has-flag": { + "node_modules/@jest/types/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/babel-jest/node_modules/supports-color": { + "node_modules/@jest/types/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3210,2085 +3551,2247 @@ "node": ">=8" } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", - "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": "^4.0.0", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.6.tgz", - "integrity": "sha512-CewFeM9Vv2gM7Yr9n5eyyLVPRSiBnk6lKZRjgwYnGKSl9M14TMn2vkN02wTF04OGuSDLEzlWiMzvjXuW9mB6Gw==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@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-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/babel-preset-jest": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.0.6.tgz", - "integrity": "sha512-WObA0/Biw2LrVVwZkF/2GqbOdzhKD6Fkdwhoy9ASIrOWr/zodcSpQh72JOkEn6NWyjmnPDjNSqaGN4KnpKzhXw==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^27.0.6", - "babel-preset-current-node-syntax": "^1.0.0" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=6.0.0" } }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "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" - } - ] + "license": "MIT" }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" } }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.16.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.7.tgz", - "integrity": "sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, - "dependencies": { - "caniuse-lite": "^1.0.30001248", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.793", - "escalade": "^3.1.1", - "node-releases": "^1.1.73" - }, - "bin": { - "browserslist": "cli.js" - }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + "node": ">= 8" } }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { - "fast-json-stable-stringify": "2.x" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">= 6" + "node": ">= 8" } }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, - "dependencies": { - "node-int64": "^0.4.0" + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "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" + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" } }, - "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "node_modules/cachedir": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.2.0.tgz", - "integrity": "sha512-VvxA0xhNqIIfg0V9AmJkDg91DaJwryutH5rVEZAhcNi4iJFj9f+QxmAjgK1LT9I8OgToX27fypX6/MeCXVbBjQ==", + "node_modules/@sinclair/typebox": { + "version": "0.34.40", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.40.tgz", + "integrity": "sha512-gwBNIP8ZAYev/ORDWW0QvxdwPXwxBtLsdsJgSc7eDIRt8ubP+rxUBzPsrwnu16fgEF8Bx4lh/+mvQvJzcTM6Kw==", "dev": true, - "engines": { - "node": ">=6" - } + "license": "MIT" }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "callsites": "^2.0.0" - }, - "engines": { - "node": ">=4" + "type-detect": "4.0.8" } }, - "node_modules/caller-callsite/node_modules/callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", "dev": true, - "engines": { - "node": ">=4" + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" } }, - "node_modules/caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "caller-callsite": "^2.0.0" - }, - "engines": { - "node": ">=4" + "tslib": "^2.4.0" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, - "engines": { - "node": ">=6" + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "engines": { - "node": ">=6" + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" } }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, + "license": "MIT", "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001251", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz", - "integrity": "sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A==", + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" } }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@types/cli-progress": { + "version": "3.11.6", + "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.6.tgz", + "integrity": "sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA==", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" + "@types/node": "*" } }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "node_modules/@types/conventional-commits-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.1.tgz", + "integrity": "sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==", "dev": true, - "engines": { - "node": ">=10" + "license": "MIT", + "dependencies": { + "@types/node": "*" } }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "node_modules/@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", "dev": true }, - "node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", "dev": true, "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" + "@types/node": "*" } }, - "node_modules/cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "node_modules/@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" } }, - "node_modules/cliui/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" + "@types/node": "*" } }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } + "license": "MIT" }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" } }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "expect": "^30.0.0", + "pretty-format": "^30.0.0" } }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" }, - "node_modules/colorette": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.3.0.tgz", - "integrity": "sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==", + "node_modules/@types/lodash": { + "version": "4.14.144", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz", + "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg==", "dev": true }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.17.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.19.tgz", + "integrity": "sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" + "undici-types": "~6.19.2" } }, - "node_modules/commitizen": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.4.tgz", - "integrity": "sha512-LlZChbDzg3Ir3O2S7jSo/cgWp5/QwylQVr59K4xayVq8S4/RdKzSyJkghAiZZHfhh5t4pxunUoyeg0ml1q/7aw==", + "node_modules/@types/node-fetch": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz", + "integrity": "sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==", "dev": true, "dependencies": { - "cachedir": "2.2.0", - "cz-conventional-changelog": "3.2.0", - "dedent": "0.7.0", - "detect-indent": "6.0.0", - "find-node-modules": "^2.1.2", - "find-root": "1.1.0", - "fs-extra": "8.1.0", - "glob": "7.1.4", - "inquirer": "6.5.2", - "is-utf8": "^0.2.1", - "lodash": "^4.17.20", - "minimist": "1.2.5", - "strip-bom": "4.0.0", - "strip-json-comments": "3.0.1" - }, - "bin": { - "commitizen": "bin/commitizen", - "cz": "bin/git-cz", - "git-cz": "bin/git-cz" - }, - "engines": { - "node": ">= 10" + "@types/node": "*", + "form-data": "^3.0.0" } }, - "node_modules/commitizen/node_modules/conventional-commit-types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", - "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", + "node_modules/@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", "dev": true }, - "node_modules/commitizen/node_modules/cz-conventional-changelog": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.2.0.tgz", - "integrity": "sha512-yAYxeGpVi27hqIilG1nh4A9Bnx4J3Ov+eXy4koL3drrR+IO9GaWPsKjik20ht608Asqi8TQPf0mczhEeyAtMzg==", + "node_modules/@types/rimraf": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-7WhJ0MdpFgYQPXlF4Dx+DhgvlPCfz/x5mHaeDQAKhcenvQP1KCpLQ18JklAqeGMYSAT2PxLpzd0g2/HE7fj7hQ==", "dev": true, "dependencies": { - "chalk": "^2.4.1", - "commitizen": "^4.0.3", - "conventional-commit-types": "^3.0.0", - "lodash.map": "^4.5.1", - "longest": "^2.0.1", - "word-wrap": "^1.0.3" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@commitlint/load": ">6.1.1" + "@types/glob": "*", + "@types/node": "*" } }, - "node_modules/commitizen/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" }, - "node_modules/commitizen/node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "node_modules/@types/table": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@types/table/-/table-4.0.7.tgz", + "integrity": "sha512-HKtXvBxU8U8evZCSlUi9HbfT/SFW7nSGCoiBEheB06jAhXeW6JbGh8biEAqIFG5rZo9f8xeJVdIn455sddmIcw==", "dev": true }, - "node_modules/commitizen/node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/@types/url-template": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/@types/url-template/-/url-template-2.0.28.tgz", + "integrity": "sha512-1i/YtOhvlWDbMDTWhCfvhyUwBS9vNFs78sJOyahoruJCcDbwaSH73AlnuCp7luKPm6qqdCg4VKq/IHUncl6gZA==", + "dev": true }, - "node_modules/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "node_modules/@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", "dev": true, + "license": "MIT", "dependencies": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" + "@types/yargs-parser": "*" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true, - "engines": [ - "node >= 6.0" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } + "license": "MIT" }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true - }, - "node_modules/conventional-changelog": { - "version": "3.1.24", - "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.24.tgz", - "integrity": "sha512-ed6k8PO00UVvhExYohroVPXcOJ/K1N0/drJHx/faTH37OIZthlecuLIRX/T6uOp682CAoVoFpu+sSEaeuH6Asg==", - "dev": true, - "dependencies": { - "conventional-changelog-angular": "^5.0.12", - "conventional-changelog-atom": "^2.0.8", - "conventional-changelog-codemirror": "^2.0.8", - "conventional-changelog-conventionalcommits": "^4.5.0", - "conventional-changelog-core": "^4.2.1", - "conventional-changelog-ember": "^2.0.9", - "conventional-changelog-eslint": "^3.0.9", - "conventional-changelog-express": "^2.0.6", - "conventional-changelog-jquery": "^3.0.11", - "conventional-changelog-jshint": "^2.0.9", - "conventional-changelog-preset-loader": "^2.3.4" + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz", + "integrity": "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.24.1", + "@typescript-eslint/type-utils": "8.24.1", + "@typescript-eslint/utils": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, - "node_modules/conventional-changelog-angular": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz", - "integrity": "sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw==", + "node_modules/@typescript-eslint/parser": { + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.1.tgz", + "integrity": "sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "compare-func": "^2.0.0", - "q": "^1.5.1" + "@typescript-eslint/scope-manager": "8.24.1", + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/typescript-estree": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1", + "debug": "^4.3.4" }, "engines": { - "node": ">=10" + "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 <5.8.0" } }, - "node_modules/conventional-changelog-atom": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz", - "integrity": "sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.1.tgz", + "integrity": "sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==", "dev": true, + "license": "MIT", "dependencies": { - "q": "^1.5.1" + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/conventional-changelog-codemirror": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz", - "integrity": "sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.1.tgz", + "integrity": "sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw==", "dev": true, + "license": "MIT", "dependencies": { - "q": "^1.5.1" + "@typescript-eslint/typescript-estree": "8.24.1", + "@typescript-eslint/utils": "8.24.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" }, "engines": { - "node": ">=10" + "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 <5.8.0" } }, - "node_modules/conventional-changelog-config-spec": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz", - "integrity": "sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ==", - "dev": true - }, - "node_modules/conventional-changelog-conventionalcommits": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.5.0.tgz", - "integrity": "sha512-buge9xDvjjOxJlyxUnar/+6i/aVEVGA7EEh4OafBCXPlLUQPGbRUBhBUveWRxzvR8TEjhKEP4BdepnpG2FSZXw==", + "node_modules/@typescript-eslint/types": { + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.1.tgz", + "integrity": "sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==", "dev": true, - "dependencies": { - "compare-func": "^2.0.0", - "lodash": "^4.17.15", - "q": "^1.5.1" - }, + "license": "MIT", "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-conventionalcommits/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/conventional-changelog-core": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.3.tgz", - "integrity": "sha512-MwnZjIoMRL3jtPH5GywVNqetGILC7g6RQFvdb8LRU/fA/338JbeWAku3PZ8yQ+mtVRViiISqJlb0sOz0htBZig==", - "dev": true, - "dependencies": { - "add-stream": "^1.0.0", - "conventional-changelog-writer": "^5.0.0", - "conventional-commits-parser": "^3.2.0", - "dateformat": "^3.0.0", - "get-pkg-repo": "^4.0.0", - "git-raw-commits": "^2.0.8", - "git-remote-origin-url": "^2.0.0", - "git-semver-tags": "^4.1.1", - "lodash": "^4.17.15", - "normalize-package-data": "^3.0.0", - "q": "^1.5.1", - "read-pkg": "^3.0.0", - "read-pkg-up": "^3.0.0", - "through2": "^4.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "engines": { - "node": ">=10" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/conventional-changelog-core/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.1.tgz", + "integrity": "sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg==", "dev": true, + "license": "MIT", "dependencies": { - "locate-path": "^2.0.0" + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" }, "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, - "node_modules/conventional-changelog-core/node_modules/hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" + "balanced-match": "^1.0.0" } }, - "node_modules/conventional-changelog-core/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/conventional-changelog-core/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/conventional-changelog-core/node_modules/normalize-package-data": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", - "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", + "node_modules/@typescript-eslint/utils": { + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.1.tgz", + "integrity": "sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ==", "dev": true, + "license": "MIT", "dependencies": { - "hosted-git-info": "^4.0.1", - "resolve": "^1.20.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.24.1", + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/typescript-estree": "8.24.1" }, "engines": { - "node": ">=10" + "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 <5.8.0" } }, - "node_modules/conventional-changelog-core/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.1.tgz", + "integrity": "sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==", "dev": true, + "license": "MIT", "dependencies": { - "p-try": "^1.0.0" + "@typescript-eslint/types": "8.24.1", + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/conventional-changelog-core/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/conventional-changelog-core/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "dev": true, - "engines": { - "node": ">=4" - } + "license": "ISC" }, - "node_modules/conventional-changelog-core/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/conventional-changelog-core/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], "dev": true, - "engines": { - "node": ">=4" - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/conventional-changelog-core/node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/conventional-changelog-core/node_modules/read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - }, - "engines": { - "node": ">=4" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/conventional-changelog-core/node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/conventional-changelog-core/node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], "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" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/conventional-changelog-core/node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], "dev": true, - "bin": { - "semver": "bin/semver" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/conventional-changelog-core/node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "@napi-rs/wasm-runtime": "^0.2.11" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/conventional-changelog-core/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@yao-pkg/pkg": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@yao-pkg/pkg/-/pkg-6.5.1.tgz", + "integrity": "sha512-z6XlySYfnqfm1AfVlBN8A3yeAQniIwL7TKQfDCGsswYSVYLt2snbRefQYsfQQ3pw5lVXrZdLqgTjzaqID9IkWA==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" + "@babel/generator": "^7.23.0", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", + "@yao-pkg/pkg-fetch": "3.5.23", + "into-stream": "^6.0.0", + "minimist": "^1.2.6", + "multistream": "^4.1.0", + "picocolors": "^1.1.0", + "picomatch": "^4.0.2", + "prebuild-install": "^7.1.1", + "resolve": "^1.22.10", + "stream-meter": "^1.0.4", + "tar": "^7.4.3", + "tinyglobby": "^0.2.11", + "unzipper": "^0.12.3" }, "bin": { - "semver": "bin/semver.js" + "pkg": "lib-es5/bin.js" }, "engines": { - "node": ">=10" + "node": ">=18.0.0" } }, - "node_modules/conventional-changelog-ember": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz", - "integrity": "sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==", + "node_modules/@yao-pkg/pkg-fetch": { + "version": "3.5.23", + "resolved": "https://registry.npmjs.org/@yao-pkg/pkg-fetch/-/pkg-fetch-3.5.23.tgz", + "integrity": "sha512-rn45sqVQSkcJNSBdTnYze3n+kyub4CN8aiWYlPgA9yp9FZeEF+BlpL68kSIm3HaVuANniF+7RBMH5DkC4zlHZA==", "dev": true, + "license": "MIT", "dependencies": { - "q": "^1.5.1" + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.6", + "picocolors": "^1.1.0", + "progress": "^2.0.3", + "semver": "^7.3.5", + "tar-fs": "^2.1.1", + "yargs": "^16.2.0" }, - "engines": { - "node": ">=10" + "bin": { + "pkg-fetch": "lib-es5/bin.js" } }, - "node_modules/conventional-changelog-eslint": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz", - "integrity": "sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==", + "node_modules/@yao-pkg/pkg-fetch/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "q": "^1.5.1" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/conventional-changelog-express": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz", - "integrity": "sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==", + "node_modules/@yao-pkg/pkg-fetch/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, + "license": "ISC", "dependencies": { - "q": "^1.5.1" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/@yao-pkg/pkg-fetch/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" }, "engines": { - "node": ">=10" + "node": ">=7.0.0" } }, - "node_modules/conventional-changelog-jquery": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz", - "integrity": "sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==", + "node_modules/@yao-pkg/pkg-fetch/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@yao-pkg/pkg-fetch/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { - "q": "^1.5.1" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/conventional-changelog-jshint": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz", - "integrity": "sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==", + "node_modules/@yao-pkg/pkg-fetch/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { - "compare-func": "^2.0.0", - "q": "^1.5.1" + "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/conventional-changelog-preset-loader": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", - "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", + "node_modules/@yao-pkg/pkg-fetch/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, - "node_modules/conventional-changelog-writer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz", - "integrity": "sha512-HnDh9QHLNWfL6E1uHz6krZEQOgm8hN7z/m7tT16xwd802fwgMN0Wqd7AQYVkhpsjDUx/99oo+nGgvKF657XP5g==", + "node_modules/@yao-pkg/pkg-fetch/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, + "license": "MIT", "dependencies": { - "conventional-commits-filter": "^2.0.7", - "dateformat": "^3.0.0", - "handlebars": "^4.7.6", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "semver": "^6.0.0", - "split": "^1.0.0", - "through2": "^4.0.0" - }, - "bin": { - "conventional-changelog-writer": "cli.js" + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" }, "engines": { "node": ">=10" } }, - "node_modules/conventional-changelog-writer/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/conventional-commit-types": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-2.1.1.tgz", - "integrity": "sha512-0Ts+fEdmjqYDOQ1yZ+LNgdSPO335XZw9qC10M7CxtLP3nIMGmeMhmkM8Taffa4+MXN13bRPlp0CtH+QfOzKTzw==", - "dev": true - }, - "node_modules/conventional-commits-filter": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", - "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", + "node_modules/@yao-pkg/pkg/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "dependencies": { - "lodash.ismatch": "^4.4.0", - "modify-values": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/conventional-commits-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz", - "integrity": "sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA==", + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, - "dependencies": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.0.4", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0", - "trim-off-newlines": "^1.0.0" - }, + "license": "MIT", + "peer": true, "bin": { - "conventional-commits-parser": "cli.js" + "acorn": "bin/acorn" }, "engines": { - "node": ">=10" + "node": ">=0.4.0" } }, - "node_modules/conventional-commits-parser/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "node_modules/conventional-recommended-bump": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz", - "integrity": "sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw==", + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, + "license": "MIT", "dependencies": { - "concat-stream": "^2.0.0", - "conventional-changelog-preset-loader": "^2.3.4", - "conventional-commits-filter": "^2.0.7", - "conventional-commits-parser": "^3.2.0", - "git-raw-commits": "^2.0.8", - "git-semver-tags": "^4.1.1", - "meow": "^8.0.0", - "q": "^1.5.1" - }, - "bin": { - "conventional-recommended-bump": "cli.js" + "debug": "4" }, "engines": { - "node": ">=10" + "node": ">= 6.0.0" } }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.1" + "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/convert-source-map/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "engines": { + "node": ">=6" + } }, - "node_modules/cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" + "type-fest": "^0.21.3" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cosmiconfig/node_modules/import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - }, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cosmiconfig/node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=4.8" - } - }, - "node_modules/cross-spawn/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" + "node": ">=4" } }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { - "cssom": "~0.3.6" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "node_modules/arg": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz", + "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", "dev": true }, - "node_modules/cz-conventional-changelog": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.0.2.tgz", - "integrity": "sha512-MPxERbtQyVp0nnpCBiwzKGKmMBSswmCV3Jpef3Axqd5f3c/SOc6VFiSUlclOyZXBn3Xtf4snzt4O15hBTRb2gA==", + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "dependencies": { - "chalk": "^2.4.1", - "commitizen": "^4.0.3", - "conventional-commit-types": "^2.0.0", - "lodash.map": "^4.5.1", - "longest": "^2.0.1", - "right-pad": "^1.0.1", - "word-wrap": "^1.0.3" - }, + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true, + "license": "MIT" + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@commitlint/load": ">6.1.1" + "node": ">=4" } }, - "node_modules/dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, + "license": "ISC", "engines": { - "node": ">=8" + "node": ">= 4.0.0" } }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios-mock-adapter": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.19.0.tgz", + "integrity": "sha512-D+0U4LNPr7WroiBDvWilzTMYPYTuZlbo6BI8YHZtj7wYQS8NkARlP9KBt8IWWHTQJ0q/8oZ0ClPBtKCCkx8cQg==", "dev": true, "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" + "fast-deep-equal": "^3.1.3", + "is-buffer": "^2.0.3" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "axios": ">= 0.9.0" } }, - "node_modules/dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "node_modules/axios-mock-adapter/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", "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" + } + ], "engines": { - "node": "*" + "node": ">=4" } }, - "node_modules/dc-management-sdk-js": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/dc-management-sdk-js/-/dc-management-sdk-js-1.14.0.tgz", - "integrity": "sha512-M92cWMkwq8EscX7zklxEVNFNYadoyZEbz5+rta8JpPOxMGW9ysDitJETZ+4BNJxlnzi377PNQdlHyHfgnjKprg==", + "node_modules/axios-retry": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-4.5.0.tgz", + "integrity": "sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==", + "license": "Apache-2.0", "dependencies": { - "axios": "^0.21.1", - "url-template": "^2.0.8" + "is-retry-allowed": "^2.2.0" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "axios": "0.x || 1.x" } }, - "node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dev": true, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "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": ">=0.10.0" + "node": ">= 6" } }, - "node_modules/decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "node_modules/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", "dev": true, + "license": "BSD-3-Clause", + "workspaces": [ + "test/babel-8" + ], "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "MIT", + "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/decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true, - "engines": { - "node": ">=4.0.0" - } + "license": "MIT" }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "license": "MIT" }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, - "node_modules/detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "node_modules/browserslist": { + "version": "4.25.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.3.tgz", + "integrity": "sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==", "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" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "caniuse-lite": "^1.0.30001735", + "electron-to-chromium": "^1.5.204", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, "engines": { - "node": ">=0.10.0" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/detect-indent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", - "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" } }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, - "engines": { - "node": ">=8" + "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/diff": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", - "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, - "engines": { - "node": ">=0.3.1" - } + "license": "MIT" }, - "node_modules/diff-sequences": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", - "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", + "node_modules/cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", "dev": true, + "license": "MIT", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=6" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { - "path-type": "^4.0.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", "dev": true, "dependencies": { - "esutils": "^2.0.2" + "callsites": "^2.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=4" } }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "node_modules/caller-callsite/node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", "dev": true, "dependencies": { - "webidl-conversions": "^5.0.0" + "caller-callsite": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "dependencies": { - "is-obj": "^2.0.0" - }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/dotgitignore": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/dotgitignore/-/dotgitignore-2.1.0.tgz", - "integrity": "sha512-sCm11ak2oY6DglEPpCB8TixLjWAxd3kJTs6UIcSasNYxXdFPV+YKlye92c8H4kKFqV5qYMIh7d+cYecEg0dIkA==", + "node_modules/caniuse-lite": { + "version": "1.0.30001735", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001735.tgz", + "integrity": "sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w==", "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" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dependencies": { - "find-up": "^3.0.0", - "minimatch": "^3.0.4" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/electron-to-chromium": { - "version": "1.3.804", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.804.tgz", - "integrity": "sha512-GB+D82NbTO6/7mC0aRNv0LPOhof/fz4UX6D/CnxTVpiPgWna+HDQJMHgsf/Ne/itKn3akJul9L0kwvML2kp3Yg==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "license": "MIT" }, - "node_modules/end-of-stream": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.2.tgz", - "integrity": "sha512-gUSUszrsxlDnUbUwEI9Oygyrk4ZEWtVaHQc+uZHphVeNxl+qeqMV/jDWoTkjN1RmGlZ5QWAP7o458p/JMlikQg==", + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "dev": true, - "dependencies": { - "once": "^1.4.0" + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "node_modules/cjs-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz", + "integrity": "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==", "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } + "license": "MIT" }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "node_modules/cli-progress": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", + "license": "MIT", + "dependencies": { + "string-width": "^4.2.3" + }, "engines": { - "node": ">=0.8.0" + "node": ">=4" } }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, + "license": "MIT", "engines": { - "node": ">=6.0" + "node": ">=6" }, - "optionalDependencies": { - "source-map": "~0.6.1" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "dev": true, + "license": "ISC", "engines": { - "node": ">=4.0" + "node": ">= 10" } }, - "node_modules/eslint": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.4.0.tgz", - "integrity": "sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA==", - "dev": true, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dependencies": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.2", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.4.1", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", + "string-width": "^3.1.0", "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "wrap-ansi": "^5.1.0" } }, - "node_modules/eslint-config-prettier": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.3.0.tgz", - "integrity": "sha512-EWaGjlDAZRzVFveh2Jsglcere2KK5CJBhkNSa1xs3KfMUGdRiT7lG089eqPdvlzWHpAqaekubOsOMu8W8Yk71A==", - "dev": true, - "dependencies": { - "get-stdin": "^6.0.0" - }, - "bin": { - "eslint-config-prettier-check": "bin/cli.js" + "node_modules/cliui/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" }, - "peerDependencies": { - "eslint": ">=3.14.1" + "engines": { + "node": ">=6" } }, - "node_modules/eslint-config-prettier/node_modules/get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=0.8" } }, - "node_modules/eslint-plugin-prettier": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.1.tgz", - "integrity": "sha512-A+TZuHZ0KU0cnn56/9mfR7/KjUJ9QNVXUhwvRFSR7PGPe0zQR6PTkmyqg1AtUUEOzTqeRsUwyKFh0oVZKVCrtA==", + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": ">=6.0.0" - }, - "peerDependencies": { - "eslint": ">= 5.0.0", - "prettier": ">= 1.13.0" + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "node_modules/eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "delayed-stream": "~1.0.0" }, "engines": { - "node": ">=8.0.0" + "node": ">= 0.8" } }, - "node_modules/eslint-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", - "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", + "node_modules/commitizen": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.3.1.tgz", + "integrity": "sha512-gwAPAVTy/j5YcOOebcCRIijn+mSjWJC+IYKivTu6aG8Ei/scoXgfsMRnuAk6b0GRste2J4NGxVdMN3ZpfNaVaw==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^1.0.0" + "cachedir": "2.3.0", + "cz-conventional-changelog": "3.3.0", + "dedent": "0.7.0", + "detect-indent": "6.1.0", + "find-node-modules": "^2.1.2", + "find-root": "1.1.0", + "fs-extra": "9.1.0", + "glob": "7.2.3", + "inquirer": "8.2.5", + "is-utf8": "^0.2.1", + "lodash": "4.17.21", + "minimist": "1.2.7", + "strip-bom": "4.0.0", + "strip-json-comments": "3.1.1" + }, + "bin": { + "commitizen": "bin/commitizen", + "cz": "bin/git-cz", + "git-cz": "bin/git-cz" }, "engines": { - "node": ">=6" + "node": ">= 12" } }, - "node_modules/eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "node_modules/commitizen/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/eslint/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/espree": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz", - "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==", + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", "dev": true, + "license": "MIT", "dependencies": { - "acorn": "^7.0.0", - "acorn-jsx": "^5.0.2", - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6.0.0" + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=16" } }, - "node_modules/esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "node_modules/conventional-changelog-conventionalcommits": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", + "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", "dev": true, + "license": "ISC", "dependencies": { - "estraverse": "^4.0.0" + "compare-func": "^2.0.0" }, "engines": { - "node": ">=0.6" + "node": ">=16" } }, - "node_modules/esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "node_modules/conventional-commit-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", + "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", + "dev": true, + "license": "ISC" + }, + "node_modules/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", "dev": true, + "license": "MIT", "dependencies": { - "estraverse": "^4.1.0" + "is-text-path": "^2.0.0", + "JSONStream": "^1.3.5", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.mjs" }, "engines": { - "node": ">=4.0" + "node": ">=16" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "engines": { - "node": ">=4.0" - } + "license": "MIT" }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", "dev": true, "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "node_modules/cosmiconfig/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", "dev": true, + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, "engines": { - "node": ">= 0.8.0" + "node": ">=4" } }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "node_modules/cosmiconfig/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", "dev": true, "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, + "license": "MIT", "dependencies": { - "homedir-polyfill": "^1.0.1" + "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": ">=0.10.0" + "node": ">=4.8" } }, - "node_modules/expect": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.0.6.tgz", - "integrity": "sha512-psNLt8j2kwg42jGBDSfAlU49CEZxejN1f1PlANWDZqIhBOVU/c2Pm888FcjWJzFewhIsNWfZJeLjUjtKGiPuSw==", + "node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/cz-conventional-changelog": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", + "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^27.0.6", - "ansi-styles": "^5.0.0", - "jest-get-type": "^27.0.6", - "jest-matcher-utils": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-regex-util": "^27.0.6" + "chalk": "^2.4.1", + "commitizen": "^4.0.3", + "conventional-commit-types": "^3.0.0", + "lodash.map": "^4.5.1", + "longest": "^2.0.1", + "word-wrap": "^1.0.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 10" + }, + "optionalDependencies": { + "@commitlint/load": ">6.1.1" } }, - "node_modules/expect/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/dargs": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz", + "integrity": "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, + "node_modules/dc-management-sdk-js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/dc-management-sdk-js/-/dc-management-sdk-js-3.2.0.tgz", + "integrity": "sha512-S8aoObfEYlTtOvoo1Gt7Jt3ezNc4EDoK1t7fMPpk38XGuM8w12hSuKo6QhUpJZrV2agzbsyli2G9a4NgIsuT8g==", + "license": "Apache-2.0", "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" + "axios": "1.12.2", + "axios-retry": "4.5.0", + "url-template": "2.0.8" }, "engines": { - "node": ">=4" + "node": ">=20" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, + "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "ms": "^2.1.3" }, "engines": { - "node": ">=8" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fastq": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.1.tgz", - "integrity": "sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "dependencies": { - "bser": "2.1.1" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^2.0.1" + "mimic-response": "^3.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4.0.0" } }, - "node_modules/find-node-modules": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.2.tgz", - "integrity": "sha512-x+3P4mbtRPlSiVE1Qco0Z4YLU8WFiFcuWTf3m75OV9Uzcfs2Bg+O9N+r/K0AnmINBW06KpfqKwYJbFlFq4qNug==", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, - "dependencies": { - "findup-sync": "^4.0.0", - "merge": "^2.1.0" - } - }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true + "license": "MIT" }, - "node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/findup-sync": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", - "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, + "license": "MIT", "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^4.0.2", - "resolve-dir": "^1.0.1" + "clone": "^1.0.2" }, - "engines": { - "node": ">= 8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/findup-sync/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "engines": { - "node": ">=8" + "node": ">=0.4.0" } }, - "node_modules/findup-sync/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/findup-sync/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=8" } }, - "node_modules/findup-sync/node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, + "license": "Apache-2.0", "engines": { - "node": ">=8.6" + "node": ">=8" } }, - "node_modules/findup-sync/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8.0" + "node": ">=8" } }, - "node_modules/flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "node_modules/diff": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", "dev": true, - "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, "engines": { - "node": ">=4" + "node": ">=0.3.1" } }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "dev": true, + "license": "MIT", "dependencies": { - "glob": "^7.1.3" + "is-obj": "^2.0.0" }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/flatted": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "node": ">=8" } }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" }, "engines": { - "node": ">= 6" + "node": ">= 0.4" } }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" + "readable-stream": "^2.0.2" } }, - "node_modules/from2/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -5299,1698 +5802,1770 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/from2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" }, - "node_modules/from2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/electron-to-chromium": { + "version": "1.5.207", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.207.tgz", + "integrity": "sha512-mryFrrL/GXDTmAtIVMVf+eIXM09BBPlO5IQ7lUyKmK8d+A4VpRGG+M3ofoVef6qyF8s60rJei8ymlJxjUA8Faw==", "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } + "license": "ISC" }, - "node_modules/fs-access": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", - "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, - "dependencies": { - "null-check": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "node_modules/end-of-stream": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.2.tgz", + "integrity": "sha512-gUSUszrsxlDnUbUwEI9Oygyrk4ZEWtVaHQc+uZHphVeNxl+qeqMV/jDWoTkjN1RmGlZ5QWAP7o458p/JMlikQg==", "dev": true, "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dependencies": { + "ansi-colors": "^4.1.1" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=8.6" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], + "license": "MIT", "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=6" } }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "is-arrayish": "^0.2.1" } }, - "node_modules/gauge/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/gauge/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/gauge/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "es-errors": "^1.3.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/gauge/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=6" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=0.8.0" } }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, + "node_modules/eslint": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", + "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.15.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.32.0", + "@eslint/plugin-kit": "^0.3.4", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, "engines": { - "node": ">=8.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/get-pkg-repo": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.1.2.tgz", - "integrity": "sha512-/FjamZL9cBYllEbReZkxF2IMh80d8TJoC4e3bmLNif8ibHw95aj0N/tzqK0kZz9eU/3w3dL6lF4fnnX/sDdW3A==", + "node_modules/eslint-config-prettier": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.1.tgz", + "integrity": "sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==", "dev": true, - "dependencies": { - "@hutson/parse-repository-url": "^3.0.0", - "hosted-git-info": "^4.0.0", - "meow": "^7.0.0", - "through2": "^2.0.0" - }, + "license": "MIT", + "peer": true, "bin": { - "get-pkg-repo": "src/cli.js" + "eslint-config-prettier": "build/bin/cli.js" }, - "engines": { - "node": ">=6.9.0" + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "node_modules/get-pkg-repo/node_modules/hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "node_modules/eslint-plugin-prettier": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz", + "integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" }, "engines": { - "node": ">=10" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } } }, - "node_modules/get-pkg-repo/node_modules/meow": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-7.1.1.tgz", - "integrity": "sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==", + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^2.5.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.13.1", - "yargs-parser": "^18.1.3" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/get-pkg-repo/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "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" + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/get-pkg-repo/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/get-pkg-repo/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/get-pkg-repo/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/get-pkg-repo/node_modules/type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true, + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/get-pkg-repo/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=6" + "node": ">=7.0.0" } }, - "node_modules/get-stdin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", - "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "node_modules/eslint/node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { - "pump": "^3.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=6" + "node": ">= 8" } }, - "node_modules/git-raw-commits": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz", - "integrity": "sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ==", + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "dependencies": { - "dargs": "^7.0.0", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - }, - "bin": { - "git-raw-commits": "cli.js" - }, + "license": "MIT", "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/git-raw-commits/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/git-remote-origin-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", - "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "dependencies": { - "gitconfiglocal": "^1.0.0", - "pify": "^2.3.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/git-semver-tags": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", - "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { - "meow": "^8.0.0", - "semver": "^6.0.0" - }, - "bin": { - "git-semver-tags": "cli.js" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/gitconfiglocal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", - "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { - "ini": "^1.3.2" + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "dev": true - }, - "node_modules/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "p-locate": "^5.0.0" }, "engines": { - "node": ">= 6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { - "ini": "^1.3.4" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "node_modules/eslint/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "dependencies": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - }, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "node_modules/eslint/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "node_modules/eslint/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/globby/node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "node_modules/eslint/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 4" + "node": ">=8" } }, - "node_modules/graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", - "dev": true + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "node_modules/eslint/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" + "isexe": "^2.0.0" }, "bin": { - "handlebars": "bin/handlebars" + "node-which": "bin/node-which" }, "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" + "node": ">= 8" } }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "node_modules/eslint/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "function-bind": "^1.1.1" + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": ">= 0.4.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, - "node_modules/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, - "dependencies": { - "parse-passwd": "^1.0.0" + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "whatwg-encoding": "^1.0.5" + "estraverse": "^5.1.0" }, "engines": { - "node": ">=10" + "node": ">=0.10" } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "estraverse": "^5.2.0" }, "engines": { - "node": ">= 6" + "node": ">=4.0" } }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">= 6" + "node": ">=4.0" } }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "engines": { - "node": ">=10.17.0" + "node": ">=0.10.0" } }, - "node_modules/husky": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.5.tgz", - "integrity": "sha512-cKd09Jy9cDyNIvAdN2QQAP/oA21sle4FWXjIMDttailpLAYZuBE7WaPmhrkj+afS8Sj9isghAtFvWSQ0JiwOHg==", + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, - "hasInstallScript": true, "dependencies": { - "chalk": "^2.4.2", - "cosmiconfig": "^5.2.1", - "execa": "^1.0.0", - "get-stdin": "^7.0.0", - "is-ci": "^2.0.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^4.2.0", - "please-upgrade-node": "^3.2.0", - "read-pkg": "^5.1.1", - "run-node": "^1.0.0", - "slash": "^3.0.0" - }, - "bin": { - "husky-run": "run.js", - "husky-upgrade": "lib/upgrader/bin.js" + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" }, "engines": { - "node": ">=8.6.0" + "node": ">=6" } }, - "node_modules/husky/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.8.0" } }, - "node_modules/husky/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, + "license": "(MIT OR WTFPL)", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/husky/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "dev": true, "dependencies": { - "p-limit": "^2.2.0" + "homedir-polyfill": "^1.0.1" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/husky/node_modules/parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "node_modules/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", - "lines-and-columns": "^1.1.6" + "@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": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/husky/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/expect/node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/husky/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "node_modules/expect/node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", "dev": true, + "license": "MIT", "dependencies": { - "find-up": "^4.0.0" + "@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": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/husky/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "node_modules/expect/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "@types/yargs-parser": "*" + } + }, + "node_modules/expect/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/husky/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/expect/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/expect/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=7.0.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "node_modules/expect/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "license": "MIT" }, - "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "node_modules/expect/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 4" + "node": ">=8" } }, - "node_modules/import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "node_modules/expect/node_modules/jest-mock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", "dev": true, + "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-util": "30.2.0" }, "engines": { - "node": ">=6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "node_modules/expect/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, "engines": { - "node": ">=0.8.19" + "node": ">=4" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" }, - "node_modules/inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "dependencies": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=6.0.0" + "reusify": "^1.0.4" } }, - "node_modules/inquirer/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } }, - "node_modules/into-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", - "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, + "license": "MIT", "dependencies": { - "from2": "^2.3.0", - "p-is-promise": "^3.0.0" + "escape-string-regexp": "^1.0.5" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "ci-info": "^2.0.0" + "flat-cache": "^4.0.0" }, - "bin": { - "is-ci": "bin.js" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/is-core-module": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", - "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { - "has": "^1.0.3" + "to-regex-range": "^5.0.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "node_modules/find-node-modules": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.2.tgz", + "integrity": "sha512-x+3P4mbtRPlSiVE1Qco0Z4YLU8WFiFcuWTf3m75OV9Uzcfs2Bg+O9N+r/K0AnmINBW06KpfqKwYJbFlFq4qNug==", "dev": true, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "findup-sync": "^4.0.0", + "merge": "^2.1.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "engines": { - "node": ">=4" - } + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, "engines": { "node": ">=6" } }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, + "node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, "dependencies": { - "is-extglob": "^2.1.1" + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" + "node": ">= 8" } }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, "engines": { - "node": ">=8" + "node": ">=16" } }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true + "license": "ISC" }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "node_modules/is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, + "license": "ISC", "dependencies": { - "text-extensions": "^1.0.0" + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "node_modules/foreground-child/node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "node_modules/foreground-child/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "node_modules/foreground-child/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "shebang-regex": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/istanbul-lib-report": { + "node_modules/foreground-child/node_modules/shebang-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { - "node": ">=8" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/foreground-child/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "node_modules/form-data": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", + "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35" }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", "dev": true, + "license": "MIT", "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" } }, - "node_modules/jest": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.6.tgz", - "integrity": "sha512-EjV8aETrsD0wHl7CKMibKwQNQc3gIRBXlTikBmmHUeVMKaPFxdcUIBfoDqTSXDoGJIivAYGqCWVlzCSaVjPQsA==", + "node_modules/from2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/core": "^27.0.6", - "import-local": "^3.0.2", - "jest-cli": "^27.0.6" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "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/jest-changed-files": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.0.6.tgz", - "integrity": "sha512-BuL/ZDauaq5dumYh5y20sn4IISnf1P9A0TDswTxUi84ORGtVa86ApuBHqICL0vepqAnZiY6a7xeSPWv2/yy4eA==", + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dependencies": { - "@jest/types": "^27.0.6", - "execa": "^5.0.0", - "throat": "^6.0.1" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=12" } }, - "node_modules/jest-changed-files/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 8" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/jest-changed-files/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { - "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" + "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": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-changed-files/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.4" } }, - "node_modules/jest-changed-files/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", "dev": true, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-changed-files/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, "engines": { "node": ">=6" } }, - "node_modules/jest-changed-files/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/git-raw-commits": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", + "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", "dev": true, + "license": "MIT", "dependencies": { - "path-key": "^3.0.0" + "dargs": "^8.0.0", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.mjs" }, "engines": { - "node": ">=8" + "node": ">=16" } }, - "node_modules/jest-changed-files/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", "dev": true, + "license": "MIT" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", "dependencies": { - "mimic-fn": "^2.1.0" + "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": ">=6" + "node": "*" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-changed-files/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/jest-changed-files/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", "dev": true, + "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "ini": "4.1.1" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-changed-files/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/global-directory/node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", "dev": true, + "license": "ISC", "engines": { - "node": ">=8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/jest-changed-files/node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "node_modules/jest-changed-files/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" }, "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/jest-circus": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.0.6.tgz", - "integrity": "sha512-OJlsz6BBeX9qR+7O9lXefWoc2m9ZqcZ5Ohlzz0pTEAG4xMiZUJoacY8f4YDHxgk0oKYxj277AfOk9w6hZYvi1Q==", + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "dev": true, "dependencies": { - "@jest/environment": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.0.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.0.6", - "jest-matcher-utils": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-runtime": "^27.0.6", - "jest-snapshot": "^27.0.6", - "jest-util": "^27.0.6", - "pretty-format": "^27.0.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-circus/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-circus/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" }, "engines": { - "node": ">=7.0.0" + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" } }, - "node_modules/jest-circus/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-circus/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/jest-circus/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.0.6.tgz", - "integrity": "sha512-JZRR3I1Plr2YxPBhgqRspDE2S5zprbga3swYNrvY3HfQGu7p/GjyLOqwrYad97tX3U3mzT53TPHVmozacfP/3w==", - "dev": true, - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.0.6", - "@jest/types": "^27.0.6", - "babel-jest": "^27.0.6", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "is-ci": "^3.0.0", - "jest-circus": "^27.0.6", - "jest-environment-jsdom": "^27.0.6", - "jest-environment-node": "^27.0.6", - "jest-get-type": "^27.0.6", - "jest-jasmine2": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-runner": "^27.0.6", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "micromatch": "^4.0.4", - "pretty-format": "^27.0.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-config/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "has-symbols": "^1.0.3" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "function-bind": "^1.1.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">= 0.4" } }, - "node_modules/jest-config/node_modules/ci-info": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", - "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", - "dev": true - }, - "node_modules/jest-config/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "parse-passwd": "^1.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-config/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "node_modules/jest-config/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" }, - "node_modules/jest-config/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/jest-config/node_modules/is-ci": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", - "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "dependencies": { - "ci-info": "^3.1.1" - }, - "bin": { - "is-ci": "bin.js" + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" } }, - "node_modules/jest-config/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/husky": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.5.tgz", + "integrity": "sha512-cKd09Jy9cDyNIvAdN2QQAP/oA21sle4FWXjIMDttailpLAYZuBE7WaPmhrkj+afS8Sj9isghAtFvWSQ0JiwOHg==", "dev": true, + "hasInstallScript": true, "dependencies": { - "has-flag": "^4.0.0" + "chalk": "^2.4.2", + "cosmiconfig": "^5.2.1", + "execa": "^1.0.0", + "get-stdin": "^7.0.0", + "is-ci": "^2.0.0", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^4.2.0", + "please-upgrade-node": "^3.2.0", + "read-pkg": "^5.1.1", + "run-node": "^1.0.0", + "slash": "^3.0.0" + }, + "bin": { + "husky-run": "run.js", + "husky-upgrade": "lib/upgrader/bin.js" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, - "node_modules/jest-diff": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.6.tgz", - "integrity": "sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg==", + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.0.6", - "jest-get-type": "^27.0.6", - "pretty-format": "^27.0.6" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "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": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">= 4" } }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" }, "engines": { - "node": ">=7.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", "dev": true, - "engines": { - "node": ">=8" + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=0.8.19" } }, - "node_modules/jest-docblock": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", - "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", - "dev": true, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/jest-each": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.0.6.tgz", - "integrity": "sha512-m6yKcV3bkSWrUIjxkE9OC0mhBZZdhovIW5ergBYirqnkLXkyEn3oUUF/QZgyecA1cF1QFyTE8bRRl8Tfg1pfLA==", + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^27.0.6", - "chalk": "^4.0.0", - "jest-get-type": "^27.0.6", - "jest-util": "^27.0.6", - "pretty-format": "^27.0.6" + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=12.0.0" } }, - "node_modules/jest-each/node_modules/ansi-styles": { + "node_modules/inquirer/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7001,11 +7576,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-each/node_modules/chalk": { + "node_modules/inquirer/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7017,11 +7593,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-each/node_modules/color-convert": { + "node_modules/inquirer/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7029,299 +7606,329 @@ "node": ">=7.0.0" } }, - "node_modules/jest-each/node_modules/color-name": { + "node_modules/inquirer/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/jest-each/node_modules/has-flag": { + "node_modules/inquirer/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jest-each/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/inquirer/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" } }, - "node_modules/jest-environment-jsdom": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.0.6.tgz", - "integrity": "sha512-FvetXg7lnXL9+78H+xUAsra3IeZRTiegA3An01cWeXBspKXUhAwMM9ycIJ4yBaR0L7HkoMPaZsozCLHh4T8fuw==", + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/environment": "^27.0.6", - "@jest/fake-timers": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "jest-mock": "^27.0.6", - "jest-util": "^27.0.6", - "jsdom": "^16.6.0" + "has-flag": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8" } }, - "node_modules/jest-environment-node": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.0.6.tgz", - "integrity": "sha512-+Vi6yLrPg/qC81jfXx3IBlVnDTI6kmRr08iVa2hFCWmJt4zha0XW7ucQltCAPhSR0FEKEoJ3i+W4E6T0s9is0w==", + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/environment": "^27.0.6", - "@jest/fake-timers": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "jest-mock": "^27.0.6", - "jest-util": "^27.0.6" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", - "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/jest-haste-map": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.0.6.tgz", - "integrity": "sha512-4ldjPXX9h8doB2JlRzg9oAZ2p6/GpQUNAeiYXqcpmrKbP0Qev0wdZlxSMOmz8mPOEnt4h6qIzXFLDi8RScX/1w==", + "node_modules/into-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", + "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^27.0.6", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.0.6", - "jest-serializer": "^27.0.6", - "jest-util": "^27.0.6", - "jest-worker": "^27.0.6", - "micromatch": "^4.0.4", - "walker": "^1.0.7" + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" }, - "optionalDependencies": { - "fsevents": "^2.3.2" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-haste-map/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "node_modules/jest-jasmine2": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.0.6.tgz", - "integrity": "sha512-cjpH2sBy+t6dvCeKBsHpW41mjHzXgsavaFMp+VWRf0eR4EW8xASk1acqmljFtK2DgyIECMv2yCdY41r2l1+4iA==", + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", "dev": true, "dependencies": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.0.6", - "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.0.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.0.6", - "jest-matcher-utils": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-runtime": "^27.0.6", - "jest-snapshot": "^27.0.6", - "jest-util": "^27.0.6", - "pretty-format": "^27.0.6", - "throat": "^6.0.1" + "ci-info": "^2.0.0" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "bin": { + "is-ci": "bin.js" } }, - "node_modules/jest-jasmine2/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "hasown": "^2.0.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-jasmine2/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", "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": ">=0.10.0" } }, - "node_modules/jest-jasmine2/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-jasmine2/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "engines": { + "node": ">=4" + } }, - "node_modules/jest-jasmine2/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/jest-jasmine2/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "is-extglob": "^2.1.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jest-leak-detector": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.0.6.tgz", - "integrity": "sha512-2/d6n2wlH5zEcdctX4zdbgX8oM61tb67PQt4Xh8JFAIy6LRKUnX528HulkaG6nD5qDl5vRV1NXejCe1XRCH5gQ==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "dependencies": { - "jest-get-type": "^27.0.6", - "pretty-format": "^27.0.6" - }, + "license": "MIT", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.12.0" } }, - "node_modules/jest-matcher-utils": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.0.6.tgz", - "integrity": "sha512-OFgF2VCQx9vdPSYTHWJ9MzFCehs20TsyFi6bIHbk5V1u52zJOnvF0Y/65z3GLZHKRuTgVPY4Z6LVePNahaQ+tA==", + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^27.0.6", - "jest-get-type": "^27.0.6", - "pretty-format": "^27.0.6" + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", + "engines": { + "node": ">=10" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/is-text-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "text-extensions": "^2.0.0" }, "engines": { "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@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" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-matcher-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "color-name": "~1.1.4" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=10" } }, - "node_modules/jest-matcher-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { + "node_modules/istanbul-lib-report/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jest-matcher-utils/node_modules/supports-color": { + "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7329,87 +7936,111 @@ "node": ">=8" } }, - "node_modules/jest-message-util": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.0.6.tgz", - "integrity": "sha512-rBxIs2XK7rGy+zGxgi+UJKP6WqQ+KrBbD1YMj517HYN3v2BG66t3Xan3FWqYHKZwjdB700KiAJ+iES9a0M+ixw==", + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.0.6", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.4", - "pretty-format": "^27.0.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" } }, - "node_modules/jest-message-util/node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "node_modules/istanbul-lib-source-maps/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@babel/highlight": "^7.14.5" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/jest-message-util/node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=6.9.0" + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jest-message-util/node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/jest": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.0.5.tgz", + "integrity": "sha512-y2mfcJywuTUkvLm2Lp1/pFX8kTgMO5yyQGq/Sk/n2mN7XWYp4JsCZ/QXW34M8YScgk8bPZlREH04f6blPnoHnQ==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@jest/core": "30.0.5", + "@jest/types": "30.0.5", + "import-local": "^3.2.0", + "jest-cli": "30.0.5" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-changed-files": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.0.5.tgz", + "integrity": "sha512-bGl2Ntdx0eAwXuGpdLdVYVr5YQHnSZlQ0y9HVDu565lCUAe9sj6JOtBbMmBBikGIegne9piDDIOeiLVoqTkz4A==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "execa": "^5.1.1", + "jest-util": "30.0.5", + "p-limit": "^3.1.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-message-util/node_modules/chalk/node_modules/ansi-styles": { + "node_modules/jest-changed-files/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7420,23 +8051,45 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-message-util/node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/jest-changed-files/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "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": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jest-message-util/node_modules/color-convert": { + "node_modules/jest-changed-files/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7444,182 +8097,187 @@ "node": ">=7.0.0" } }, - "node_modules/jest-message-util/node_modules/color-name": { + "node_modules/jest-changed-files/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-message-util/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/jest-message-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-changed-files/node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/jest-mock": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.0.6.tgz", - "integrity": "sha512-lzBETUoK8cSxts2NYXSBWT+EJNzmUVtVVwS1sU9GwE1DLCfGsngg+ZVSIe0yd0ZSm+y791esiuo+WSwpXJQ5Bw==", + "node_modules/jest-changed-files/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^27.0.6", - "@types/node": "*" + "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.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "node_modules/jest-changed-files/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" + "node": ">=10" }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-regex-util": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", - "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", + "node_modules/jest-changed-files/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8" } }, - "node_modules/jest-resolve": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.0.6.tgz", - "integrity": "sha512-yKmIgw2LgTh7uAJtzv8UFHGF7Dm7XfvOe/LQ3Txv101fLM8cx2h1QVwtSJ51Q/SCxpIiKfVn6G2jYYMDNHZteA==", + "node_modules/jest-changed-files/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, - "dependencies": { - "@jest/types": "^27.0.6", - "chalk": "^4.0.0", - "escalade": "^3.1.1", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "resolve": "^1.20.0", - "slash": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-resolve-dependencies": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.0.6.tgz", - "integrity": "sha512-mg9x9DS3BPAREWKCAoyg3QucCr0n6S8HEEsqRCKSPjPcu9HzRILzhdzY3imsLoZWeosEbJZz6TKasveczzpJZA==", + "node_modules/jest-changed-files/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-snapshot": "^27.0.6" + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-resolve/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-changed-files/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "path-key": "^3.0.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-resolve/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-changed-files/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "yocto-queue": "^0.1.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-resolve/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/jest-changed-files/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, + "license": "MIT", "engines": { - "node": ">=7.0.0" + "node": ">=8" } }, - "node_modules/jest-resolve/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-resolve/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "node_modules/jest-resolve/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-changed-files/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/jest-resolve/node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "node_modules/jest-changed-files/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "shebang-regex": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=8" } }, - "node_modules/jest-resolve/node_modules/supports-color": { + "node_modules/jest-changed-files/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-changed-files/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7627,44 +8285,73 @@ "node": ">=8" } }, - "node_modules/jest-runner": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.0.6.tgz", - "integrity": "sha512-W3Bz5qAgaSChuivLn+nKOgjqNxM7O/9JOJoKDCqThPIg2sH/d4A/lzyiaFgnb9V1/w29Le11NpzTJSzga1vyYQ==", + "node_modules/jest-changed-files/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/jest-changed-files/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-circus": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.0.5.tgz", + "integrity": "sha512-h/sjXEs4GS+NFFfqBDYT7y5Msfxh04EwWLhQi0F8kuWpe+J/7tICSlswU8qvBqumR3kFgHbfu7vU6qruWWBPug==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/console": "^27.0.6", - "@jest/environment": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", + "@jest/environment": "30.0.5", + "@jest/expect": "30.0.5", + "@jest/test-result": "30.0.5", + "@jest/types": "30.0.5", "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.0.6", - "jest-environment-jsdom": "^27.0.6", - "jest-environment-node": "^27.0.6", - "jest-haste-map": "^27.0.6", - "jest-leak-detector": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-runtime": "^27.0.6", - "jest-util": "^27.0.6", - "jest-worker": "^27.0.6", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.0.5", + "jest-matcher-utils": "30.0.5", + "jest-message-util": "30.0.5", + "jest-runtime": "30.0.5", + "jest-snapshot": "30.0.5", + "jest-util": "30.0.5", + "p-limit": "^3.1.0", + "pretty-format": "30.0.5", + "pure-rand": "^7.0.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-runner/node_modules/ansi-styles": { + "node_modules/jest-circus/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7675,11 +8362,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-runner/node_modules/chalk": { + "node_modules/jest-circus/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7691,11 +8379,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-runner/node_modules/color-convert": { + "node_modules/jest-circus/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7703,132 +8408,295 @@ "node": ">=7.0.0" } }, - "node_modules/jest-runner/node_modules/color-name": { + "node_modules/jest-circus/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/jest-runner/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true + "node_modules/jest-circus/node_modules/dedent": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } }, - "node_modules/jest-runner/node_modules/has-flag": { + "node_modules/jest-circus/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.0.5.tgz", + "integrity": "sha512-1UIqE9PoEKaHcIKvq2vbibrCog4Y8G0zmOxgQUVEiTqwR5hJVMCoDsN1vFvI5JvwD37hjueZ1C4l2FyGnfpE0A==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.0.1", + "chalk": "^4.1.2", + "pretty-format": "30.0.5" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-runtime": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.0.6.tgz", - "integrity": "sha512-BhvHLRVfKibYyqqEFkybsznKwhrsu7AWx2F3y9G9L95VSIN3/ZZ9vBpm/XCS2bS+BWz3sSeNGLzI3TVQ0uL85Q==", - "dev": true, - "dependencies": { - "@jest/console": "^27.0.6", - "@jest/environment": "^27.0.6", - "@jest/fake-timers": "^27.0.6", - "@jest/globals": "^27.0.6", - "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-mock": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-snapshot": "^27.0.6", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^16.0.3" + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.0.5.tgz", + "integrity": "sha512-uQgGWt7GOrRLP1P7IwNWwK1WAQbq+m//ZY0yXygyfWp0rJlksMSLQAA4wYQC3b6wl3zfnchyTx+k3HZ5aPtCbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.0.1", + "chalk": "^4.1.2", + "jest-diff": "30.0.5", + "pretty-format": "30.0.5" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-runtime/node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "node_modules/jest-circus/node_modules/jest-message-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.5.tgz", + "integrity": "sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.0.5", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.0.5", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-runtime/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-circus/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-circus/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "yocto-queue": "^0.1.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-runtime/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/jest-circus/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/jest-runtime/node_modules/color-convert": { + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", + "dev": true, + "license": "MIT", + "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/jest-circus/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-cli": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.0.5.tgz", + "integrity": "sha512-Sa45PGMkBZzF94HMrlX4kUyPOwUpdZasaliKN3mifvDmkhLYqLLg8HQTzn6gq7vJGahFYMQjXgyJWfYImKZzOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.0.5", + "@jest/test-result": "30.0.5", + "@jest/types": "30.0.5", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.0.5", + "jest-util": "30.0.5", + "jest-validate": "30.0.5", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.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/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "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": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-cli/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7836,73 +8704,73 @@ "node": ">=7.0.0" } }, - "node_modules/jest-runtime/node_modules/color-name": { + "node_modules/jest-cli/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runtime/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/jest-runtime/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/jest-runtime/node_modules/has-flag": { + "node_modules/jest-cli/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jest-runtime/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/jest-cli/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-runtime/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "node_modules/jest-cli/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/jest-runtime/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "node_modules/jest-cli/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" } }, - "node_modules/jest-runtime/node_modules/supports-color": { + "node_modules/jest-cli/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7910,11 +8778,12 @@ "node": ">=8" } }, - "node_modules/jest-runtime/node_modules/wrap-ansi": { + "node_modules/jest-cli/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -7927,92 +8796,141 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/jest-runtime/node_modules/y18n": { + "node_modules/jest-cli/node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, - "node_modules/jest-runtime/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "node_modules/jest-cli/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/jest-serializer": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", - "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", + "node_modules/jest-cli/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - }, + "license": "ISC", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=12" } }, - "node_modules/jest-serializer/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true + "node_modules/jest-config": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.0.5.tgz", + "integrity": "sha512-aIVh+JNOOpzUgzUnPn5FLtyVnqc3TQHVMupYtyeURSb//iLColiMIR8TxCIDKyx9ZgjKnXGucuW68hCxgbrwmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.0.1", + "@jest/pattern": "30.0.1", + "@jest/test-sequencer": "30.0.5", + "@jest/types": "30.0.5", + "babel-jest": "30.0.5", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-circus": "30.0.5", + "jest-docblock": "30.0.1", + "jest-environment-node": "30.0.5", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.0.5", + "jest-runner": "30.0.5", + "jest-util": "30.0.5", + "jest-validate": "30.0.5", + "micromatch": "^4.0.8", + "parse-json": "^5.2.0", + "pretty-format": "30.0.5", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } + } }, - "node_modules/jest-snapshot": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.0.6.tgz", - "integrity": "sha512-NTHaz8He+ATUagUgE7C/UtFcRoHqR2Gc+KDfhQIyx+VFgwbeEMjeP+ILpUTLosZn/ZtbNdCF5LkVnN/l+V751A==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/parser": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.0.6", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.0.6", - "jest-get-type": "^27.0.6", - "jest-haste-map": "^27.0.6", - "jest-matcher-utils": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-util": "^27.0.6", - "natural-compare": "^1.4.0", - "pretty-format": "^27.0.6", - "semver": "^7.3.2" + "node_modules/jest-config/node_modules/@jest/transform": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.5.tgz", + "integrity": "sha512-Vk8amLQCmuZyy6GbBht1Jfo9RSdBtg7Lks+B0PecnjI8J+PCLQPGh7uI8Q/2wwpW2gLdiAfiHNsmekKlywULqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.0.5", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.0", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.0.5", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-snapshot/node_modules/ansi-styles": { + "node_modules/jest-config/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -8023,11 +8941,76 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-snapshot/node_modules/chalk": { + "node_modules/jest-config/node_modules/babel-jest": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.0.5.tgz", + "integrity": "sha512-mRijnKimhGDMsizTvBTWotwNpzrkHr+VvZUQBof2AufXKB8NXrL1W69TG20EvOz7aevx6FTJIaBuBkYxS8zolg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "30.0.5", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.0", + "babel-preset-jest": "30.0.1", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0" + } + }, + "node_modules/jest-config/node_modules/babel-plugin-jest-hoist": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.0.1.tgz", + "integrity": "sha512-zTPME3pI50NsFW8ZBaVIOeAxzEY7XHlmWeXXu9srI+9kNfzCUTy8MFan46xOGZY8NZThMqq+e3qZUKsvXbasnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.3", + "@types/babel__core": "^7.20.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-config/node_modules/babel-preset-jest": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.0.1.tgz", + "integrity": "sha512-+YHejD5iTWI46cZmcc/YtX4gaKBtdqCHCVfuVinizVpbmyjO3zYmeuyFdfA8duRqQZfgCAMlsfmkVbJ+e2MAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "30.0.1", + "babel-preset-current-node-syntax": "^1.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0" + } + }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/jest-config/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -8039,11 +9022,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-snapshot/node_modules/color-convert": { + "node_modules/jest-config/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -8051,158 +9051,202 @@ "node": ">=7.0.0" } }, - "node_modules/jest-snapshot/node_modules/color-name": { + "node_modules/jest-config/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/jest-snapshot/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true + "node_modules/jest-config/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "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/jest-snapshot/node_modules/has-flag": { + "node_modules/jest-config/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/jest-config/node_modules/jest-haste-map": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.5.tgz", + "integrity": "sha512-dkmlWNlsTSR0nH3nRfW5BKbqHefLZv0/6LCccG0xFCTWcJu8TuEwG+5Cm75iBfjVoockmO6J35o5gxtFSn5xeg==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "@jest/types": "30.0.5", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "jest-worker": "30.0.5", + "micromatch": "^4.0.8", + "walker": "^1.0.8" }, "engines": { - "node": ">=10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" } }, - "node_modules/jest-snapshot/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/jest-config/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-util": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", - "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "node_modules/jest-config/node_modules/jest-worker": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.0.5.tgz", + "integrity": "sha512-ojRXsWzEP16NdUuBw/4H/zkZdHOa7MMYCk4E430l+8fELeLg/mqmMlRhjL7UNZvQrDmnovWZV4DxX03fZF48fQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^27.0.6", "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^3.0.0", - "picomatch": "^2.2.3" + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.0.5", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-config/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-config/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-util/node_modules/ci-info": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", - "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", - "dev": true - }, - "node_modules/jest-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/jest-config/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@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": ">=7.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-util/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "node_modules/jest-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-config/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/jest-util/node_modules/is-ci": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", - "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "node_modules/jest-config/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", "dev": true, + "license": "MIT", "dependencies": { - "ci-info": "^3.1.1" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, - "bin": { - "is-ci": "bin.js" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-util/node_modules/supports-color": { + "node_modules/jest-config/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -8210,28 +9254,38 @@ "node": ">=8" } }, - "node_modules/jest-validate": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.0.6.tgz", - "integrity": "sha512-yhZZOaMH3Zg6DC83n60pLmdU1DQE46DW+KLozPiPbSbPhlXXaiUTDlhHQhHFpaqIFRrInko1FHXjTRpjWRuWfA==", + "node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^27.0.6", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.0.6", - "leven": "^3.1.0", - "pretty-format": "^27.0.6" + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-validate/node_modules/ansi-styles": { + "node_modules/jest-diff/node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -8242,23 +9296,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-validate/node_modules/chalk": { + "node_modules/jest-diff/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -8270,11 +9313,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-validate/node_modules/color-convert": { + "node_modules/jest-diff/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -8282,26 +9326,29 @@ "node": ">=7.0.0" } }, - "node_modules/jest-validate/node_modules/color-name": { + "node_modules/jest-diff/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/jest-validate/node_modules/has-flag": { + "node_modules/jest-diff/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jest-validate/node_modules/supports-color": { + "node_modules/jest-diff/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -8309,44 +9356,42 @@ "node": ">=8" } }, - "node_modules/jest-watcher": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.0.6.tgz", - "integrity": "sha512-/jIoKBhAP00/iMGnTwUBLgvxkn7vsOweDrOTSPzc7X9uOyUtJIDthQBTI1EXz90bdkrxorUZVhJwiB69gcHtYQ==", + "node_modules/jest-docblock": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.0.1.tgz", + "integrity": "sha512-/vF78qn3DYphAaIc3jy4gA7XSAz167n9Bm/wn/1XhTLW7tTBIzXtCJpb/vcmc73NIIeeohCbdL94JasyXUZsGA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/test-result": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.0.6", - "string-length": "^4.0.1" + "detect-newline": "^3.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-watcher/node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "node_modules/jest-each": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.0.5.tgz", + "integrity": "sha512-dKjRsx1uZ96TVyejD3/aAWcNKy6ajMaN531CwWIsrazIqIoXI9TnnpPlkrEYku/8rkS3dh2rbH+kMOyiEIv0xQ==", "dev": true, + "license": "MIT", "dependencies": { - "type-fest": "^0.21.3" + "@jest/get-type": "30.0.1", + "@jest/types": "30.0.5", + "chalk": "^4.1.2", + "jest-util": "30.0.5", + "pretty-format": "30.0.5" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-watcher/node_modules/ansi-styles": { + "node_modules/jest-each/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -8357,11 +9402,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-watcher/node_modules/chalk": { + "node_modules/jest-each/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -8373,11 +9419,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-watcher/node_modules/color-convert": { + "node_modules/jest-each/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -8385,97 +9448,120 @@ "node": ">=7.0.0" } }, - "node_modules/jest-watcher/node_modules/color-name": { + "node_modules/jest-each/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/jest-watcher/node_modules/has-flag": { + "node_modules/jest-each/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jest-watcher/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/jest-each/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-watcher/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "node_modules/jest-each/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/jest-worker": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.6.tgz", - "integrity": "sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA==", + "node_modules/jest-each/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": ">= 10.13.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-each/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=8" } }, - "node_modules/jest/node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "node_modules/jest-environment-node": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.0.5.tgz", + "integrity": "sha512-ppYizXdLMSvciGsRsMEnv/5EFpvOdXBaXRBzFUDPWrsfmog4kYrOGWXarLllz6AXan6ZAA/kYokgDWuos1IKDA==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.0.5", + "@jest/fake-timers": "30.0.5", + "@jest/types": "30.0.5", + "@types/node": "*", + "jest-mock": "30.0.5", + "jest-util": "30.0.5", + "jest-validate": "30.0.5" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest/node_modules/ansi-styles": { + "node_modules/jest-environment-node/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -8486,11 +9572,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest/node_modules/chalk": { + "node_modules/jest-environment-node/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -8502,22 +9589,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/jest-environment-node/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/jest/node_modules/color-convert": { + "node_modules/jest-environment-node/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -8525,1310 +9618,1501 @@ "node": ">=7.0.0" } }, - "node_modules/jest/node_modules/color-name": { + "node_modules/jest-environment-node/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/jest/node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/jest/node_modules/has-flag": { + "node_modules/jest-environment-node/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jest/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/jest-environment-node/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest/node_modules/jest-cli": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.0.6.tgz", - "integrity": "sha512-qUUVlGb9fdKir3RDE+B10ULI+LQrz+MCflEH2UJyoUjoHHCbxDrMxSzjQAPUMsic4SncI62ofYCcAvW6+6rhhg==", + "node_modules/jest-environment-node/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "dependencies": { - "@jest/core": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/types": "^27.0.6", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "jest-config": "^27.0.6", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "prompts": "^2.0.1", - "yargs": "^16.0.3" - }, - "bin": { - "jest": "bin/jest.js" - }, + "license": "MIT", "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "node": ">=12" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/jest/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "node_modules/jest-environment-node/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/jest/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "node_modules/jest-leak-detector": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.0.5.tgz", + "integrity": "sha512-3Uxr5uP8jmHMcsOtYMRB/zf1gXN3yUIc+iPorhNETG54gErFIiUhLvyY/OggYpSMOEYqsmRxmuU4ZOoX5jpRFg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.0" + "@jest/get-type": "30.0.1", + "pretty-format": "30.0.5" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/jest-leak-detector/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "node_modules/jest-matcher-utils/node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jsdom/node_modules/acorn": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", - "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.4.0" + "node": ">=7.0.0" } }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, + "license": "MIT" + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/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://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "minimist": "^1.2.5" + "has-flag": "^4.0.0" }, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, + "license": "MIT", + "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": ">=6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "node_modules/jest-message-util/node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "license": "MIT", + "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/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "node_modules/jest-message-util/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, - "engines": [ - "node >= 0.2.0" - ] + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" + "color-convert": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=6" + "node": ">=7.0.0" } }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "has-flag": "^4.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "node_modules/jest-mock": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.0.5.tgz", + "integrity": "sha512-Od7TyasAAQX/6S+QCbN6vZoWOMwlTtzzGuxJku1GhGanAjz9y+QsQkpScDmETvdc9aSXyJ/Op4rhpMYBWW91wQ==", "dev": true, + "license": "MIT", "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "@jest/types": "30.0.5", + "@types/node": "*", + "jest-util": "30.0.5" }, "engines": { - "node": ">=4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/load-json-file/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "node_modules/jest-mock/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/load-json-file/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "node_modules/jest-mock/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.ismatch": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", - "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", - "dev": true - }, - "node_modules/lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", - "dev": true - }, - "node_modules/longest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", - "integrity": "sha1-eB4YMpaqlPbU2RbcM10NF676I/g=", + "node_modules/jest-mock/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/jest-mock/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=10" + "node": ">=7.0.0" } }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/jest-mock/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, + "license": "MIT" + }, + "node_modules/jest-mock/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-error": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", - "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "node_modules/jest-mock/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", "dependencies": { - "tmpl": "1.0.x" + "@jest/types": "30.0.5", + "@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/map-obj": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", - "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", + "node_modules/jest-mock/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "node_modules/jest-mock/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } } }, - "node_modules/meow/node_modules/hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.0.5.tgz", + "integrity": "sha512-d+DjBQ1tIhdz91B79mywH5yYu76bZuE96sSbxj8MkjWVx5WNdt1deEFRONVL4UkKLSrAbMkdhb24XN691yDRHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.0.5", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.0.5", + "jest-validate": "30.0.5", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" }, "engines": { - "node": ">=10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/meow/node_modules/normalize-package-data": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", - "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", + "node_modules/jest-resolve-dependencies": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.0.5.tgz", + "integrity": "sha512-/xMvBR4MpwkrHW4ikZIWRttBBRZgWK4d6xt3xW1iRDSKt4tXzYkMkyPfBnSCgv96cpkrctfXs6gexeqMYqdEpw==", "dev": true, + "license": "MIT", "dependencies": { - "hosted-git-info": "^4.0.1", - "resolve": "^1.20.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.0.5" }, "engines": { - "node": ">=10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/meow/node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/meow/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "node_modules/jest-resolve/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/merge": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", - "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", - "dev": true + "node_modules/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "node_modules/jest-resolve/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=8" } }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "node_modules/jest-resolve/node_modules/jest-haste-map": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.5.tgz", + "integrity": "sha512-dkmlWNlsTSR0nH3nRfW5BKbqHefLZv0/6LCccG0xFCTWcJu8TuEwG+5Cm75iBfjVoockmO6J35o5gxtFSn5xeg==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "@jest/types": "30.0.5", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "jest-worker": "30.0.5", + "micromatch": "^4.0.8", + "walker": "^1.0.8" }, "engines": { - "node": ">=8.6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" } }, - "node_modules/mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "node_modules/jest-resolve/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, "engines": { - "node": ">= 0.6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "node_modules/jest-resolve/node_modules/jest-worker": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.0.5.tgz", + "integrity": "sha512-ojRXsWzEP16NdUuBw/4H/zkZdHOa7MMYCk4E430l+8fELeLg/mqmMlRhjL7UNZvQrDmnovWZV4DxX03fZF48fQ==", "dev": true, + "license": "MIT", "dependencies": { - "mime-db": "1.40.0" + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.0.5", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" }, "engines": { - "node": ">= 0.6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "node_modules/jest-resolve/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "node_modules/jest-resolve/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "has-flag": "^4.0.0" }, "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "node_modules/jest-runner": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.0.5.tgz", + "integrity": "sha512-JcCOucZmgp+YuGgLAXHNy7ualBx4wYSgJVWrYMRBnb79j9PD0Jxh0EHvR5Cx/r0Ce+ZBC4hCdz2AzFFLl9hCiw==", "dev": true, + "license": "MIT", "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" + "@jest/console": "30.0.5", + "@jest/environment": "30.0.5", + "@jest/test-result": "30.0.5", + "@jest/transform": "30.0.5", + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.0.1", + "jest-environment-node": "30.0.5", + "jest-haste-map": "30.0.5", + "jest-leak-detector": "30.0.5", + "jest-message-util": "30.0.5", + "jest-resolve": "30.0.5", + "jest-runtime": "30.0.5", + "jest-util": "30.0.5", + "jest-watcher": "30.0.5", + "jest-worker": "30.0.5", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/transform": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.5.tgz", + "integrity": "sha512-Vk8amLQCmuZyy6GbBht1Jfo9RSdBtg7Lks+B0PecnjI8J+PCLQPGh7uI8Q/2wwpW2gLdiAfiHNsmekKlywULqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.0.5", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.0", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.0.5", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" }, "engines": { - "node": ">= 6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "node_modules/jest-runner/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, + "license": "MIT", "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "node_modules/mkdirp/node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/modify-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", - "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "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/multistream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", - "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", + "node_modules/jest-runner/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", "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" + "url": "https://github.com/sponsors/sibiraj-s" } ], - "dependencies": { - "once": "^1.4.0", - "readable-stream": "^3.6.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/nock": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", - "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "node_modules/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.1.0", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.13", - "propagate": "^2.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 10.13" + "node": ">=7.0.0" } }, - "node_modules/nock/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/node-abi": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.0.tgz", - "integrity": "sha512-g6bZh3YCKQRdwuO/tSZZYJAw622SjsRfJ2X0Iy4sSOHZ34/sPPdVBn8fev2tj7njzLwuqPw9uMtGsGkO5kIQvg==", + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "dependencies": { - "semver": "^5.4.1" - } + "license": "MIT" }, - "node_modules/node-abi/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "license": "MIT", "engines": { - "node": "4.x || >=6.0.0" + "node": ">=8" } }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node_modules/node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "node_modules/jest-runner/node_modules/jest-haste-map": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.5.tgz", + "integrity": "sha512-dkmlWNlsTSR0nH3nRfW5BKbqHefLZv0/6LCccG0xFCTWcJu8TuEwG+5Cm75iBfjVoockmO6J35o5gxtFSn5xeg==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.0.5", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "jest-worker": "30.0.5", + "micromatch": "^4.0.8", + "walker": "^1.0.8" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" } }, - "node_modules/node-releases": { - "version": "1.1.74", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.74.tgz", - "integrity": "sha512-caJBVempXZPepZoZAPCWRTNxYQ+xtG/KAi4ozTA5A+nJ7IU+kLQCbqaUjb5Rwy14M9upBWiQ4NutcmW04LJSRw==", - "dev": true - }, - "node_modules/noop-logger": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/jest-runner/node_modules/jest-message-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.5.tgz", + "integrity": "sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA==", "dev": true, + "license": "MIT", "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.0.5", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.0.5", + "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/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "node_modules/jest-runner/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, - "bin": { - "semver": "bin/semver" + "license": "MIT", + "dependencies": { + "@jest/types": "30.0.5", + "@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/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/jest-runner/node_modules/jest-worker": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.0.5.tgz", + "integrity": "sha512-ojRXsWzEP16NdUuBw/4H/zkZdHOa7MMYCk4E430l+8fELeLg/mqmMlRhjL7UNZvQrDmnovWZV4DxX03fZF48fQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.0.5", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "node_modules/jest-runner/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { - "path-key": "^2.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "node_modules/jest-runner/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/null-check": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", - "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", + "node_modules/jest-runner/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "node_modules/jest-runner/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "node_modules/jest-runner/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "mimic-fn": "^1.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/opencollective-postinstall": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", - "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", + "node_modules/jest-runner/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, - "bin": { - "opencollective-postinstall": "index.js" + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "node_modules/jest-runtime": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.0.5.tgz", + "integrity": "sha512-7oySNDkqpe4xpX5PPiJTe5vEa+Ak/NnNz2bGYZrA1ftG3RL3EFlHaUkA1Cjx+R8IhK0Vg43RML5mJedGTPNz3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.0.5", + "@jest/fake-timers": "30.0.5", + "@jest/globals": "30.0.5", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.0.5", + "@jest/transform": "30.0.5", + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.0.5", + "jest-message-util": "30.0.5", + "jest-mock": "30.0.5", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.0.5", + "jest-snapshot": "30.0.5", + "jest-util": "30.0.5", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "node_modules/jest-runtime/node_modules/@jest/transform": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.5.tgz", + "integrity": "sha512-Vk8amLQCmuZyy6GbBht1Jfo9RSdBtg7Lks+B0PecnjI8J+PCLQPGh7uI8Q/2wwpW2gLdiAfiHNsmekKlywULqg==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.0.5", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.0", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.0.5", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", + "node_modules/jest-runtime/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "engines": { - "node": ">=4" + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/p-is-promise": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", - "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" + "balanced-match": "^1.0.0" } }, - "node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", "dependencies": { - "p-limit": "^2.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/jest-runtime/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { - "callsites": "^3.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=6" + "node": ">=7.0.0" } }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, + "license": "ISC", "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "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" }, - "engines": { - "node": ">=4" + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "node_modules/jest-runtime/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "node_modules/jest-runtime/node_modules/jest-haste-map": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.5.tgz", + "integrity": "sha512-dkmlWNlsTSR0nH3nRfW5BKbqHefLZv0/6LCccG0xFCTWcJu8TuEwG+5Cm75iBfjVoockmO6J35o5gxtFSn5xeg==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.0.5", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "jest-worker": "30.0.5", + "micromatch": "^4.0.8", + "walker": "^1.0.8" + }, "engines": { - "node": ">=4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/jest-runtime/node_modules/jest-message-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.5.tgz", + "integrity": "sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.0.5", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.0.5", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "node_modules/jest-runtime/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, - "engines": { - "node": ">=8.6" + "license": "MIT", + "dependencies": { + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "node_modules/jest-runtime/node_modules/jest-worker": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.0.5.tgz", + "integrity": "sha512-ojRXsWzEP16NdUuBw/4H/zkZdHOa7MMYCk4E430l+8fELeLg/mqmMlRhjL7UNZvQrDmnovWZV4DxX03fZF48fQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.0.5", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "node_modules/jest-runtime/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { - "node-modules-regexp": "^1.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/pkg": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.3.1.tgz", - "integrity": "sha512-jT/sptM1ZG++FNk+jnJYNoWLDQXYd7hqpnBhd5j18SNW1jJzNYo55RahuCiD0KN0PX9mb53GWCqKM0ia/mJytA==", + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { - "@babel/parser": "7.13.13", - "@babel/types": "7.13.12", - "chalk": "^4.1.0", - "escodegen": "^2.0.0", - "fs-extra": "^9.1.0", - "globby": "^11.0.3", - "into-stream": "^6.0.0", - "minimist": "^1.2.5", - "multistream": "^4.1.0", - "pkg-fetch": "3.2.2", - "prebuild-install": "6.0.1", - "progress": "^2.0.3", - "resolve": "^1.20.0", - "stream-meter": "^1.0.4", - "tslib": "2.1.0" + "brace-expansion": "^2.0.1" }, - "bin": { - "pkg": "lib-es5/bin.js" - }, - "peerDependencies": { - "node-notifier": ">=9.0.1" + "engines": { + "node": ">=16 || 14 >=14.17" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "node_modules/jest-runtime/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/jest-runtime/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", "dev": true, + "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/jest-runtime/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, + "node_modules/jest-snapshot": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.0.5.tgz", + "integrity": "sha512-T00dWU/Ek3LqTp4+DcW6PraVxjk28WY5Ua/s+3zUKSERZSNyxTqhDXCWKG5p2HAJ+crVQ3WJ2P9YVHpj1tkW+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.0.5", + "@jest/get-type": "30.0.1", + "@jest/snapshot-utils": "30.0.5", + "@jest/transform": "30.0.5", + "@jest/types": "30.0.5", + "babel-preset-current-node-syntax": "^1.1.0", + "chalk": "^4.1.2", + "expect": "30.0.5", + "graceful-fs": "^4.2.11", + "jest-diff": "30.0.5", + "jest-matcher-utils": "30.0.5", + "jest-message-util": "30.0.5", + "jest-util": "30.0.5", + "pretty-format": "30.0.5", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@jest/expect-utils": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.0.5.tgz", + "integrity": "sha512-F3lmTT7CXWYywoVUGTCmom0vXq3HTTkaZyTAzIy+bXSBizB7o5qzlC9VCtq0arOa8GqmNsbg/cE9C6HLn7Szew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@jest/transform": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.5.tgz", + "integrity": "sha512-Vk8amLQCmuZyy6GbBht1Jfo9RSdBtg7Lks+B0PecnjI8J+PCLQPGh7uI8Q/2wwpW2gLdiAfiHNsmekKlywULqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.0.5", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.0", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.0.5", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/pkg-fetch": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.2.2.tgz", - "integrity": "sha512-bLhFNT4cNnONxzbHo1H2mCCKuQkCR4dgQtv0gUZnWtp8TDP0v0UAXKHG7DXhAoTC5IYP3slLsFJtIda9ksny8g==", + "node_modules/jest-snapshot/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "^4.1.0", - "fs-extra": "^9.1.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.1", - "progress": "^2.0.3", - "semver": "^7.3.5", - "yargs": "^16.2.0" - }, - "bin": { - "pkg-fetch": "lib-es5/bin.js" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/pkg-fetch/node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "node_modules/jest-snapshot/node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" } }, - "node_modules/pkg-fetch/node_modules/ansi-styles": { + "node_modules/jest-snapshot/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -9839,11 +11123,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/pkg-fetch/node_modules/chalk": { + "node_modules/jest-snapshot/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -9855,22 +11140,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/pkg-fetch/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/jest-snapshot/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/pkg-fetch/node_modules/color-convert": { + "node_modules/jest-snapshot/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -9878,197 +11169,293 @@ "node": ">=7.0.0" } }, - "node_modules/pkg-fetch/node_modules/color-name": { + "node_modules/jest-snapshot/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/pkg-fetch/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/pkg-fetch/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/jest-snapshot/node_modules/expect": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.0.5.tgz", + "integrity": "sha512-P0te2pt+hHI5qLJkIR+iMvS+lYUZml8rKKsohVHAGY+uClp9XVbdyYNJOIjSRpHVp8s8YqxJCiHUkSYZGr8rtQ==", "dev": true, + "license": "MIT", "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@jest/expect-utils": "30.0.5", + "@jest/get-type": "30.0.1", + "jest-matcher-utils": "30.0.5", + "jest-message-util": "30.0.5", + "jest-mock": "30.0.5", + "jest-util": "30.0.5" }, "engines": { - "node": ">=10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/pkg-fetch/node_modules/has-flag": { + "node_modules/jest-snapshot/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/pkg-fetch/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.0.5.tgz", + "integrity": "sha512-1UIqE9PoEKaHcIKvq2vbibrCog4Y8G0zmOxgQUVEiTqwR5hJVMCoDsN1vFvI5JvwD37hjueZ1C4l2FyGnfpE0A==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.0.1", + "chalk": "^4.1.2", + "pretty-format": "30.0.5" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/pkg-fetch/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "node_modules/jest-snapshot/node_modules/jest-haste-map": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.5.tgz", + "integrity": "sha512-dkmlWNlsTSR0nH3nRfW5BKbqHefLZv0/6LCccG0xFCTWcJu8TuEwG+5Cm75iBfjVoockmO6J35o5gxtFSn5xeg==", "dev": true, + "license": "MIT", "dependencies": { - "universalify": "^2.0.0" + "@jest/types": "30.0.5", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.0.5", + "jest-worker": "30.0.5", + "micromatch": "^4.0.8", + "walker": "^1.0.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "optionalDependencies": { - "graceful-fs": "^4.1.6" + "fsevents": "^2.3.3" } }, - "node_modules/pkg-fetch/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.0.5.tgz", + "integrity": "sha512-uQgGWt7GOrRLP1P7IwNWwK1WAQbq+m//ZY0yXygyfWp0rJlksMSLQAA4wYQC3b6wl3zfnchyTx+k3HZ5aPtCbQ==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" + "@jest/get-type": "30.0.1", + "chalk": "^4.1.2", + "jest-diff": "30.0.5", + "pretty-format": "30.0.5" }, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-message-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.5.tgz", + "integrity": "sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.0.5", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.0.5", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" }, "engines": { - "node": ">=10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/pkg-fetch/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "node_modules/jest-snapshot/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "@jest/types": "30.0.5", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/pkg-fetch/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "node_modules/jest-snapshot/node_modules/jest-worker": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.0.5.tgz", + "integrity": "sha512-ojRXsWzEP16NdUuBw/4H/zkZdHOa7MMYCk4E430l+8fELeLg/mqmMlRhjL7UNZvQrDmnovWZV4DxX03fZF48fQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.0" + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.0.5", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/pkg-fetch/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/jest-snapshot/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/pkg-fetch/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "node_modules/jest-snapshot/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 10.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pkg-fetch/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "@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/jest-snapshot/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/pkg-fetch/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/pkg-fetch/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "node_modules/jest-snapshot/node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", "dev": true, + "license": "MIT", "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "@pkgr/core": "^0.2.9" }, "engines": { - "node": ">=10" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" } }, - "node_modules/pkg/node_modules/@babel/parser": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz", - "integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==", + "node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, - "bin": { - "parser": "bin/babel-parser.js" + "license": "MIT", + "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": ">=6.0.0" + "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://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, + "license": "MIT", + "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/pkg/node_modules/@babel/types": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.12.tgz", - "integrity": "sha512-K4nY2xFN4QMvQwkQ+zmBDp6ANMbVNw6BbxWmYA4qNjhR9W+Lj/8ky5MEY2Me5r+B2c6/v6F53oMndG+f9s3IiA==", + "node_modules/jest-util/node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" + "@types/yargs-parser": "*" } }, - "node_modules/pkg/node_modules/ansi-styles": { + "node_modules/jest-util/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -10079,11 +11466,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/pkg/node_modules/chalk": { + "node_modules/jest-util/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -10095,11 +11483,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/pkg/node_modules/color-convert": { + "node_modules/jest-util/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -10107,72 +11512,42 @@ "node": ">=7.0.0" } }, - "node_modules/pkg/node_modules/color-name": { + "node_modules/jest-util/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/pkg/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/pkg/node_modules/has-flag": { + "node_modules/jest-util/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/pkg/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/pkg/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/pkg/node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "node_modules/jest-util/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pkg/node_modules/supports-color": { + "node_modules/jest-util/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -10180,11556 +11555,3260 @@ "node": ">=8" } }, - "node_modules/pkg/node_modules/tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", - "dev": true - }, - "node_modules/pkg/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "node_modules/jest-validate": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.0.5.tgz", + "integrity": "sha512-ouTm6VFHaS2boyl+k4u+Qip4TSH7Uld5tyD8psQ8abGgt2uYYB8VwVfAHWHjHc0NWmGGbwO5h0sCPOGHHevefw==", "dev": true, + "license": "MIT", "dependencies": { - "semver-compare": "^1.0.0" + "@jest/get-type": "30.0.1", + "@jest/types": "30.0.5", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.0.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/prebuild-install": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.0.1.tgz", - "integrity": "sha512-7GOJrLuow8yeiyv75rmvZyeMGzl8mdEX5gY69d6a6bHWmiPevwqFw+tQavhK0EYMaSg3/KD24cWqeQv1EWsqDQ==", + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.7.0", - "noop-logger": "^0.1.1", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^3.0.3", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0", - "which-pm-runs": "^1.0.0" - }, - "bin": { - "prebuild-install": "bin.js" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" + "node": ">=10" }, - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "fast-diff": "^1.1.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/pretty-format": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", - "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.0.6", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prompts": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", - "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/propagate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", - "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "engines": { - "node": ">=6" - } - }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "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/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { + "node_modules/jest-validate/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8" + "node": ">=7.0.0" } }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/read-pkg-up/node_modules/path-exists": { + "node_modules/jest-validate/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "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" - }, + "license": "MIT", "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", + "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", "dev": true, + "license": "MIT", "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": ">=8" - } - }, - "node_modules/regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true, - "engines": { - "node": ">=6.5.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "node_modules/resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", - "dev": true, - "dependencies": { - "path-parse": "^1.0.6" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "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://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", - "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", - "dev": true, - "dependencies": { - "global-dirs": "^0.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/right-pad": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/right-pad/-/right-pad-1.0.1.tgz", - "integrity": "sha1-jKCMLLtbVedNr6lr9/0aJ9VoyNA=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/rimraf": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", - "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, - "dependencies": { - "is-promise": "^2.1.0" - }, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", - "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", - "dev": true, - "bin": { - "run-node": "run-node" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "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": "6.5.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", - "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "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/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/sanitize-filename": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", - "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", - "dependencies": { - "truncate-utf8-bytes": "^1.0.0" - } - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/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/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "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/simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", - "dev": true, - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "dependencies": { - "readable-stream": "^3.0.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "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://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/standard-version": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/standard-version/-/standard-version-9.3.1.tgz", - "integrity": "sha512-5qMxXw/FxLouC5nANyx/5RY1kiorJx9BppUso8gN07MG64q2uLRmrPb4KfXp3Ql4s/gxjZwZ89e0FwxeLubGww==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "conventional-changelog": "3.1.24", - "conventional-changelog-config-spec": "2.1.0", - "conventional-changelog-conventionalcommits": "4.5.0", - "conventional-recommended-bump": "6.1.0", - "detect-indent": "^6.0.0", - "detect-newline": "^3.1.0", - "dotgitignore": "^2.1.0", - "figures": "^3.1.0", - "find-up": "^5.0.0", - "fs-access": "^1.0.1", - "git-semver-tags": "^4.0.0", - "semver": "^7.1.1", - "stringify-package": "^1.0.1", - "yargs": "^16.0.0" - }, - "bin": { - "standard-version": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/standard-version/node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/standard-version/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/standard-version/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/standard-version/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/standard-version/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/standard-version/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/standard-version/node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/standard-version/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "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/standard-version/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/standard-version/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/standard-version/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/standard-version/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/standard-version/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/standard-version/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/standard-version/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/standard-version/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/standard-version/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/standard-version/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/standard-version/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stream-meter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", - "integrity": "sha1-Uq+Vql6nYKJJFxZwTb/5D3Ov3R0=", - "dev": true, - "dependencies": { - "readable-stream": "^2.1.4" - } - }, - "node_modules/stream-meter/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": 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/stream-meter/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/stream-meter/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-length/node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/stringify-package": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz", - "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==", - "dev": true - }, - "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/table/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/table/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terminal-link/node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terminal-link/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "dependencies": { - "readable-stream": "3" - } - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/trim-off-newlines": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", - "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/truncate-utf8-bytes": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", - "integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=", - "dependencies": { - "utf8-byte-length": "^1.0.1" - } - }, - "node_modules/ts-jest": { - "version": "27.0.4", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.4.tgz", - "integrity": "sha512-c4E1ECy9Xz2WGfTMyHbSaArlIva7Wi2p43QOMmCqjSSjHP06KXv+aT+eSY+yZMuqsMi3k7pyGsGj2q5oSl5WfQ==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "buffer-from": "1.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^27.0.0", - "json5": "2.x", - "lodash": "4.x", - "make-error": "1.x", - "mkdirp": "1.x", - "semver": "7.x", - "yargs-parser": "20.x" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@types/jest": "^26.0.0", - "babel-jest": ">=27.0.0 <28", - "jest": "^27.0.0", - "typescript": ">=3.8 <5.0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@types/jest": { - "optional": true - }, - "babel-jest": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/ts-jest/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-node": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.4.1.tgz", - "integrity": "sha512-5LpRN+mTiCs7lI5EtbXmF/HfMeCjzt7DH9CZwtkr6SywStrNQC723wG+aOWFiLNn7zT3kD/RnFqi3ZUfr4l5Qw==", - "dev": true, - "dependencies": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.6", - "yn": "^3.0.0" - }, - "bin": { - "ts-node": "dist/bin.js" - }, - "engines": { - "node": ">=4.2.0" - }, - "peerDependencies": { - "typescript": ">=2.0" - } - }, - "node_modules/tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/uglify-js": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.1.tgz", - "integrity": "sha512-JhS3hmcVaXlp/xSo3PKY5R0JqKs5M3IV+exdLHW99qKvKivPO4Z8qbej6mte17SOPqAOVMjt/XGgWacnFSzM3g==", - "dev": true, - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-template": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", - "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" - }, - "node_modules/utf8-byte-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", - "integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "node_modules/v8-compile-cache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", - "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.0.0.tgz", - "integrity": "sha512-LkmXi8UUNxnCC+JlH7/fsfsKr5AU110l+SYGJimWNkWhxbN5EyeOtm1MJ0hhvqMMOhGwBj1Fp70Yv9i+hX0QAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "dependencies": { - "makeerror": "1.0.x" - } - }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, - "engines": { - "node": ">=10.4" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/whatwg-url/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "node_modules/which-pm-runs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", - "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", - "dev": true - }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", - "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", - "dev": true, - "engines": { - "node": ">=8.3.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": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/yargs": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", - "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", - "dependencies": { - "cliui": "^5.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.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": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^15.0.1" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", - "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", - "dev": true - }, - "@babel/core": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz", - "integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.0", - "@babel/helper-module-transforms": "^7.15.0", - "@babel/helpers": "^7.14.8", - "@babel/parser": "^7.15.0", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.14.5" - } - }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", - "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", - "dev": true, - "requires": { - "@babel/types": "^7.15.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", - "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", - "semver": "^6.3.0" - } - }, - "@babel/helper-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", - "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", - "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", - "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", - "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", - "dev": true, - "requires": { - "@babel/types": "^7.15.0" - } - }, - "@babel/helper-module-imports": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", - "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-module-transforms": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", - "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.0", - "@babel/helper-simple-access": "^7.14.8", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", - "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", - "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.15.0", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" - } - }, - "@babel/helper-simple-access": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", - "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", - "dev": true, - "requires": { - "@babel/types": "^7.14.8" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", - "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", - "dev": true - }, - "@babel/helpers": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.3.tgz", - "integrity": "sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g==", - "dev": true, - "requires": { - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" - } - }, - "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.3.tgz", - "integrity": "sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", - "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/template": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", - "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.14.5" - } - }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - } - } - }, - "@babel/traverse": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", - "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.15.0", - "@babel/types": "^7.15.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.14.5" - } - }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - } - } - }, - "@babel/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", - "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.9", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@commitlint/cli": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-13.1.0.tgz", - "integrity": "sha512-xN/uNYWtGTva5OMSd+xA6e6/c2jk8av7MUbdd6w2cw89u6z3fAWoyiH87X0ewdSMNYmW/6B3L/2dIVGHRDID5w==", - "dev": true, - "requires": { - "@commitlint/format": "^13.1.0", - "@commitlint/lint": "^13.1.0", - "@commitlint/load": "^13.1.0", - "@commitlint/read": "^13.1.0", - "@commitlint/types": "^13.1.0", - "lodash": "^4.17.19", - "resolve-from": "5.0.0", - "resolve-global": "1.0.0", - "yargs": "^17.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.0.tgz", - "integrity": "sha512-SQr7qqmQ2sNijjJGHL4u7t8vyDZdZ3Ahkmo4sc1w5xI9TBX0QDdG/g4SFnxtWOsGLjwHQue57eFALfwFCnixgg==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - } - } - }, - "@commitlint/config-conventional": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-8.2.0.tgz", - "integrity": "sha512-HuwlHQ3DyVhpK9GHgTMhJXD8Zp8PGIQVpQGYh/iTrEU6TVxdRC61BxIDZvfWatCaiG617Z/U8maRAFrqFM4TqA==", - "dev": true - }, - "@commitlint/ensure": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-13.1.0.tgz", - "integrity": "sha512-NRGyjOdZQnlYwm9it//BZJ2Vm+4x7G9rEnHpLCvNKYY0c6RA8Qf7hamLAB8dWO12RLuFt06JaOpHZoTt/gHutA==", - "dev": true, - "requires": { - "@commitlint/types": "^13.1.0", - "lodash": "^4.17.19" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - } - } - }, - "@commitlint/execute-rule": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-13.0.0.tgz", - "integrity": "sha512-lBz2bJhNAgkkU/rFMAw3XBNujbxhxlaFHY3lfKB/MxpAa+pIfmWB3ig9i1VKe0wCvujk02O0WiMleNaRn2KJqw==", - "dev": true - }, - "@commitlint/format": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-13.1.0.tgz", - "integrity": "sha512-n46rYvzf+6Sm99TJjTLjJBkjm6JVcklt31lDO5Q+pCIV0NnJ4qIUcwa6wIL9a9Vqb1XzlMgtp27E0zyYArkvSg==", - "dev": true, - "requires": { - "@commitlint/types": "^13.1.0", - "chalk": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@commitlint/is-ignored": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-13.1.0.tgz", - "integrity": "sha512-P6zenLE5Tn3FTNjRzmL9+/KooTXEI0khA2TmUbuei9KiycemeO4q7Xk7w7aXwFPNAbN0O9oI7z3z7cFpzKJWmQ==", - "dev": true, - "requires": { - "@commitlint/types": "^13.1.0", - "semver": "7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@commitlint/lint": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-13.1.0.tgz", - "integrity": "sha512-qH9AYSQDDTaSWSdtOvB3G1RdPpcYSgddAdFYqpFewlKQ1GJj/L+sM7vwqCG7/ip6AiM04Sry1sgmFzaEoFREUA==", - "dev": true, - "requires": { - "@commitlint/is-ignored": "^13.1.0", - "@commitlint/parse": "^13.1.0", - "@commitlint/rules": "^13.1.0", - "@commitlint/types": "^13.1.0" - } - }, - "@commitlint/load": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-13.1.0.tgz", - "integrity": "sha512-zlZbjJCWnWmBOSwTXis8H7I6pYk6JbDwOCuARA6B9Y/qt2PD+NCo0E/7EuaaFoxjHl+o56QR5QttuMBrf+BJzg==", - "dev": true, - "requires": { - "@commitlint/execute-rule": "^13.0.0", - "@commitlint/resolve-extends": "^13.0.0", - "@commitlint/types": "^13.1.0", - "chalk": "^4.0.0", - "cosmiconfig": "^7.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "dev": true, - "requires": { - "@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" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - } - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@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" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@commitlint/message": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-13.0.0.tgz", - "integrity": "sha512-W/pxhesVEk8747BEWJ+VGQ9ILHmCV27/pEwJ0hGny1wqVquUR8SxvScRCbUjHCB1YtWX4dEnOPXOS9CLH/CX7A==", - "dev": true - }, - "@commitlint/parse": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-13.1.0.tgz", - "integrity": "sha512-xFybZcqBiKVjt6vTStvQkySWEUYPI0AcO4QQELyy29o8EzYZqWkhUfrb7K61fWiHsplWL1iL6F3qCLoxSgTcrg==", - "dev": true, - "requires": { - "@commitlint/types": "^13.1.0", - "conventional-changelog-angular": "^5.0.11", - "conventional-commits-parser": "^3.0.0" - } - }, - "@commitlint/read": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-13.1.0.tgz", - "integrity": "sha512-NrVe23GMKyL6i1yDJD8IpqCBzhzoS3wtLfDj8QBzc01Ov1cYBmDojzvBklypGb+MLJM1NbzmRM4PR5pNX0U/NQ==", - "dev": true, - "requires": { - "@commitlint/top-level": "^13.0.0", - "@commitlint/types": "^13.1.0", - "fs-extra": "^10.0.0", - "git-raw-commits": "^2.0.0" - }, - "dependencies": { - "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } - } - }, - "@commitlint/resolve-extends": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-13.0.0.tgz", - "integrity": "sha512-1SyaE+UOsYTkQlTPUOoj4NwxQhGFtYildVS/d0TJuK8a9uAJLw7bhCLH2PEeH5cC2D1do4Eqhx/3bLDrSLH3hg==", - "dev": true, - "requires": { - "import-fresh": "^3.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0", - "resolve-global": "^1.0.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@commitlint/rules": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-13.1.0.tgz", - "integrity": "sha512-b6F+vBqEXsHVghrhomG0Y6YJimHZqkzZ0n5QEpk03dpBXH2OnsezpTw5e+GvbyYCc7PutGbYVQkytuv+7xCxYA==", - "dev": true, - "requires": { - "@commitlint/ensure": "^13.1.0", - "@commitlint/message": "^13.0.0", - "@commitlint/to-lines": "^13.0.0", - "@commitlint/types": "^13.1.0", - "execa": "^5.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "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" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "@commitlint/to-lines": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-13.0.0.tgz", - "integrity": "sha512-mzxWwCio1M4/kG9/69TTYqrraQ66LmtJCYTzAZdZ2eJX3I5w52pSjyP/DJzAUVmmJCYf2Kw3s+RtNVShtnZ+Rw==", - "dev": true - }, - "@commitlint/top-level": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-13.0.0.tgz", - "integrity": "sha512-baBy3MZBF28sR93yFezd4a5TdHsbXaakeladfHK9dOcGdXo9oQe3GS5hP3BmlN680D6AiQSN7QPgEJgrNUWUCg==", - "dev": true, - "requires": { - "find-up": "^5.0.0" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } - } - }, - "@commitlint/types": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-13.1.0.tgz", - "integrity": "sha512-zcVjuT+OfKt8h91vhBxt05RMcTGEx6DM7Q9QZeuMbXFk6xgbsSEDMMapbJPA1bCZ81fa/1OQBijSYPrKvtt06g==", - "dev": true, - "requires": { - "chalk": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@hutson/parse-repository-url": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", - "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.0.6.tgz", - "integrity": "sha512-fMlIBocSHPZ3JxgWiDNW/KPj6s+YRd0hicb33IrmelCcjXo/pXPwvuiKFmZz+XuqI/1u7nbUK10zSsWL/1aegg==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.0.6", - "jest-util": "^27.0.6", - "slash": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/core": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.0.6.tgz", - "integrity": "sha512-SsYBm3yhqOn5ZLJCtccaBcvD/ccTLCeuDv8U41WJH/V1MW5eKUkeMHT9U+Pw/v1m1AIWlnIW/eM2XzQr0rEmow==", - "dev": true, - "requires": { - "@jest/console": "^27.0.6", - "@jest/reporters": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.0.6", - "jest-config": "^27.0.6", - "jest-haste-map": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-resolve-dependencies": "^27.0.6", - "jest-runner": "^27.0.6", - "jest-runtime": "^27.0.6", - "jest-snapshot": "^27.0.6", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "jest-watcher": "^27.0.6", - "micromatch": "^4.0.4", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, - "@jest/environment": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.0.6.tgz", - "integrity": "sha512-4XywtdhwZwCpPJ/qfAkqExRsERW+UaoSRStSHCCiQTUpoYdLukj+YJbQSFrZjhlUDRZeNiU9SFH0u7iNimdiIg==", - "dev": true, - "requires": { - "@jest/fake-timers": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "jest-mock": "^27.0.6" - } - }, - "@jest/fake-timers": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.0.6.tgz", - "integrity": "sha512-sqd+xTWtZ94l3yWDKnRTdvTeZ+A/V7SSKrxsrOKSqdyddb9CeNRF8fbhAU0D7ZJBpTTW2nbp6MftmKJDZfW2LQ==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "@sinonjs/fake-timers": "^7.0.2", - "@types/node": "*", - "jest-message-util": "^27.0.6", - "jest-mock": "^27.0.6", - "jest-util": "^27.0.6" - } - }, - "@jest/globals": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.0.6.tgz", - "integrity": "sha512-DdTGCP606rh9bjkdQ7VvChV18iS7q0IMJVP1piwTWyWskol4iqcVwthZmoJEf7obE1nc34OpIyoVGPeqLC+ryw==", - "dev": true, - "requires": { - "@jest/environment": "^27.0.6", - "@jest/types": "^27.0.6", - "expect": "^27.0.6" - } - }, - "@jest/reporters": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.0.6.tgz", - "integrity": "sha512-TIkBt09Cb2gptji3yJXb3EE+eVltW6BjO7frO7NEfjI9vSIYoISi5R3aI3KpEDXlB1xwB+97NXIqz84qYeYsfA==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-util": "^27.0.6", - "jest-worker": "^27.0.6", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/source-map": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", - "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - } - } - }, - "@jest/test-result": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.0.6.tgz", - "integrity": "sha512-ja/pBOMTufjX4JLEauLxE3LQBPaI2YjGFtXexRAjt1I/MbfNlMx0sytSX3tn5hSLzQsR3Qy2rd0hc1BWojtj9w==", - "dev": true, - "requires": { - "@jest/console": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.0.6.tgz", - "integrity": "sha512-bISzNIApazYOlTHDum9PwW22NOyDa6VI31n6JucpjTVM0jD6JDgqEZ9+yn575nDdPF0+4csYDxNNW13NvFQGZA==", - "dev": true, - "requires": { - "@jest/test-result": "^27.0.6", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.0.6", - "jest-runtime": "^27.0.6" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - } - } - }, - "@jest/transform": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.0.6.tgz", - "integrity": "sha512-rj5Dw+mtIcntAUnMlW/Vju5mr73u8yg+irnHwzgtgoeI6cCPOvUwQ0D1uQtc/APmWgvRweEb1g05pkUpxH3iCA==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.0.6", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-util": "^27.0.6", - "micromatch": "^4.0.4", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/types": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", - "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", - "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@types/babel__core": { - "version": "7.1.15", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz", - "integrity": "sha512-bxlMKPDbY8x5h6HBwVzEOk2C8fb6SLfYQ5Jw3uBYuYF1lfWk/kbLd81la82vrIkBb0l+JdmrZaDikPrNxpS/Ew==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", - "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/chalk": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/chalk/-/chalk-2.2.0.tgz", - "integrity": "sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw==", - "dev": true, - "requires": { - "chalk": "*" - } - }, - "@types/eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", - "dev": true - }, - "@types/events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", - "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", - "dev": true - }, - "@types/glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", - "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", - "dev": true, - "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "24.0.18", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.18.tgz", - "integrity": "sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ==", - "dev": true, - "requires": { - "@types/jest-diff": "*" - } - }, - "@types/jest-diff": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz", - "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", - "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", - "dev": true - }, - "@types/lodash": { - "version": "4.14.144", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz", - "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true - }, - "@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "dev": true - }, - "@types/node": { - "version": "12.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz", - "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==", - "dev": true - }, - "@types/node-fetch": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz", - "integrity": "sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==", - "dev": true, - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - }, - "dependencies": { - "form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, - "@types/prettier": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.2.tgz", - "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", - "dev": true - }, - "@types/promise-retry": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@types/promise-retry/-/promise-retry-1.1.3.tgz", - "integrity": "sha512-LxIlEpEX6frE3co3vCO2EUJfHIta1IOmhDlcAsR4GMMv9hev1iTI9VwberVGkePJAuLZs5rMucrV8CziCfuJMw==", - "dev": true, - "requires": { - "@types/retry": "*" - } - }, - "@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true - }, - "@types/rimraf": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.0.tgz", - "integrity": "sha512-7WhJ0MdpFgYQPXlF4Dx+DhgvlPCfz/x5mHaeDQAKhcenvQP1KCpLQ18JklAqeGMYSAT2PxLpzd0g2/HE7fj7hQ==", - "dev": true, - "requires": { - "@types/glob": "*", - "@types/node": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/table": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@types/table/-/table-4.0.7.tgz", - "integrity": "sha512-HKtXvBxU8U8evZCSlUi9HbfT/SFW7nSGCoiBEheB06jAhXeW6JbGh8biEAqIFG5rZo9f8xeJVdIn455sddmIcw==", - "dev": true - }, - "@types/url-template": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/@types/url-template/-/url-template-2.0.28.tgz", - "integrity": "sha512-1i/YtOhvlWDbMDTWhCfvhyUwBS9vNFs78sJOyahoruJCcDbwaSH73AlnuCp7luKPm6qqdCg4VKq/IHUncl6gZA==", - "dev": true - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", - "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "2.34.0", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.0.0", - "tsutils": "^3.17.1" - }, - "dependencies": { - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - } - } - }, - "@typescript-eslint/experimental-utils": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", - "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.34.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - }, - "dependencies": { - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - } - } - }, - "@typescript-eslint/parser": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", - "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", - "dev": true, - "requires": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.34.0", - "@typescript-eslint/typescript-estree": "2.34.0", - "eslint-visitor-keys": "^1.1.0" - } - }, - "@typescript-eslint/typescript-estree": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", - "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "eslint-visitor-keys": "^1.1.0", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "dependencies": { - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "acorn-jsx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", - "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "add-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", - "integrity": "sha1-anmQQ3ynNtXhKI25K9MmbV9csqo=", - "dev": true - }, - "adm-zip": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.13.tgz", - "integrity": "sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", - "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "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" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "arg": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz", - "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, - "axios": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.2.tgz", - "integrity": "sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg==", - "requires": { - "follow-redirects": "^1.14.0" - } - }, - "axios-mock-adapter": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.19.0.tgz", - "integrity": "sha512-D+0U4LNPr7WroiBDvWilzTMYPYTuZlbo6BI8YHZtj7wYQS8NkARlP9KBt8IWWHTQJ0q/8oZ0ClPBtKCCkx8cQg==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3", - "is-buffer": "^2.0.3" - }, - "dependencies": { - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true - } - } - }, - "babel-jest": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.0.6.tgz", - "integrity": "sha512-iTJyYLNc4wRofASmofpOc5NK9QunwMk+TLFgGXsTFS8uEqmd8wdI7sga0FPe2oVH3b5Agt/EAK1QjPEuKL8VfA==", - "dev": true, - "requires": { - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.0.6", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.6.tgz", - "integrity": "sha512-CewFeM9Vv2gM7Yr9n5eyyLVPRSiBnk6lKZRjgwYnGKSl9M14TMn2vkN02wTF04OGuSDLEzlWiMzvjXuW9mB6Gw==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@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-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.0.6.tgz", - "integrity": "sha512-WObA0/Biw2LrVVwZkF/2GqbOdzhKD6Fkdwhoy9ASIrOWr/zodcSpQh72JOkEn6NWyjmnPDjNSqaGN4KnpKzhXw==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^27.0.6", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "browserslist": { - "version": "4.16.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.7.tgz", - "integrity": "sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001248", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.793", - "escalade": "^3.1.1", - "node-releases": "^1.1.73" - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "cachedir": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.2.0.tgz", - "integrity": "sha512-VvxA0xhNqIIfg0V9AmJkDg91DaJwryutH5rVEZAhcNi4iJFj9f+QxmAjgK1LT9I8OgToX27fypX6/MeCXVbBjQ==", - "dev": true - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - }, - "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - } - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - } - }, - "caniuse-lite": { - "version": "1.0.30001251", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz", - "integrity": "sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "colorette": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.3.0.tgz", - "integrity": "sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commitizen": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.4.tgz", - "integrity": "sha512-LlZChbDzg3Ir3O2S7jSo/cgWp5/QwylQVr59K4xayVq8S4/RdKzSyJkghAiZZHfhh5t4pxunUoyeg0ml1q/7aw==", - "dev": true, - "requires": { - "cachedir": "2.2.0", - "cz-conventional-changelog": "3.2.0", - "dedent": "0.7.0", - "detect-indent": "6.0.0", - "find-node-modules": "^2.1.2", - "find-root": "1.1.0", - "fs-extra": "8.1.0", - "glob": "7.1.4", - "inquirer": "6.5.2", - "is-utf8": "^0.2.1", - "lodash": "^4.17.20", - "minimist": "1.2.5", - "strip-bom": "4.0.0", - "strip-json-comments": "3.0.1" - }, - "dependencies": { - "conventional-commit-types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", - "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", - "dev": true - }, - "cz-conventional-changelog": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.2.0.tgz", - "integrity": "sha512-yAYxeGpVi27hqIilG1nh4A9Bnx4J3Ov+eXy4koL3drrR+IO9GaWPsKjik20ht608Asqi8TQPf0mczhEeyAtMzg==", - "dev": true, - "requires": { - "@commitlint/load": ">6.1.1", - "chalk": "^2.4.1", - "commitizen": "^4.0.3", - "conventional-commit-types": "^3.0.0", - "lodash.map": "^4.5.1", - "longest": "^2.0.1", - "word-wrap": "^1.0.3" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - } - } - }, - "compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, - "requires": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true - }, - "conventional-changelog": { - "version": "3.1.24", - "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.24.tgz", - "integrity": "sha512-ed6k8PO00UVvhExYohroVPXcOJ/K1N0/drJHx/faTH37OIZthlecuLIRX/T6uOp682CAoVoFpu+sSEaeuH6Asg==", - "dev": true, - "requires": { - "conventional-changelog-angular": "^5.0.12", - "conventional-changelog-atom": "^2.0.8", - "conventional-changelog-codemirror": "^2.0.8", - "conventional-changelog-conventionalcommits": "^4.5.0", - "conventional-changelog-core": "^4.2.1", - "conventional-changelog-ember": "^2.0.9", - "conventional-changelog-eslint": "^3.0.9", - "conventional-changelog-express": "^2.0.6", - "conventional-changelog-jquery": "^3.0.11", - "conventional-changelog-jshint": "^2.0.9", - "conventional-changelog-preset-loader": "^2.3.4" - } - }, - "conventional-changelog-angular": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz", - "integrity": "sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw==", - "dev": true, - "requires": { - "compare-func": "^2.0.0", - "q": "^1.5.1" - } - }, - "conventional-changelog-atom": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz", - "integrity": "sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==", - "dev": true, - "requires": { - "q": "^1.5.1" - } - }, - "conventional-changelog-codemirror": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz", - "integrity": "sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==", - "dev": true, - "requires": { - "q": "^1.5.1" - } - }, - "conventional-changelog-config-spec": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz", - "integrity": "sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ==", - "dev": true - }, - "conventional-changelog-conventionalcommits": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.5.0.tgz", - "integrity": "sha512-buge9xDvjjOxJlyxUnar/+6i/aVEVGA7EEh4OafBCXPlLUQPGbRUBhBUveWRxzvR8TEjhKEP4BdepnpG2FSZXw==", - "dev": true, - "requires": { - "compare-func": "^2.0.0", - "lodash": "^4.17.15", - "q": "^1.5.1" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - } - } - }, - "conventional-changelog-core": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.3.tgz", - "integrity": "sha512-MwnZjIoMRL3jtPH5GywVNqetGILC7g6RQFvdb8LRU/fA/338JbeWAku3PZ8yQ+mtVRViiISqJlb0sOz0htBZig==", - "dev": true, - "requires": { - "add-stream": "^1.0.0", - "conventional-changelog-writer": "^5.0.0", - "conventional-commits-parser": "^3.2.0", - "dateformat": "^3.0.0", - "get-pkg-repo": "^4.0.0", - "git-raw-commits": "^2.0.8", - "git-remote-origin-url": "^2.0.0", - "git-semver-tags": "^4.1.1", - "lodash": "^4.17.15", - "normalize-package-data": "^3.0.0", - "q": "^1.5.1", - "read-pkg": "^3.0.0", - "read-pkg-up": "^3.0.0", - "through2": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "normalize-package-data": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", - "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "resolve": "^1.20.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "dependencies": { - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - } - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "conventional-changelog-ember": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz", - "integrity": "sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==", - "dev": true, - "requires": { - "q": "^1.5.1" - } - }, - "conventional-changelog-eslint": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz", - "integrity": "sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==", - "dev": true, - "requires": { - "q": "^1.5.1" - } - }, - "conventional-changelog-express": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz", - "integrity": "sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==", - "dev": true, - "requires": { - "q": "^1.5.1" - } - }, - "conventional-changelog-jquery": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz", - "integrity": "sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==", - "dev": true, - "requires": { - "q": "^1.5.1" - } - }, - "conventional-changelog-jshint": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz", - "integrity": "sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==", - "dev": true, - "requires": { - "compare-func": "^2.0.0", - "q": "^1.5.1" - } - }, - "conventional-changelog-preset-loader": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", - "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", - "dev": true - }, - "conventional-changelog-writer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz", - "integrity": "sha512-HnDh9QHLNWfL6E1uHz6krZEQOgm8hN7z/m7tT16xwd802fwgMN0Wqd7AQYVkhpsjDUx/99oo+nGgvKF657XP5g==", - "dev": true, - "requires": { - "conventional-commits-filter": "^2.0.7", - "dateformat": "^3.0.0", - "handlebars": "^4.7.6", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "semver": "^6.0.0", - "split": "^1.0.0", - "through2": "^4.0.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - } - } - }, - "conventional-commit-types": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-2.1.1.tgz", - "integrity": "sha512-0Ts+fEdmjqYDOQ1yZ+LNgdSPO335XZw9qC10M7CxtLP3nIMGmeMhmkM8Taffa4+MXN13bRPlp0CtH+QfOzKTzw==", - "dev": true - }, - "conventional-commits-filter": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", - "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", - "dev": true, - "requires": { - "lodash.ismatch": "^4.4.0", - "modify-values": "^1.0.0" - } - }, - "conventional-commits-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz", - "integrity": "sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA==", - "dev": true, - "requires": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.0.4", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0", - "trim-off-newlines": "^1.0.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - } - } - }, - "conventional-recommended-bump": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz", - "integrity": "sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw==", - "dev": true, - "requires": { - "concat-stream": "^2.0.0", - "conventional-changelog-preset-loader": "^2.3.4", - "conventional-commits-filter": "^2.0.7", - "conventional-commits-parser": "^3.2.0", - "git-raw-commits": "^2.0.8", - "git-semver-tags": "^4.1.1", - "meow": "^8.0.0", - "q": "^1.5.1" - } - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "dependencies": { - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - } - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "cz-conventional-changelog": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.0.2.tgz", - "integrity": "sha512-MPxERbtQyVp0nnpCBiwzKGKmMBSswmCV3Jpef3Axqd5f3c/SOc6VFiSUlclOyZXBn3Xtf4snzt4O15hBTRb2gA==", - "dev": true, - "requires": { - "@commitlint/load": ">6.1.1", - "chalk": "^2.4.1", - "commitizen": "^4.0.3", - "conventional-commit-types": "^2.0.0", - "lodash.map": "^4.5.1", - "longest": "^2.0.1", - "right-pad": "^1.0.1", - "word-wrap": "^1.0.3" - } - }, - "dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", - "dev": true - }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } - }, - "dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "dev": true - }, - "dc-management-sdk-js": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/dc-management-sdk-js/-/dc-management-sdk-js-1.14.0.tgz", - "integrity": "sha512-M92cWMkwq8EscX7zklxEVNFNYadoyZEbz5+rta8JpPOxMGW9ysDitJETZ+4BNJxlnzi377PNQdlHyHfgnjKprg==", - "requires": { - "axios": "^0.21.1", - "url-template": "^2.0.8" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", - "dev": true, - "requires": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "dependencies": { - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - } - } - }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "dev": true, - "requires": { - "mimic-response": "^2.0.0" - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true - }, - "detect-indent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", - "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", - "dev": true - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", - "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", - "dev": true - }, - "diff-sequences": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", - "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "dotgitignore": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/dotgitignore/-/dotgitignore-2.1.0.tgz", - "integrity": "sha512-sCm11ak2oY6DglEPpCB8TixLjWAxd3kJTs6UIcSasNYxXdFPV+YKlye92c8H4kKFqV5qYMIh7d+cYecEg0dIkA==", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "minimatch": "^3.0.4" - } - }, - "electron-to-chromium": { - "version": "1.3.804", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.804.tgz", - "integrity": "sha512-GB+D82NbTO6/7mC0aRNv0LPOhof/fz4UX6D/CnxTVpiPgWna+HDQJMHgsf/Ne/itKn3akJul9L0kwvML2kp3Yg==", - "dev": true - }, - "emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "end-of-stream": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.2.tgz", - "integrity": "sha512-gUSUszrsxlDnUbUwEI9Oygyrk4ZEWtVaHQc+uZHphVeNxl+qeqMV/jDWoTkjN1RmGlZ5QWAP7o458p/JMlikQg==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "eslint": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.4.0.tgz", - "integrity": "sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.2", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.4.1", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - } - } - }, - "eslint-config-prettier": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.3.0.tgz", - "integrity": "sha512-EWaGjlDAZRzVFveh2Jsglcere2KK5CJBhkNSa1xs3KfMUGdRiT7lG089eqPdvlzWHpAqaekubOsOMu8W8Yk71A==", - "dev": true, - "requires": { - "get-stdin": "^6.0.0" - }, - "dependencies": { - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - } - } - }, - "eslint-plugin-prettier": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.1.tgz", - "integrity": "sha512-A+TZuHZ0KU0cnn56/9mfR7/KjUJ9QNVXUhwvRFSR7PGPe0zQR6PTkmyqg1AtUUEOzTqeRsUwyKFh0oVZKVCrtA==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", - "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.0.0" - } - }, - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true - }, - "espree": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz", - "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==", - "dev": true, - "requires": { - "acorn": "^7.0.0", - "acorn-jsx": "^5.0.2", - "eslint-visitor-keys": "^1.1.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", - "dev": true, - "requires": { - "estraverse": "^4.0.0" - } - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "expect": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.0.6.tgz", - "integrity": "sha512-psNLt8j2kwg42jGBDSfAlU49CEZxejN1f1PlANWDZqIhBOVU/c2Pm888FcjWJzFewhIsNWfZJeLjUjtKGiPuSw==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-styles": "^5.0.0", - "jest-get-type": "^27.0.6", - "jest-matcher-utils": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-regex-util": "^27.0.6" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - } - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.1.tgz", - "integrity": "sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-node-modules": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.2.tgz", - "integrity": "sha512-x+3P4mbtRPlSiVE1Qco0Z4YLU8WFiFcuWTf3m75OV9Uzcfs2Bg+O9N+r/K0AnmINBW06KpfqKwYJbFlFq4qNug==", - "dev": true, - "requires": { - "findup-sync": "^4.0.0", - "merge": "^2.1.0" - } - }, - "find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "findup-sync": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", - "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^4.0.2", - "resolve-dir": "^1.0.1" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "dependencies": { - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "flatted": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", - "dev": true - }, - "follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" - }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "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" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "fs-access": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", - "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", - "dev": true, - "requires": { - "null-check": "^1.0.0" - } - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-pkg-repo": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.1.2.tgz", - "integrity": "sha512-/FjamZL9cBYllEbReZkxF2IMh80d8TJoC4e3bmLNif8ibHw95aj0N/tzqK0kZz9eU/3w3dL6lF4fnnX/sDdW3A==", - "dev": true, - "requires": { - "@hutson/parse-repository-url": "^3.0.0", - "hosted-git-info": "^4.0.0", - "meow": "^7.0.0", - "through2": "^2.0.0" - }, - "dependencies": { - "hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "meow": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-7.1.1.tgz", - "integrity": "sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==", - "dev": true, - "requires": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^2.5.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.13.1", - "yargs-parser": "^18.1.3" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "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" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "get-stdin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", - "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "git-raw-commits": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz", - "integrity": "sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ==", - "dev": true, - "requires": { - "dargs": "^7.0.0", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - } - } - }, - "git-remote-origin-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", - "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=", - "dev": true, - "requires": { - "gitconfiglocal": "^1.0.0", - "pify": "^2.3.0" - } - }, - "git-semver-tags": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", - "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", - "dev": true, - "requires": { - "meow": "^8.0.0", - "semver": "^6.0.0" - } - }, - "gitconfiglocal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", - "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=", - "dev": true, - "requires": { - "ini": "^1.3.2" - } - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "dev": true - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", - "dev": true, - "requires": { - "ini": "^1.3.4" - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - } - } - }, - "graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", - "dev": true - }, - "handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "dev": true, - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - } - }, - "hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.5" - } - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "husky": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.5.tgz", - "integrity": "sha512-cKd09Jy9cDyNIvAdN2QQAP/oA21sle4FWXjIMDttailpLAYZuBE7WaPmhrkj+afS8Sj9isghAtFvWSQ0JiwOHg==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "cosmiconfig": "^5.2.1", - "execa": "^1.0.0", - "get-stdin": "^7.0.0", - "is-ci": "^2.0.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^4.2.0", - "please-upgrade-node": "^3.2.0", - "read-pkg": "^5.1.1", - "run-node": "^1.0.0", - "slash": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", - "lines-and-columns": "^1.1.6" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - } - } - }, - "into-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", - "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", - "dev": true, - "requires": { - "from2": "^2.3.0", - "p-is-promise": "^3.0.0" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", - "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", - "dev": true, - "requires": { - "text-extensions": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jest": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.6.tgz", - "integrity": "sha512-EjV8aETrsD0wHl7CKMibKwQNQc3gIRBXlTikBmmHUeVMKaPFxdcUIBfoDqTSXDoGJIivAYGqCWVlzCSaVjPQsA==", - "dev": true, - "requires": { - "@jest/core": "^27.0.6", - "import-local": "^3.0.2", - "jest-cli": "^27.0.6" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "jest-cli": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.0.6.tgz", - "integrity": "sha512-qUUVlGb9fdKir3RDE+B10ULI+LQrz+MCflEH2UJyoUjoHHCbxDrMxSzjQAPUMsic4SncI62ofYCcAvW6+6rhhg==", - "dev": true, - "requires": { - "@jest/core": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/types": "^27.0.6", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "jest-config": "^27.0.6", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "prompts": "^2.0.1", - "yargs": "^16.0.3" - } - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - } - } - }, - "jest-changed-files": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.0.6.tgz", - "integrity": "sha512-BuL/ZDauaq5dumYh5y20sn4IISnf1P9A0TDswTxUi84ORGtVa86ApuBHqICL0vepqAnZiY6a7xeSPWv2/yy4eA==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "execa": "^5.0.0", - "throat": "^6.0.1" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "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" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "jest-circus": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.0.6.tgz", - "integrity": "sha512-OJlsz6BBeX9qR+7O9lXefWoc2m9ZqcZ5Ohlzz0pTEAG4xMiZUJoacY8f4YDHxgk0oKYxj277AfOk9w6hZYvi1Q==", - "dev": true, - "requires": { - "@jest/environment": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.0.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.0.6", - "jest-matcher-utils": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-runtime": "^27.0.6", - "jest-snapshot": "^27.0.6", - "jest-util": "^27.0.6", - "pretty-format": "^27.0.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-config": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.0.6.tgz", - "integrity": "sha512-JZRR3I1Plr2YxPBhgqRspDE2S5zprbga3swYNrvY3HfQGu7p/GjyLOqwrYad97tX3U3mzT53TPHVmozacfP/3w==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.0.6", - "@jest/types": "^27.0.6", - "babel-jest": "^27.0.6", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "is-ci": "^3.0.0", - "jest-circus": "^27.0.6", - "jest-environment-jsdom": "^27.0.6", - "jest-environment-node": "^27.0.6", - "jest-get-type": "^27.0.6", - "jest-jasmine2": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-runner": "^27.0.6", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "micromatch": "^4.0.4", - "pretty-format": "^27.0.6" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "ci-info": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", - "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-ci": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", - "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", - "dev": true, - "requires": { - "ci-info": "^3.1.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-diff": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.6.tgz", - "integrity": "sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^27.0.6", - "jest-get-type": "^27.0.6", - "pretty-format": "^27.0.6" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-docblock": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", - "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.0.6.tgz", - "integrity": "sha512-m6yKcV3bkSWrUIjxkE9OC0mhBZZdhovIW5ergBYirqnkLXkyEn3oUUF/QZgyecA1cF1QFyTE8bRRl8Tfg1pfLA==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "chalk": "^4.0.0", - "jest-get-type": "^27.0.6", - "jest-util": "^27.0.6", - "pretty-format": "^27.0.6" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-environment-jsdom": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.0.6.tgz", - "integrity": "sha512-FvetXg7lnXL9+78H+xUAsra3IeZRTiegA3An01cWeXBspKXUhAwMM9ycIJ4yBaR0L7HkoMPaZsozCLHh4T8fuw==", - "dev": true, - "requires": { - "@jest/environment": "^27.0.6", - "@jest/fake-timers": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "jest-mock": "^27.0.6", - "jest-util": "^27.0.6", - "jsdom": "^16.6.0" - } - }, - "jest-environment-node": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.0.6.tgz", - "integrity": "sha512-+Vi6yLrPg/qC81jfXx3IBlVnDTI6kmRr08iVa2hFCWmJt4zha0XW7ucQltCAPhSR0FEKEoJ3i+W4E6T0s9is0w==", - "dev": true, - "requires": { - "@jest/environment": "^27.0.6", - "@jest/fake-timers": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "jest-mock": "^27.0.6", - "jest-util": "^27.0.6" - } - }, - "jest-get-type": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", - "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", - "dev": true - }, - "jest-haste-map": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.0.6.tgz", - "integrity": "sha512-4ldjPXX9h8doB2JlRzg9oAZ2p6/GpQUNAeiYXqcpmrKbP0Qev0wdZlxSMOmz8mPOEnt4h6qIzXFLDi8RScX/1w==", - "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.0.6", - "jest-serializer": "^27.0.6", - "jest-util": "^27.0.6", - "jest-worker": "^27.0.6", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - } - } - }, - "jest-jasmine2": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.0.6.tgz", - "integrity": "sha512-cjpH2sBy+t6dvCeKBsHpW41mjHzXgsavaFMp+VWRf0eR4EW8xASk1acqmljFtK2DgyIECMv2yCdY41r2l1+4iA==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.0.6", - "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.0.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.0.6", - "jest-matcher-utils": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-runtime": "^27.0.6", - "jest-snapshot": "^27.0.6", - "jest-util": "^27.0.6", - "pretty-format": "^27.0.6", - "throat": "^6.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-leak-detector": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.0.6.tgz", - "integrity": "sha512-2/d6n2wlH5zEcdctX4zdbgX8oM61tb67PQt4Xh8JFAIy6LRKUnX528HulkaG6nD5qDl5vRV1NXejCe1XRCH5gQ==", - "dev": true, - "requires": { - "jest-get-type": "^27.0.6", - "pretty-format": "^27.0.6" - } - }, - "jest-matcher-utils": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.0.6.tgz", - "integrity": "sha512-OFgF2VCQx9vdPSYTHWJ9MzFCehs20TsyFi6bIHbk5V1u52zJOnvF0Y/65z3GLZHKRuTgVPY4Z6LVePNahaQ+tA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^27.0.6", - "jest-get-type": "^27.0.6", - "pretty-format": "^27.0.6" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-message-util": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.0.6.tgz", - "integrity": "sha512-rBxIs2XK7rGy+zGxgi+UJKP6WqQ+KrBbD1YMj517HYN3v2BG66t3Xan3FWqYHKZwjdB700KiAJ+iES9a0M+ixw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.0.6", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.4", - "pretty-format": "^27.0.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.14.5" - } - }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - } + "node_modules/jest-validate/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "jest-mock": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.0.6.tgz", - "integrity": "sha512-lzBETUoK8cSxts2NYXSBWT+EJNzmUVtVVwS1sU9GwE1DLCfGsngg+ZVSIe0yd0ZSm+y791esiuo+WSwpXJQ5Bw==", + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "@types/node": "*" + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "node_modules/jest-watcher": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.0.5.tgz", + "integrity": "sha512-z9slj/0vOwBDBjN3L4z4ZYaA+pG56d6p3kTUhFRYGvXbXMWhXmb/FIxREZCD06DYUwDKKnj2T80+Pb71CQ0KEg==", "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", - "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", - "dev": true + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.0.5", + "@jest/types": "30.0.5", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.0.5", + "string-length": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } }, - "jest-resolve": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.0.6.tgz", - "integrity": "sha512-yKmIgw2LgTh7uAJtzv8UFHGF7Dm7XfvOe/LQ3Txv101fLM8cx2h1QVwtSJ51Q/SCxpIiKfVn6G2jYYMDNHZteA==", + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "chalk": "^4.0.0", - "escalade": "^3.1.1", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "resolve": "^1.20.0", - "slash": "^3.0.0" - }, + "license": "MIT", "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "jest-resolve-dependencies": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.0.6.tgz", - "integrity": "sha512-mg9x9DS3BPAREWKCAoyg3QucCr0n6S8HEEsqRCKSPjPcu9HzRILzhdzY3imsLoZWeosEbJZz6TKasveczzpJZA==", + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-snapshot": "^27.0.6" + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "jest-runner": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.0.6.tgz", - "integrity": "sha512-W3Bz5qAgaSChuivLn+nKOgjqNxM7O/9JOJoKDCqThPIg2sH/d4A/lzyiaFgnb9V1/w29Le11NpzTJSzga1vyYQ==", + "node_modules/jest-watcher/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", "dev": true, - "requires": { - "@jest/console": "^27.0.6", - "@jest/environment": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.0.6", - "jest-environment-jsdom": "^27.0.6", - "jest-environment-node": "^27.0.6", - "jest-haste-map": "^27.0.6", - "jest-leak-detector": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-runtime": "^27.0.6", - "jest-util": "^27.0.6", - "jest-worker": "^27.0.6", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" } + ], + "license": "MIT", + "engines": { + "node": ">=8" } }, - "jest-runtime": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.0.6.tgz", - "integrity": "sha512-BhvHLRVfKibYyqqEFkybsznKwhrsu7AWx2F3y9G9L95VSIN3/ZZ9vBpm/XCS2bS+BWz3sSeNGLzI3TVQ0uL85Q==", - "dev": true, - "requires": { - "@jest/console": "^27.0.6", - "@jest/environment": "^27.0.6", - "@jest/fake-timers": "^27.0.6", - "@jest/globals": "^27.0.6", - "@jest/source-map": "^27.0.6", - "@jest/test-result": "^27.0.6", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-mock": "^27.0.6", - "jest-regex-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-snapshot": "^27.0.6", - "jest-util": "^27.0.6", - "jest-validate": "^27.0.6", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^16.0.3" - }, + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - } + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "jest-serializer": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", - "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - } - } + "license": "MIT" }, - "jest-snapshot": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.0.6.tgz", - "integrity": "sha512-NTHaz8He+ATUagUgE7C/UtFcRoHqR2Gc+KDfhQIyx+VFgwbeEMjeP+ILpUTLosZn/ZtbNdCF5LkVnN/l+V751A==", - "dev": true, - "requires": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/parser": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.0.6", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.0.6", - "jest-get-type": "^27.0.6", - "jest-haste-map": "^27.0.6", - "jest-matcher-utils": "^27.0.6", - "jest-message-util": "^27.0.6", - "jest-resolve": "^27.0.6", - "jest-util": "^27.0.6", - "natural-compare": "^1.4.0", - "pretty-format": "^27.0.6", - "semver": "^7.3.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "jest-util": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", - "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "node_modules/jest-watcher/node_modules/jest-util": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", + "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", + "license": "MIT", + "dependencies": { + "@jest/types": "30.0.5", "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^3.0.0", - "picomatch": "^2.2.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "ci-info": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", - "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-ci": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", - "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", - "dev": true, - "requires": { - "ci-info": "^3.1.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "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" } }, - "jest-validate": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.0.6.tgz", - "integrity": "sha512-yhZZOaMH3Zg6DC83n60pLmdU1DQE46DW+KLozPiPbSbPhlXXaiUTDlhHQhHFpaqIFRrInko1FHXjTRpjWRuWfA==", + "node_modules/jest-watcher/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.0.6", - "leven": "^3.1.0", - "pretty-format": "^27.0.6" + "license": "MIT", + "engines": { + "node": ">=12" }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "jest-watcher": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.0.6.tgz", - "integrity": "sha512-/jIoKBhAP00/iMGnTwUBLgvxkn7vsOweDrOTSPzc7X9uOyUtJIDthQBTI1EXz90bdkrxorUZVhJwiB69gcHtYQ==", + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { - "@jest/test-result": "^27.0.6", - "@jest/types": "^27.0.6", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.0.6", - "string-length": "^4.0.1" - }, - "dependencies": { - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "jest-worker": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.6.tgz", - "integrity": "sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA==", + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" } }, - "js-tokens": { + "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, - "js-yaml": { + "node_modules/js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, - "requires": { + "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", - "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", - "dev": true - } + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" } }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" }, - "json-parse-better-errors": { + "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, - "json-parse-even-better-errors": { + "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "json-schema-traverse": { + "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, - "json-stable-stringify-without-jsonify": { + "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, - "json-stringify-safe": { + "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "requires": { - "minimist": "^1.2.5" + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { "graceful-fs": "^4.1.6" } }, - "jsonparse": { + "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" } }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { + "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "lines-and-columns": { + "node_modules/lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", "dev": true }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, - "locate-path": { + "node_modules/locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { + "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "lodash": { + "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash.ismatch": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", - "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", - "dev": true + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true, + "license": "MIT" }, - "lodash.map": { + "node_modules/lodash.map": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", + "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", "dev": true }, - "longest": { + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "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/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/longest": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", - "integrity": "sha1-eB4YMpaqlPbU2RbcM10NF676I/g=", - "dev": true + "integrity": "sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, - "requires": { - "yallist": "^4.0.0" + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" } }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, - "requires": { - "semver": "^6.0.0" + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "make-error": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", - "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", - "dev": true + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, - "requires": { - "tmpl": "1.0.x" + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" } }, - "map-obj": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", - "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", - "dev": true + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", - "dev": true, - "requires": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "dependencies": { - "hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "normalize-package-data": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", - "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "resolve": "^1.20.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - } - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "dev": true - } + "node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "merge": { + "node_modules/merge": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", "dev": true }, - "merge-stream": { + "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "license": "MIT" }, - "merge2": { + "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "engines": { + "node": ">= 8" } }, - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", - "dev": true - }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, - "requires": { - "mime-db": "1.40.0" + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" } }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } }, - "mimic-response": { + "node_modules/mimic-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } }, - "minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", "dev": true, - "requires": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" } }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "dev": true, - "requires": { - "minimist": "^1.2.5" + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - } + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "mkdirp-classic": { + "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "modify-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", - "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", - "dev": true + "dev": true, + "license": "MIT" }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" }, - "multistream": { + "node_modules/multistream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", "dev": true, - "requires": { + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { "once": "^1.4.0", "readable-stream": "^3.6.0" } }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } }, - "natural-compare": { + "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "neo-async": { + "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "dev": true, + "license": "MIT" }, - "nice-try": { + "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, - "nock": { + "node_modules/nock": { "version": "12.0.3", "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", "dev": true, - "requires": { + "dependencies": { "debug": "^4.1.0", "json-stringify-safe": "^5.0.1", "lodash": "^4.17.13", "propagate": "^2.0.0" }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - } + "engines": { + "node": ">= 10.13" } }, - "node-abi": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.0.tgz", - "integrity": "sha512-g6bZh3YCKQRdwuO/tSZZYJAw622SjsRfJ2X0Iy4sSOHZ34/sPPdVBn8fev2tj7njzLwuqPw9uMtGsGkO5kIQvg==", + "node_modules/node-abi": { + "version": "3.75.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.75.0.tgz", + "integrity": "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==", "dev": true, - "requires": { - "semver": "^5.4.1" + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true } } }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" - }, - "node-int64": { + "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-releases": { - "version": "1.1.74", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.74.tgz", - "integrity": "sha512-caJBVempXZPepZoZAPCWRTNxYQ+xtG/KAi4ozTA5A+nJ7IU+kLQCbqaUjb5Rwy14M9upBWiQ4NutcmW04LJSRw==", - "dev": true + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" }, - "noop-logger": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", - "dev": true + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" }, - "normalize-package-data": { + "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, - "requires": { + "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } } }, - "normalize-path": { + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "npm-run-path": { + "node_modules/npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", "dev": true, - "requires": { + "dependencies": { "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" } }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "null-check": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", - "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", - "dev": true + "node_modules/opencollective-postinstall": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", + "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", + "dev": true, + "bin": { + "opencollective-postinstall": "index.js" + } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "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" + } }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "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" + } }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "onetime": { + "node_modules/ora/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "requires": { - "mimic-fn": "^1.0.0" + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "opencollective-postinstall": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", - "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", - "dev": true + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "os-tmpdir": { + "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", - "dev": true + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "p-finally": { + "node_modules/p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "dev": true, + "engines": { + "node": ">=4" + } }, - "p-is-promise": { + "node_modules/p-is-promise": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "requires": { + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-locate": { + "node_modules/p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { + "dependencies": { "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" } }, - "p-try": { + "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } }, - "parent-module": { + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "requires": { + "dependencies": { "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "parse-json": { + "node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dev": true, - "requires": { + "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" } }, - "parse-passwd": { + "node_modules/parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "path-exists": { + "node_modules/path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } }, - "path-is-absolute": { + "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } }, - "path-key": { + "node_modules/path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } }, - "path-parse": { + "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "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" + } }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "pkg": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.3.1.tgz", - "integrity": "sha512-jT/sptM1ZG++FNk+jnJYNoWLDQXYd7hqpnBhd5j18SNW1jJzNYo55RahuCiD0KN0PX9mb53GWCqKM0ia/mJytA==", + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "dev": true, - "requires": { - "@babel/parser": "7.13.13", - "@babel/types": "7.13.12", - "chalk": "^4.1.0", - "escodegen": "^2.0.0", - "fs-extra": "^9.1.0", - "globby": "^11.0.3", - "into-stream": "^6.0.0", - "minimist": "^1.2.5", - "multistream": "^4.1.0", - "pkg-fetch": "3.2.2", - "prebuild-install": "6.0.1", - "progress": "^2.0.3", - "resolve": "^1.20.0", - "stream-meter": "^1.0.4", - "tslib": "2.1.0" - }, - "dependencies": { - "@babel/parser": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz", - "integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==", - "dev": true - }, - "@babel/types": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.12.tgz", - "integrity": "sha512-K4nY2xFN4QMvQwkQ+zmBDp6ANMbVNw6BbxWmYA4qNjhR9W+Lj/8ky5MEY2Me5r+B2c6/v6F53oMndG+f9s3IiA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", - "dev": true - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } + "license": "MIT", + "engines": { + "node": ">= 6" } }, - "pkg-dir": { + "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, - "requires": { + "dependencies": { "find-up": "^4.0.0" }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "pkg-fetch": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.2.2.tgz", - "integrity": "sha512-bLhFNT4cNnONxzbHo1H2mCCKuQkCR4dgQtv0gUZnWtp8TDP0v0UAXKHG7DXhAoTC5IYP3slLsFJtIda9ksny8g==", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, - "requires": { - "chalk": "^4.1.0", - "fs-extra": "^9.1.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.1", - "progress": "^2.0.3", - "semver": "^7.3.5", - "yargs": "^16.2.0" + "dependencies": { + "p-locate": "^4.1.0" }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - } + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" } }, - "please-upgrade-node": { + "node_modules/please-upgrade-node": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", "dev": true, - "requires": { + "dependencies": { "semver-compare": "^1.0.0" } }, - "prebuild-install": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.0.1.tgz", - "integrity": "sha512-7GOJrLuow8yeiyv75rmvZyeMGzl8mdEX5gY69d6a6bHWmiPevwqFw+tQavhK0EYMaSg3/KD24cWqeQv1EWsqDQ==", + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", "dev": true, - "requires": { - "detect-libc": "^1.0.3", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.7.0", - "noop-logger": "^0.1.1", - "npmlog": "^4.0.1", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", - "simple-get": "^3.0.3", + "simple-get": "^4.0.0", "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0", - "which-pm-runs": "^1.0.0" + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" } }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } }, - "prettier": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", - "dev": true + "node_modules/prettier": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz", + "integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } }, - "prettier-linter-helpers": { + "node_modules/prettier-linter-helpers": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, - "requires": { + "dependencies": { "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" } }, - "pretty-format": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", - "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", + "node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, - "requires": { - "@jest/types": "^27.0.6", - "ansi-regex": "^5.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } + "@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/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "process-nextick-args": { + "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "dev": true, + "license": "MIT" }, - "progress": { + "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "requires": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - } - }, - "prompts": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", - "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" + "license": "MIT", + "engines": { + "node": ">=0.4.0" } }, - "propagate": { + "node_modules/propagate": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", - "dev": true + "dev": true, + "engines": { + "node": ">= 8" + } }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" }, - "pump": { + "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, - "requires": { + "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, - "punycode": { + "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" }, - "queue-microtask": { + "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true + "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" + } + ] }, - "rc": { + "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, - "requires": { + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - } + "bin": { + "rc": "cli.js" } }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" }, - "read-pkg": { + "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, - "requires": { + "dependencies": { "@types/normalize-package-data": "^2.4.0", "normalize-package-data": "^2.5.0", "parse-json": "^5.0.0", "type-fest": "^0.6.0" }, - "dependencies": { - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@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" } }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "node_modules/read-pkg/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "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" } }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, - "requires": { + "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "requires": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - } - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true - }, - "require-directory": { + "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "require-main-filename": { + "node_modules/require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, - "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, - "requires": { - "path-parse": "^1.0.6" + "license": "MIT", + "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" } }, - "resolve-cwd": { + "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "resolve-from": "^5.0.0" }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "resolve-dir": { + "node_modules/resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", "dev": true, - "requires": { + "dependencies": { "expand-tilde": "^2.0.0", "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "resolve-from": { + "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "resolve-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", - "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", "dev": true, - "requires": { - "global-dirs": "^0.1.1" + "engines": { + "node": ">=4" } }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, - "requires": { - "onetime": "^2.0.0", + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" } }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" - }, - "reusify": { + "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "right-pad": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/right-pad/-/right-pad-1.0.1.tgz", - "integrity": "sha1-jKCMLLtbVedNr6lr9/0aJ9VoyNA=", - "dev": true + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } }, - "rimraf": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", - "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", - "requires": { + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true, - "requires": { - "is-promise": "^2.1.0" + "license": "MIT", + "engines": { + "node": ">=0.12.0" } }, - "run-node": { + "node_modules/run-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", - "dev": true + "dev": true, + "bin": { + "run-node": "run-node" + }, + "engines": { + "node": ">=4" + } }, - "run-parallel": { + "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, - "requires": { + "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" } }, - "rxjs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", - "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "dev": true, - "requires": { - "tslib": "^1.9.0" + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" } }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "safer-buffer": { + "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "license": "MIT" }, - "sanitize-filename": { + "node_modules/sanitize-filename": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", - "requires": { + "dependencies": { "truncate-utf8-bytes": "^1.0.0" } }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, - "requires": { - "xmlchars": "^2.2.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "semver-compare": { + "node_modules/semver-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", "dev": true }, - "set-blocking": { + "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, - "shebang-command": { + "node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, - "requires": { + "dependencies": { "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "shebang-regex": { + "node_modules/shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, - "simple-concat": { + "node_modules/simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true + "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" + } + ], + "license": "MIT" }, - "simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", "dev": true, - "requires": { - "decompress-response": "^4.2.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { + "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "slice-ansi": { + "node_modules/slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "requires": { + "dependencies": { "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" } }, - "source-map": { + "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } }, - "source-map-support": { + "node_modules/source-map-support": { "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "spdx-correct": { + "node_modules/spdx-correct": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, - "requires": { + "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, - "spdx-exceptions": { + "node_modules/spdx-exceptions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", "dev": true }, - "spdx-expression-parse": { + "node_modules/spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, - "requires": { + "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, - "spdx-license-ids": { + "node_modules/spdx-license-ids": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "requires": { - "through": "2" - } - }, - "split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true, - "requires": { - "readable-stream": "^3.0.0" + "license": "ISC", + "engines": { + "node": ">= 10.x" } }, - "sprintf-js": { + "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "escape-string-regexp": "^2.0.0" }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } + "engines": { + "node": ">=10" } }, - "standard-version": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/standard-version/-/standard-version-9.3.1.tgz", - "integrity": "sha512-5qMxXw/FxLouC5nANyx/5RY1kiorJx9BppUso8gN07MG64q2uLRmrPb4KfXp3Ql4s/gxjZwZ89e0FwxeLubGww==", + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, - "requires": { - "chalk": "^2.4.2", - "conventional-changelog": "3.1.24", - "conventional-changelog-config-spec": "2.1.0", - "conventional-changelog-conventionalcommits": "4.5.0", - "conventional-recommended-bump": "6.1.0", - "detect-indent": "^6.0.0", - "detect-newline": "^3.1.0", - "dotgitignore": "^2.1.0", - "figures": "^3.1.0", - "find-up": "^5.0.0", - "fs-access": "^1.0.1", - "git-semver-tags": "^4.0.0", - "semver": "^7.1.1", - "stringify-package": "^1.0.1", - "yargs": "^16.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - } + "license": "MIT", + "engines": { + "node": ">=8" } }, - "stream-meter": { + "node_modules/stream-meter": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", - "integrity": "sha1-Uq+Vql6nYKJJFxZwTb/5D3Ov3R0=", + "integrity": "sha512-4sOEtrbgFotXwnEuzzsQBYEV1elAeFSO8rSGeTwabuX1RRn/kEq9JVH7I0MRBhKVRR0sJkr0M0QCH7yOLf9fhQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "readable-stream": "^2.1.4" - }, + } + }, + "node_modules/stream-meter/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "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" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "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" } }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "requires": { - "safe-buffer": "~5.2.0" + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "string-length": { + "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", "dependencies": { - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "stringify-package": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz", - "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==", - "dev": true + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } }, - "strip-ansi": { + "node_modules/strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { + "dependencies": { "ansi-regex": "^4.1.0" }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - } + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "engines": { + "node": ">=6" } }, - "strip-bom": { + "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "strip-eof": { + "node_modules/strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "strip-final-newline": { + "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, - "requires": { - "min-indent": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", - "dev": true + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "supports-color": { + "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { + "dependencies": { "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "node_modules/synckit": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, + "license": "MIT", "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" } }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "table": { + "node_modules/table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "requires": { + "dependencies": { "ajv": "^6.10.2", "lodash": "^4.17.14", "slice-ansi": "^2.1.0", "string-width": "^3.0.0" }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/table/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" } }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar-fs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", + "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", + "dev": true, + "license": "MIT", + "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, - "tar-stream": { + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC" + }, + "node_modules/tar-stream": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" } }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "dependencies": { - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - } - }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, - "test-exclude": { + "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" } }, - "text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", - "dev": true - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true + "node_modules/text-extensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "through": { + "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, - "through2": { + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "requires": { - "readable-stream": "3" + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "tmp": { + "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" } }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" }, - "to-regex-range": { + "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - } - }, - "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } - }, - "trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true - }, - "trim-off-newlines": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", - "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", - "dev": true + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" }, - "truncate-utf8-bytes": { + "node_modules/truncate-utf8-bytes": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", "integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=", - "requires": { + "dependencies": { "utf8-byte-length": "^1.0.1" } }, - "ts-jest": { - "version": "27.0.4", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.4.tgz", - "integrity": "sha512-c4E1ECy9Xz2WGfTMyHbSaArlIva7Wi2p43QOMmCqjSSjHP06KXv+aT+eSY+yZMuqsMi3k7pyGsGj2q5oSl5WfQ==", - "dev": true, - "requires": { - "bs-logger": "0.x", - "buffer-from": "1.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^27.0.0", - "json5": "2.x", - "lodash": "4.x", - "make-error": "1.x", - "mkdirp": "1.x", - "semver": "7.x", - "yargs-parser": "20.x" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "node_modules/ts-api-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", + "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-jest": { + "version": "29.4.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.1.tgz", + "integrity": "sha512-SaeUtjfpg9Uqu8IbeDKtdaS0g8lS6FT6OzM3ezrDfErPJPHNDo/Ey+VFGP1bQIDfagYDLyRpd7O15XpG1Es2Uw==", + "dev": true, + "license": "MIT", + "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.2", + "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 }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true } } }, - "ts-node": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.4.1.tgz", - "integrity": "sha512-5LpRN+mTiCs7lI5EtbXmF/HfMeCjzt7DH9CZwtkr6SywStrNQC723wG+aOWFiLNn7zT3kD/RnFqi3ZUfr4l5Qw==", + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ts-jest/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "requires": { + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "peer": 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", - "source-map-support": "^0.5.6", - "yn": "^3.0.0" + "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 + } } }, - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - }, - "tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "node_modules/ts-node/node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true, - "requires": { - "tslib": "^1.8.1" + "engines": { + "node": ">=0.4.0" } }, - "tunnel-agent": { + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, - "requires": { + "license": "Apache-2.0", + "dependencies": { "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" } }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "requires": { - "prelude-ls": "~1.1.2" + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "type-detect": { + "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "type-fest": { + "node_modules/type-fest": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true + "node_modules/typescript": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", "dev": true, - "requires": { - "is-typedarray": "^1.0.0" + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/unzipper": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.3.tgz", + "integrity": "sha512-PZ8hTS+AqcGxsaQntl3IRBw65QrBI6lxzqDEL7IAo/XCEqRTKGfOX56Vea5TH9SZczRVxuzk1re04z/YjuYCJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "~3.7.2", + "duplexer2": "~0.1.4", + "fs-extra": "^11.2.0", + "graceful-fs": "^4.2.2", + "node-int64": "^0.4.0" } }, - "typescript": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", - "dev": true - }, - "uglify-js": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.1.tgz", - "integrity": "sha512-JhS3hmcVaXlp/xSo3PKY5R0JqKs5M3IV+exdLHW99qKvKivPO4Z8qbej6mte17SOPqAOVMjt/XGgWacnFSzM3g==", + "node_modules/unzipper/node_modules/fs-extra": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", "dev": true, - "optional": true + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } }, - "uri-js": { + "node_modules/uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { + "dependencies": { "punycode": "^2.1.0" } }, - "url-template": { + "node_modules/url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" }, - "utf8-byte-length": { + "node_modules/utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", "integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=" }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "v8-compile-cache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", - "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, - "v8-to-istanbul": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.0.0.tgz", - "integrity": "sha512-LkmXi8UUNxnCC+JlH7/fsfsKr5AU110l+SYGJimWNkWhxbN5EyeOtm1MJ0hhvqMMOhGwBj1Fp70Yv9i+hX0QAg==", + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" + "convert-source-map": "^2.0.0" }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "validate-npm-package-license": { + "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, - "requires": { + "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "requires": { - "xml-name-validator": "^3.0.0" - } - }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, - "requires": { - "makeerror": "1.0.x" + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" } }, - "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, - "requires": { - "iconv-lite": "0.4.24" + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" } }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" }, - "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - } + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, - "which": { + "node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, - "requires": { + "dependencies": { "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" } }, - "which-module": { + "node_modules/which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, - "which-pm-runs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", - "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wordwrap": { + "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" }, - "wrap-ansi": { + "node_modules/wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "requires": { + "dependencies": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", "strip-ansi": "^5.0.0" }, - "dependencies": { - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } + "engines": { + "node": ">=6" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "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" + } }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "requires": { - "mkdirp": "^0.5.1" + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "ws": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", - "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "requires": {} + "license": "MIT" }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "y18n": { + "node_modules/y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" }, - "yargs": { + "node_modules/yargs": { "version": "14.2.3", "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", - "requires": { + "license": "MIT", + "dependencies": { "cliui": "^5.0.0", "decamelize": "^1.2.0", "find-up": "^3.0.0", @@ -21741,46 +14820,62 @@ "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^15.0.1" - }, - "dependencies": { - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "yargs-parser": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", - "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } } }, - "yargs-parser": { + "node_modules/yargs-parser": { "version": "20.2.9", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } }, - "yn": { + "node_modules/yargs/node_modules/yargs-parser": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.3.tgz", + "integrity": "sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 4927e157..5aafdccb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@amplience/dc-cli", - "version": "0.13.0", + "version": "0.30.0", "description": "Dynamic Content CLI Tool", "main": "./dist/index.js", "man": "./dist/dc-cli.1", @@ -14,24 +14,14 @@ "pretest": "npm run lint", "test": "FORCE_COLOR=1 jest --silent --coverage", "fix": "prettier --write '**/*.ts'", - "reset": "git clean -dfx && git reset --hard && npm ci", - "prerelease": "npm run reset", - "release": "standard-version", - "prereleaseas": "npm run reset", - "releaseas": "standard-version --release-as ", "clean": "rimraf dist packages", "build": "npm run clean && tsc && cp HOW_TO_USE.1 dist/dc-cli.1", + "build:package:pre": "node scripts/package/pre-package.js", + "build:package:post": "node scripts/package/post-package.js", + "build:package": "npm run build && npm run build:package:pre && pkg --targets node22-macos-x64,node22-linux-x64,node22-win-x64 --out-dir packages . && npm run build:package:post", "update:man": "./update_man.sh", - "build:package": "npm run build && pkg --targets node8-macos-x64,node8-linux-x64,node8-win-x64 --out-dir packages .", - "build:compress": "npm run build:package && scripts/compress", "dev": "ts-node ./src/index.ts" }, - "standard-version": { - "scripts": { - "prerelease": "npm run build:package", - "posttag": "scripts/compress" - } - }, "repository": { "type": "git", "url": "git@github.com:amplience/dc-cli.git" @@ -79,53 +69,65 @@ "pkg": { "scripts": [ "./dist/**/*.js" + ], + "assets": [ + "./node_modules/axios/dist/node/**" ] }, "devDependencies": { - "@commitlint/cli": "^13.1.0", - "@commitlint/config-conventional": "^8.2.0", - "@types/chalk": "^2.2.0", - "@types/jest": "^24.0.18", - "@types/lodash": "^4.14.144", - "@types/node-fetch": "^2.5.7", - "@types/promise-retry": "^1.1.3", - "@types/rimraf": "^3.0.0", - "@types/table": "^4.0.7", - "@types/url-template": "^2.0.28", - "@typescript-eslint/eslint-plugin": "^2.34.0", - "@typescript-eslint/parser": "^2.34.0", - "adm-zip": "^0.4.13", - "axios-mock-adapter": "^1.19.0", - "commitizen": "^4.2.4", - "cz-conventional-changelog": "^3.0.2", - "eslint": "^6.4.0", - "eslint-config-prettier": "^6.3.0", - "eslint-plugin-prettier": "^3.1.1", - "husky": "^3.0.5", - "jest": "^27.0.6", - "nock": "^12.0.3", - "pkg": "^5.3.1", - "prettier": "^1.18.2", - "standard-version": "^9.3.1", - "ts-jest": "^27.0.4", - "ts-node": "^8.4.1", - "typescript": "^3.9.10" + "@commitlint/cli": "19.7.1", + "@commitlint/config-conventional": "19.7.1", + "@eslint/eslintrc": "3.3.1", + "@eslint/js": "9.32.0", + "@types/cli-progress": "3.11.6", + "@types/fs-extra": "9.0.13", + "@types/graceful-fs": "4.1.9", + "@types/jest": "30.0.0", + "@types/lodash": "4.14.144", + "@types/node": "20.17.19", + "@types/node-fetch": "2.5.7", + "@types/rimraf": "3.0.0", + "@types/table": "4.0.7", + "@types/url-template": "2.0.28", + "@types/yargs": "16.0.4", + "@typescript-eslint/eslint-plugin": "8.24.1", + "@typescript-eslint/parser": "8.24.1", + "@yao-pkg/pkg": "6.5.1", + "axios-mock-adapter": "1.19.0", + "commitizen": "4.3.1", + "cz-conventional-changelog": "3.3.0", + "eslint": "9.32.0", + "eslint-config-prettier": "10.0.1", + "eslint-plugin-prettier": "5.2.3", + "globals": "15.15.0", + "husky": "3.0.5", + "jest": "30.0.5", + "nock": "12.0.3", + "prettier": "3.5.1", + "ts-jest": "29.4.1", + "ts-node": "10.9.1", + "typescript": "5.7.3" }, "dependencies": { - "ajv": "^6.12.3", - "axios": "^0.21.1", - "chalk": "^2.4.2", - "dc-management-sdk-js": "^1.14.0", - "lodash": "^4.17.21", - "node-fetch": "^2.6.1", - "promise-retry": "^2.0.1", - "rimraf": "^3.0.0", - "sanitize-filename": "^1.6.3", - "table": "^5.4.6", - "url-template": "^2.0.8", - "yargs": "^14.0.0" + "ajv": "6.12.6", + "axios": "1.12.2", + "axios-retry": "4.5.0", + "bottleneck": "2.19.5", + "chalk": "2.4.2", + "cli-progress": "3.12.0", + "dc-management-sdk-js": "3.2.0", + "enquirer": "2.3.6", + "fs-extra": "10.1.0", + "graceful-fs": "4.2.11", + "lodash": "4.17.21", + "node-fetch": "2.7.0", + "rimraf": "3.0.2", + "sanitize-filename": "1.6.3", + "table": "5.4.6", + "url-template": "2.0.8", + "yargs": "14.2.3" }, "engines": { - "node": ">12" + "node": ">=20" } } diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 00000000..19e43da6 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,9 @@ +{ + "packages": { + ".": { + "release-type": "node", + "package-name": "dc-cli" + } + }, + "bump-minor-pre-major": true +} diff --git a/scripts/compress b/scripts/compress deleted file mode 100755 index 138f3375..00000000 --- a/scripts/compress +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env node - -const fs = require('fs'); -const path = require('path'); -const Zip = require('adm-zip'); - -const VERSION = require('../package.json').version; -const PACKAGES_DIR = path.join(__dirname, '../packages'); - -fs.readdirSync(PACKAGES_DIR) - .filter(filename => filename.match(/^dc-cli.*$/)) - .forEach(filename => { - const toFilename = `${filename.replace('.exe', '')}-${VERSION}${filename.match(/\.exe$/) ? '.exe' : ''}`; - fs.renameSync(path.join(PACKAGES_DIR, filename), path.join(PACKAGES_DIR, toFilename)); - - const zip = new Zip(); - zip.addLocalFile(path.join(PACKAGES_DIR, toFilename)); - zip.writeZip(`${PACKAGES_DIR}/${filename.replace(/\.exe$/, '')}-${VERSION}.zip`); - - fs.unlinkSync(path.join(PACKAGES_DIR, toFilename)); - }); diff --git a/scripts/compress.sh b/scripts/compress.sh new file mode 100755 index 00000000..7d4d490d --- /dev/null +++ b/scripts/compress.sh @@ -0,0 +1,5 @@ +#!/bin/sh +for i in ./packages/* +do + [ -f "$i" ] && zip -r "$i.zip" "$i" && rm "$i" +done diff --git a/scripts/package/post-package.js b/scripts/package/post-package.js new file mode 100644 index 00000000..c40c772d --- /dev/null +++ b/scripts/package/post-package.js @@ -0,0 +1,12 @@ +const { existsSync, copyFileSync, unlinkSync } = require('fs'); +const { resolve } = require('path'); + +// Temporarily patch Axios package.json to fix issue when used in conjuction with `@yao-pkg/pkg` +// Relates to: https://github.com/yao-pkg/pkg/issues/16 & https://github.com/yao-pkg/pkg/pull/33 +const axiosPkgPath = resolve(__dirname, '../../node_modules/axios/package.json'); +const backupPath = `${axiosPkgPath}.bak`; + +if (existsSync(backupPath)) { + copyFileSync(backupPath, axiosPkgPath); + unlinkSync(backupPath); +} diff --git a/scripts/package/pre-package.js b/scripts/package/pre-package.js new file mode 100644 index 00000000..113d6a3d --- /dev/null +++ b/scripts/package/pre-package.js @@ -0,0 +1,11 @@ +const { readFileSync, writeFileSync } = require('fs'); +const { resolve } = require('path'); + +// Temporarily patch Axios package.json to fix issue when used in conjuction with `@yao-pkg/pkg` +// Relates to: https://github.com/yao-pkg/pkg/issues/16 & https://github.com/yao-pkg/pkg/pull/33 +const axiosPkgPath = resolve(__dirname, '../../node_modules/axios/package.json'); +const axiosPkg = JSON.parse(readFileSync(axiosPkgPath, 'utf-8')); + +writeFileSync(`${axiosPkgPath}.bak`, JSON.stringify(axiosPkg, null, 2)); +axiosPkg.main = './dist/node/axios.cjs'; +writeFileSync(axiosPkgPath, JSON.stringify(axiosPkg, null, 2)); diff --git a/src/__snapshots__/cli.spec.ts.snap b/src/__snapshots__/cli.spec.ts.snap index 70e5ee40..a968b08e 100644 --- a/src/__snapshots__/cli.spec.ts.snap +++ b/src/__snapshots__/cli.spec.ts.snap @@ -1,26 +1,25 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`cli should create a yarg instance if one is not supplied 1`] = ` "dc-cli Commands: - dc-cli configure Saves the configuration options to a file - dc-cli content-item Content Item - dc-cli content-repository Content Repository - dc-cli content-type-schema Content Type Schema - dc-cli content-type Content Type - dc-cli event Event - dc-cli extension Extension - dc-cli hub Hub - dc-cli search-index Search Index - dc-cli settings Settings + dc-cli configure Saves the configuration options to a file + dc-cli content-item Content Item + dc-cli content-repository Content Repository + dc-cli content-type-schema Content Type Schema + dc-cli content-type Content Type + dc-cli event Event + dc-cli extension Extension + dc-cli hub Hub + dc-cli job Job + dc-cli linked-content-repository Linked Content Repository + dc-cli search-index Search Index + dc-cli settings Settings + dc-cli webhook Webhook Options: - --help Show help [boolean] - --version Show version number [boolean] - --clientId [string] [required] - --clientSecret [string] [required] - --hubId [string] [required] - --config Path to JSON config file [string] [default: \\"config.json\\"] -Error: Please specify at least one command" + --help Show help [boolean] + --version Show version number [boolean] +2025-02-24T01:01:01.001Z Error: Please specify at least one command" `; diff --git a/src/__snapshots__/error-handler.spec.ts.snap b/src/__snapshots__/error-handler.spec.ts.snap index fc4a0d95..ff855750 100644 --- a/src/__snapshots__/error-handler.spec.ts.snap +++ b/src/__snapshots__/error-handler.spec.ts.snap @@ -1,8 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`error handler tests HttpErrors should display contenthub http network error 1`] = ` +" +2025-02-24T01:01:01.001Z Error: No response from server - check your network connection." +`; + exports[`error handler tests HttpErrors should display sdk http 400 error 1`] = ` " -Error: Request failed with status code 400 +2025-02-24T01:01:01.001Z Error: Request failed with status code 400 { \\"status\\": 400, \\"data\\": {} @@ -11,50 +16,55 @@ Error: Request failed with status code 400 exports[`error handler tests HttpErrors should display sdk http 401 error 1`] = ` " -Error: Unauthorized - Please ensure your client ID & secret are correct." +2025-02-24T01:01:01.001Z Error: Unauthorized - Please ensure your client ID & secret or PAT token are correct." `; exports[`error handler tests HttpErrors should display sdk http 403 error (with request) 1`] = ` " -Error: The requested action (PATCH: http://example.com) is not available (forbidden), ensure you have permission to perform this action." +2025-02-24T01:01:01.001Z Error: The requested action (PATCH: http://example.com) is not available (forbidden), ensure you have permission to perform this action." `; exports[`error handler tests HttpErrors should display sdk http 403 error 1`] = ` " -Error: The requested action is not available (forbidden), ensure you have permission to perform this action." +2025-02-24T01:01:01.001Z Error: The requested action is not available (forbidden), ensure you have permission to perform this action." `; exports[`error handler tests HttpErrors should display sdk http 429 error 1`] = ` " -Error: Too many requests - Please try again later." +2025-02-24T01:01:01.001Z Error: Too many requests - Please try again later." `; exports[`error handler tests HttpErrors should display sdk http 500 error 1`] = ` " -Error: Internal Server Error - Message" +2025-02-24T01:01:01.001Z Error: Internal Server Error - Message" `; exports[`error handler tests HttpErrors should display sdk http 501 error - unmapped status code 1`] = ` " -Error: Message" +2025-02-24T01:01:01.001Z Error: Message" `; exports[`error handler tests HttpErrors should display sdk http error 1`] = ` " -Error: Message" +2025-02-24T01:01:01.001Z Error: Message" +`; + +exports[`error handler tests HttpErrors should display sdk http network error 1`] = ` +" +2025-02-24T01:01:01.001Z Error: No response from server - check your network connection." `; exports[`error handler tests should display sdk error ({message: string}) 1`] = ` " -Error: Error message" +2025-02-24T01:01:01.001Z Error: Error message" `; exports[`error handler tests should display sdk error (new Error()) 1`] = ` " -Error: Error instance" +2025-02-24T01:01:01.001Z Error: Error instance" `; exports[`error handler tests should display sdk error (string) 1`] = ` " -Error: The list-content-type-schemas action is not available, ensure you have permission to perform this action." +2025-02-24T01:01:01.001Z Error: The list-content-type-schemas action is not available, ensure you have permission to perform this action." `; diff --git a/src/cli.spec.ts b/src/cli.spec.ts index 8c296331..2e3c0fef 100644 --- a/src/cli.spec.ts +++ b/src/cli.spec.ts @@ -5,6 +5,8 @@ import YargsCommandBuilderOptions from './common/yargs/yargs-command-builder-opt jest.mock('./commands/configure'); +jest.useFakeTimers().setSystemTime(new Date('2025-02-24T01:01:01.001Z')); + describe('cli', (): void => { afterEach(() => { jest.restoreAllMocks(); @@ -20,15 +22,11 @@ describe('cli', (): void => { it('should configure yarg instance', async (): Promise => { const argv = Yargs(process.argv.slice(2)); - const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); - const spyConfig = jest.spyOn(argv, 'config').mockReturnThis(); const spyCommandDir = jest.spyOn(argv, 'commandDir').mockReturnThis(); const spyDemandCommand = jest.spyOn(argv, 'demandCommand').mockReturnValue(argv); await cli.default(argv); - expect(spyOptions).toHaveBeenCalledWith(configureCommandOptions); - expect(spyConfig).toHaveBeenCalledWith('config', expect.any(Function)); expect(spyCommandDir).toHaveBeenCalledWith('./commands', YargsCommandBuilderOptions); expect(spyDemandCommand).toHaveBeenCalledWith(1, 'Please specify at least one command'); }); diff --git a/src/cli.ts b/src/cli.ts index 401b428e..a84ce848 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,42 +1,38 @@ import Yargs from 'yargs/yargs'; import YargsCommandBuilderOptions from './common/yargs/yargs-command-builder-options'; -import { configureCommandOptions, readConfigFile } from './commands/configure'; +import { readConfigFile } from './commands/configure'; import { Arguments, Argv } from 'yargs'; import errorHandler from './error-handler'; -const readConfig = (configFile: string): object => { +export const readConfig = (configFile: string): object => { return readConfigFile(configFile, process.argv[2] === 'configure'); }; const configureYargs = (yargInstance: Argv): Promise => { - return new Promise( - async (resolve): Promise => { - let failInvoked = false; - const isYError = (err?: Error | string): boolean => err instanceof Error && err.name === 'YError'; - const failFn = (msg: string, err?: Error | string): void => { - // fail should only be invoked once - if (failInvoked) { - return; - } - failInvoked = true; - if ((msg && !err) || isYError(err)) { - yargInstance.showHelp('error'); - } - errorHandler(err || msg); - }; - const argv = await yargInstance - .scriptName('dc-cli') - .options(configureCommandOptions) - .config('config', readConfig) - .commandDir('./commands', YargsCommandBuilderOptions) - .strict() - .demandCommand(1, 'Please specify at least one command') - .exitProcess(false) - .showHelpOnFail(false) - .fail(failFn).argv; - resolve(argv); - } - ); + return new Promise(async (resolve): Promise => { + let failInvoked = false; + const isYError = (err?: Error | string): boolean => err instanceof Error && err.name === 'YError'; + const failFn = (msg: string, err?: Error | string): void => { + // fail should only be invoked once + if (failInvoked) { + return; + } + failInvoked = true; + if ((msg && !err) || isYError(err)) { + yargInstance.showHelp('error'); + } + errorHandler(err || msg); + }; + const argv = await yargInstance + .scriptName('dc-cli') + .commandDir('./commands', YargsCommandBuilderOptions) + .strict() + .demandCommand(1, 'Please specify at least one command') + .exitProcess(false) + .showHelpOnFail(false) + .fail(failFn).argv; + resolve(argv); + }); }; export default async (yargInstance = Yargs(process.argv.slice(2))): Promise => { diff --git a/src/commands/configure.spec.ts b/src/commands/configure.spec.ts index f8987661..65239135 100644 --- a/src/commands/configure.spec.ts +++ b/src/commands/configure.spec.ts @@ -2,7 +2,7 @@ import { CONFIG_FILENAME, handler, readConfigFile } from './configure'; import fs from 'fs'; import { join } from 'path'; -describe('configure command', function() { +describe('configure command', function () { afterEach((): void => { jest.restoreAllMocks(); }); @@ -19,14 +19,12 @@ describe('configure command', function() { const configFixture = { clientId: 'client-id', clientSecret: 'client-id', - hubId: 'hub-id' + hubId: 'hub-id', + patToken: 'amp-pat' }; it('should write a config file and create the .amplience dir', () => { - jest - .spyOn(fs, 'existsSync') - .mockReturnValueOnce(false) - .mockReturnValueOnce(false); + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(false).mockReturnValueOnce(false); jest.spyOn(fs, 'mkdirSync').mockReturnValueOnce(undefined); jest.spyOn(fs, 'writeFileSync').mockReturnValueOnce(undefined); @@ -41,10 +39,7 @@ describe('configure command', function() { }); it('should optionally write dst parameters when present', () => { - jest - .spyOn(fs, 'existsSync') - .mockReturnValueOnce(false) - .mockReturnValueOnce(false); + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(false).mockReturnValueOnce(false); jest.spyOn(fs, 'mkdirSync').mockReturnValueOnce(undefined); jest.spyOn(fs, 'writeFileSync').mockReturnValueOnce(undefined); @@ -64,10 +59,7 @@ describe('configure command', function() { }); it('should write the config file and re-used the .amplience dir', () => { - jest - .spyOn(fs, 'existsSync') - .mockReturnValueOnce(false) - .mockReturnValueOnce(true); + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(false).mockReturnValueOnce(true); jest.spyOn(fs, 'mkdirSync'); jest.spyOn(fs, 'writeFileSync').mockReturnValueOnce(undefined); @@ -82,10 +74,7 @@ describe('configure command', function() { }); it('should write a config file and use the specified file', () => { - jest - .spyOn(fs, 'existsSync') - .mockReturnValueOnce(false) - .mockReturnValueOnce(false); + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(false).mockReturnValueOnce(false); jest.spyOn(fs, 'mkdirSync').mockReturnValueOnce(undefined); jest.spyOn(fs, 'writeFileSync').mockReturnValueOnce(undefined); @@ -100,10 +89,7 @@ describe('configure command', function() { }); it('should report an error if its not possible to create the .amplience dir', () => { - jest - .spyOn(fs, 'existsSync') - .mockReturnValueOnce(false) - .mockReturnValueOnce(false); + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(false).mockReturnValueOnce(false); jest.spyOn(fs, 'mkdirSync').mockImplementation(() => { throw new Error('Mock error'); }); @@ -111,7 +97,7 @@ describe('configure command', function() { expect(() => { handler({ ...yargArgs, ...configFixture, config: CONFIG_FILENAME() }); - }).toThrowError(/^Unable to create dir ".*". Reason: .*/); + }).toThrow(/^Unable to create dir ".*". Reason: .*/); expect(fs.existsSync).toHaveBeenCalledWith(expect.stringMatching(/\.amplience$/)); expect(fs.mkdirSync).toHaveBeenCalledWith(expect.stringMatching(/\.amplience$/), { recursive: true }); @@ -119,10 +105,7 @@ describe('configure command', function() { }); it('should report an error if its not possible to create/write the config file', () => { - jest - .spyOn(fs, 'existsSync') - .mockReturnValueOnce(false) - .mockReturnValueOnce(true); + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(false).mockReturnValueOnce(true); jest.spyOn(fs, 'mkdirSync'); jest.spyOn(fs, 'writeFileSync').mockImplementationOnce(() => { throw new Error('Mock Error'); @@ -130,7 +113,7 @@ describe('configure command', function() { expect(() => { handler({ ...yargArgs, ...configFixture, config: CONFIG_FILENAME() }); - }).toThrowError(/^Unable to write config file ".*". Reason: .*/); + }).toThrow(/^Unable to write config file ".*". Reason: .*/); expect(fs.existsSync).toHaveBeenCalledWith(expect.stringMatching(/\.amplience$/)); expect(fs.mkdirSync).not.toHaveBeenCalledWith(); @@ -184,10 +167,9 @@ describe('configure command', function() { expect(fs.existsSync).toHaveBeenCalledWith(configFile); expect(fs.readFileSync).toHaveBeenCalledWith(configFile, 'utf-8'); expect(mockExit).toHaveBeenCalledWith(2); - expect(mockError.mock.calls[0][0]).toMatchInlineSnapshot(` - "FATAL - Could not parse JSON configuration. Inspect the configuration file at config.json - Unexpected token i in JSON at position 1" - `); + expect(mockError.mock.calls[0][0]).toContain( + 'FATAL - Could not parse JSON configuration. Inspect the configuration file at config.json' + ); }); it('should not exit the process if the config file is invalid, but ignoreError is true', () => { @@ -203,10 +185,9 @@ describe('configure command', function() { expect(fs.existsSync).toHaveBeenCalledWith(configFile); expect(fs.readFileSync).toHaveBeenCalledWith(configFile, 'utf-8'); expect(mockExit).not.toHaveBeenCalled(); - expect(mockError.mock.calls[0][0]).toMatchInlineSnapshot(` - "The configuration file at config.json is invalid, its contents will be ignored. - Unexpected token i in JSON at position 1" - `); + expect(mockError.mock.calls[0][0]).toContain( + 'The configuration file at config.json is invalid, its contents will be ignored.' + ); }); it('should use USERPROFILE env var for win32', () => { diff --git a/src/commands/configure.ts b/src/commands/configure.ts index c46c5fab..ff2a6150 100644 --- a/src/commands/configure.ts +++ b/src/commands/configure.ts @@ -1,4 +1,5 @@ -import { Arguments, Argv } from 'yargs'; +import yargs, { Arguments, Argv } from 'yargs'; +import { readConfig } from '../cli'; import { CommandOptions } from '../interfaces/command-options.interface'; import fs from 'fs'; import { join, dirname } from 'path'; @@ -11,8 +12,19 @@ export const desc = 'Saves the configuration options to a file'; export const CONFIG_FILENAME = (platform: string = process.platform): string => join(process.env[platform == 'win32' ? 'USERPROFILE' : 'HOME'] || __dirname, '.amplience', 'dc-cli-config.json'); +export const configureCommandOptions: CommandOptions = { + clientId: { type: 'string', demandOption: false }, + clientSecret: { type: 'string', demandOption: false }, + hubId: { type: 'string', demandOption: true }, + patToken: { type: 'string', demandOption: false }, + + config: { type: 'string', default: CONFIG_FILENAME() } +}; + export const builder = (yargs: Argv): void => { yargs + .options(configureCommandOptions) + .config('config', readConfig) .option('dstHubId', { type: 'string', describe: 'Destination hub ID. If not specified, it will be the same as the source.' @@ -29,13 +41,23 @@ export const builder = (yargs: Argv): void => { }); }; +const getCommandLineArgs = (): Arguments => { + const rawArgs = process.argv.slice(2); + return yargs(rawArgs) + .option('clientId', { type: 'string' }) + .option('clientSecret', { type: 'string' }) + .option('patToken', { type: 'string' }).argv; +}; + export type ConfigurationParameters = { - clientId: string; - clientSecret: string; + clientId?: string; + clientSecret?: string; + patToken?: string; hubId: string; dstClientId?: string; dstSecret?: string; + dstPatToken?: string; dstHubId?: string; }; @@ -43,14 +65,6 @@ type ConfigArgument = { config: string; }; -export const configureCommandOptions: CommandOptions = { - clientId: { type: 'string', demandOption: true }, - clientSecret: { type: 'string', demandOption: true }, - hubId: { type: 'string', demandOption: true }, - - config: { type: 'string', default: CONFIG_FILENAME() } -}; - const writeConfigFile = (configFile: string, parameters: ConfigurationParameters): void => { const dir = dirname(configFile); if (!fs.existsSync(dir)) { @@ -89,11 +103,22 @@ export const readConfigFile = (configFile: string, ignoreError?: boolean): objec }; export const handler = (argv: Arguments): void => { - const { clientId, clientSecret, hubId } = argv; + const { clientId, clientSecret, hubId, patToken } = argv; const storedConfig = readConfigFile(argv.config); + const newConfig: ConfigurationParameters = { clientId, clientSecret, hubId, patToken }; + const commandLineArgs = getCommandLineArgs(); - const newConfig: ConfigurationParameters = { clientId, clientSecret, hubId }; - + if ((commandLineArgs.clientId || commandLineArgs.clientSecret) && commandLineArgs.patToken) { + console.error('Error: Specify clientId & clientSecret or patToken, not both'); + return; + } + if (commandLineArgs.patToken && (clientId || clientSecret)) { + delete newConfig.clientId; + delete newConfig.clientSecret; + } + if ((commandLineArgs.clientId || commandLineArgs.clientSecret) && patToken) { + delete newConfig.patToken; + } if (argv.dstClientId) newConfig.dstClientId = argv.dstClientId; if (argv.dstSecret) newConfig.dstSecret = argv.dstSecret; if (argv.dstHubId) newConfig.dstHubId = argv.dstHubId; diff --git a/src/commands/content-item.spec.ts b/src/commands/content-item.spec.ts index 6aa550a7..15027787 100644 --- a/src/commands/content-item.spec.ts +++ b/src/commands/content-item.spec.ts @@ -1,12 +1,17 @@ import { builder } from './content-item'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; import Yargs from 'yargs/yargs'; +import { configureCommandOptions } from './configure'; -describe('content-item command', function() { +describe('content-item command', function () { it('should include the commands in the content-item dir', () => { const argv = Yargs(process.argv.slice(2)); const spyCommandDir = jest.spyOn(argv, 'commandDir').mockReturnValue(argv); + const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); + const spyConfig = jest.spyOn(argv, 'config').mockReturnThis(); builder(argv); expect(spyCommandDir).toHaveBeenCalledWith('content-item', YargsCommandBuilderOptions); + expect(spyOptions).toHaveBeenCalledWith(configureCommandOptions); + expect(spyConfig).toHaveBeenCalledWith('config', expect.any(Function)); }); }); diff --git a/src/commands/content-item.ts b/src/commands/content-item.ts index 5850f269..cf63c4b1 100644 --- a/src/commands/content-item.ts +++ b/src/commands/content-item.ts @@ -1,5 +1,7 @@ import { Argv } from 'yargs'; +import { readConfig } from '../cli'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import { configureCommandOptions } from './configure'; export const command = 'content-item'; @@ -8,8 +10,9 @@ export const desc = 'Content Item'; export const builder = (yargs: Argv): Argv => yargs .commandDir('content-item', YargsCommandBuilderOptions) + .options(configureCommandOptions) + .config('config', readConfig) .demandCommand() .help(); -// eslint-disable-next-line @typescript-eslint/no-empty-function export const handler = (): void => {}; diff --git a/src/commands/content-item/__mocks__/dependant-content-helper.ts b/src/commands/content-item/__mocks__/dependant-content-helper.ts index c1dd3277..c1aa2e99 100644 --- a/src/commands/content-item/__mocks__/dependant-content-helper.ts +++ b/src/commands/content-item/__mocks__/dependant-content-helper.ts @@ -1,9 +1,12 @@ -import { ContentDependancy } from '../../../common/content-item/content-dependancy-tree'; +import { ContentDependancy, DependancyContentTypeSchema } from '../../../common/content-item/content-dependancy-tree'; -function dependancy(id: string): ContentDependancy { +function dependancy( + id: string, + type = 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-link' +): ContentDependancy { return { _meta: { - schema: 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-link', + schema: type as DependancyContentTypeSchema, name: 'content-link' }, contentType: 'https://dev-solutions.s3.amazonaws.com/DynamicContentTypes/Accelerators/blog.json', @@ -21,14 +24,35 @@ function dependProps(itemProps: [string, string][]): object { } // eslint-disable-next-line @typescript-eslint/no-explicit-any -export function dependsOn(itemIds: string[], itemProps?: [string, string][]): any { +export function dependsOn(itemIds: string[], type?: string, itemProps?: [string, string][]): any { itemProps = itemProps || []; return { - links: itemIds.map(id => dependancy(id)), + links: itemIds.map(id => dependancy(id, type)), ...dependProps(itemProps) }; } +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function hierarchyParent(parentId: string, itemProps?: [string, string][]): any { + itemProps = itemProps || []; + const item = { + ...dependProps(itemProps) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any; + + if (!item._meta) { + item._meta = {}; + } + + if (!item._meta.hierarchy) { + item._meta.hierarchy = {}; + } + + item._meta.hierarchy.parentId = parentId; + + return item; +} + // eslint-disable-next-line @typescript-eslint/no-explicit-any export function dependantType(items: number): any { return { diff --git a/src/commands/content-item/archive.spec.ts b/src/commands/content-item/archive.spec.ts index a2eb5886..9610f0e2 100644 --- a/src/commands/content-item/archive.spec.ts +++ b/src/commands/content-item/archive.spec.ts @@ -1,23 +1,15 @@ -import { - builder, - command, - handler, - LOG_FILENAME, - filterContentItems, - getContentItems, - processItems, - coerceLog -} from './archive'; +import { builder, command, handler, LOG_FILENAME, coerceLog } from './archive'; import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; -import { ContentRepository, ContentItem, Folder } from 'dc-management-sdk-js'; +import { ContentRepository, ContentItem, Folder, Status } from 'dc-management-sdk-js'; import Yargs from 'yargs/yargs'; import readline from 'readline'; import MockPage from '../../common/dc-management-sdk-js/mock-page'; import { dirname } from 'path'; import { promisify } from 'util'; -import { exists, readFile, unlink, mkdir, writeFile } from 'fs'; +import { readFile, unlink, mkdir, writeFile, existsSync } from 'fs'; import { FileLog, setVersion } from '../../common/file-log'; import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import * as fetchContentModule from '../../common/filter/fetch-content'; setVersion('test-ver'); @@ -30,6 +22,8 @@ jest.mock('../../common/log-helpers', () => ({ getDefaultLogPath: jest.fn() })); +jest.mock('../../common/filter/fetch-content'); + describe('content-item archive command', () => { afterEach((): void => { jest.restoreAllMocks(); @@ -57,6 +51,7 @@ describe('content-item archive command', () => { mockItemUpdate: () => void; mockRepoGet: () => void; mockFolderGet: () => void; + mockGetContent: () => void; contentItems: ContentItem[]; } => { const mockGet = jest.fn(); @@ -67,6 +62,7 @@ describe('content-item archive command', () => { const mockItemUpdate = jest.fn(); const mockRepoGet = jest.fn(); const mockFolderGet = jest.fn(); + const mockGetContent = jest.spyOn(fetchContentModule, 'getContent') as jest.Mock; const contentItems = [ new ContentItem({ @@ -142,8 +138,7 @@ describe('content-item archive command', () => { }, _links: { 'content-items': { - href: - 'https://api.amplience.net/v2/content/content-repositories/repo1/content-items{?folderId,page,projection,size,sort,status}', + href: 'https://api.amplience.net/v2/content/content-repositories/repo1/content-items{?folderId,page,projection,size,sort,status}', templated: true } }, @@ -173,8 +168,7 @@ describe('content-item archive command', () => { }, _links: { 'content-items': { - href: - 'https://api.amplience.net/v2/content/content-repositories/repo1/content-items{?folderId,page,projection,size,sort,status}', + href: 'https://api.amplience.net/v2/content/content-repositories/repo1/content-items{?folderId,page,projection,size,sort,status}', templated: true } }, @@ -195,8 +189,7 @@ describe('content-item archive command', () => { }, _links: { 'content-items': { - href: - 'https://api.amplience.net/v2/content/content-repositories/repo1/content-items{?folderId,page,projection,size,sort,status}', + href: 'https://api.amplience.net/v2/content/content-repositories/repo1/content-items{?folderId,page,projection,size,sort,status}', templated: true } }, @@ -216,6 +209,8 @@ describe('content-item archive command', () => { mockItemsList.mockResolvedValue(new MockPage(ContentItem, contentItems)); + mockGetContent.mockResolvedValue(contentItems); + if (archiveError) { mockArchive.mockRejectedValue(new Error('Error')); mockFolderGet.mockRejectedValue(new Error('Error')); @@ -231,16 +226,17 @@ describe('content-item archive command', () => { mockItemUpdate, mockRepoGet, mockFolderGet, + mockGetContent, contentItems }; }; - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('archive [id]'); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); @@ -302,17 +298,27 @@ describe('content-item archive command', () => { describe: 'Path to a log file to write to.', coerce: coerceLog }); + + expect(spyOption).toHaveBeenCalledWith('ignoreSchemaValidation', { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during archive' + }); }); }); - describe('handler tests', function() { - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + describe('handler tests', function () { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('content-item', 'archive', process.platform); }); - it('should generate a log with coerceLog with the appropriate title', function() { + it('should generate a log with coerceLog with the appropriate title', function () { const logFile = coerceLog('filename.log'); expect(logFile).toEqual(expect.any(FileLog)); @@ -323,7 +329,7 @@ describe('content-item archive command', () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockGet, mockGetList, mockItemsList, mockArchive } = mockValues(); + const { mockGet, mockGetContent, mockArchive } = mockValues(); const argv = { ...yargArgs, @@ -332,16 +338,18 @@ describe('content-item archive command', () => { await handler(argv); expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockArchive).toBeCalledTimes(2); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + status: Status.ACTIVE, + enrichItems: true + }); + expect(mockArchive).toHaveBeenCalledTimes(2); }); it('should archive content by id', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockArchive, mockItemGetById } = mockValues(); + const { mockArchive, mockItemGetById, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -352,14 +360,15 @@ describe('content-item archive command', () => { await handler(argv); expect(mockItemGetById).toHaveBeenCalled(); - expect(mockArchive).toBeCalledTimes(1); + expect(mockGetContent).not.toHaveBeenCalled(); + expect(mockArchive).toHaveBeenCalledTimes(1); }); it("shouldn't archive content by id", async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockArchive, mockItemGetById } = mockValues(true); + const { mockArchive, mockItemGetById, mockGetContent } = mockValues(true); const argv = { ...yargArgs, @@ -369,14 +378,15 @@ describe('content-item archive command', () => { await handler(argv); expect(mockItemGetById).toHaveBeenCalled(); - expect(mockArchive).not.toBeCalled(); + expect(mockGetContent).not.toHaveBeenCalled(); + expect(mockArchive).not.toHaveBeenCalled(); }); it('should archive content by repo id', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockArchive, mockRepoGet } = mockValues(); + const { mockGet, mockArchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -385,15 +395,20 @@ describe('content-item archive command', () => { }; await handler(argv); - expect(mockRepoGet).toBeCalledTimes(1); - expect(mockArchive).toBeCalledTimes(2); + expect(mockGet).toHaveBeenCalled(); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + status: Status.ACTIVE, + repoId: 'repo1', + enrichItems: true + }); + expect(mockArchive).toHaveBeenCalledTimes(2); }); it('should archive content by repo ids', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockArchive, mockRepoGet } = mockValues(); + const { mockGet, mockArchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -402,15 +417,20 @@ describe('content-item archive command', () => { }; await handler(argv); - expect(mockRepoGet).toBeCalledTimes(2); - expect(mockArchive).toBeCalledTimes(4); + expect(mockGet).toHaveBeenCalled(); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + status: Status.ACTIVE, + repoId: ['repo1', 'repo2'], + enrichItems: true + }); + expect(mockArchive).toHaveBeenCalledTimes(2); }); it('should archive content by folder id', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockArchive, mockFolderGet, mockItemsList } = mockValues(); + const { mockGet, mockArchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -420,16 +440,21 @@ describe('content-item archive command', () => { }; await handler(argv); - expect(mockFolderGet).toBeCalledTimes(1); - expect(mockItemsList).toBeCalledTimes(1); - expect(mockArchive).toBeCalledTimes(2); + expect(mockGet).toHaveBeenCalled(); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + status: Status.ACTIVE, + folderId: 'folder1', + repoId: 'repo123', + enrichItems: true + }); + expect(mockArchive).toHaveBeenCalledTimes(2); }); it('should archive content by folder ids', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockArchive, mockFolderGet, mockItemsList } = mockValues(); + const { mockGet, mockArchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -438,16 +463,20 @@ describe('content-item archive command', () => { }; await handler(argv); - expect(mockFolderGet).toBeCalledTimes(2); - expect(mockItemsList).toBeCalledTimes(2); - expect(mockArchive).toBeCalledTimes(4); + expect(mockGet).toHaveBeenCalled(); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + status: Status.ACTIVE, + folderId: ['folder1', 'folder1'], + enrichItems: true + }); + expect(mockArchive).toHaveBeenCalledTimes(2); }); it('should archive content by name', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockArchive, mockFolderGet, mockItemsList } = mockValues(); + const { mockGet, mockArchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -457,16 +486,20 @@ describe('content-item archive command', () => { }; await handler(argv); - expect(mockFolderGet).toBeCalledTimes(1); - expect(mockItemsList).toBeCalledTimes(1); - expect(mockArchive).toBeCalledTimes(1); + expect(mockGet).toHaveBeenCalled(); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), 'name:item1', { + folderId: 'folder1', + status: Status.ACTIVE, + enrichItems: true + }); + expect(mockArchive).toHaveBeenCalledTimes(2); }); it('should exit if a facet AND id are provided', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockArchive, mockFolderGet, mockItemsList } = mockValues(); + const { mockArchive, mockFolderGet, mockItemsList, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -476,16 +509,20 @@ describe('content-item archive command', () => { }; await handler(argv); - expect(mockFolderGet).not.toBeCalled(); - expect(mockItemsList).not.toBeCalled(); - expect(mockArchive).not.toBeCalled(); + expect(mockGetContent).not.toHaveBeenCalled(); + expect(mockFolderGet).not.toHaveBeenCalled(); + expect(mockItemsList).not.toHaveBeenCalled(); + expect(mockArchive).not.toHaveBeenCalled(); }); - it("shouldn't archive content by name", async () => { + it("shouldn't unarchive content when facet returns none", async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockArchive, mockFolderGet, mockItemsList } = mockValues(); + const { mockGet, mockArchive, mockGetContent } = mockValues(); + + (mockGetContent as jest.Mock).mockReset(); + (mockGetContent as jest.Mock).mockResolvedValue([]); const argv = { ...yargArgs, @@ -495,16 +532,20 @@ describe('content-item archive command', () => { }; await handler(argv); - expect(mockFolderGet).toBeCalledTimes(1); - expect(mockItemsList).toBeCalledTimes(1); - expect(mockArchive).not.toBeCalled(); + expect(mockGet).toHaveBeenCalled(); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), 'name:item3', { + folderId: 'folder1', + status: Status.ACTIVE, + enrichItems: true + }); + expect(mockArchive).not.toHaveBeenCalled(); }); it("shouldn't archive content, answer no", async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['n']); - const { mockArchive, mockFolderGet, mockItemsList } = mockValues(); + const { mockGet, mockArchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -514,35 +555,20 @@ describe('content-item archive command', () => { }; await handler(argv); - expect(mockFolderGet).toBeCalledTimes(1); - expect(mockItemsList).toBeCalledTimes(1); - expect(mockArchive).not.toBeCalled(); - }); - - it('should archive content by name regexp', async () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (readline as any).setResponses(['y']); - - const { mockGet, mockGetList, mockArchive, mockItemsList } = mockValues(); - - const argv = { - ...yargArgs, - ...config, - name: '/item/' - }; - await handler(argv); - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockArchive).toBeCalledTimes(2); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), 'name:item1', { + folderId: 'folder1', + status: Status.ACTIVE, + enrichItems: true + }); + expect(mockArchive).not.toHaveBeenCalled(); }); it('should archive content by content type name', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockGet, mockGetList, mockArchive, mockItemsList } = mockValues(); + const { mockGet, mockArchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -552,54 +578,18 @@ describe('content-item archive command', () => { await handler(argv); expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockArchive).toBeCalledTimes(1); - }); - - it('should archive content by content type regexp', async () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (readline as any).setResponses(['y']); - - const { mockGet, mockGetList, mockArchive, mockItemsList } = mockValues(); - - const argv = { - ...yargArgs, - ...config, - facet: 'schema:/test/' - }; - await handler(argv); - - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockArchive).toBeCalledTimes(2); - }); - - it("shouldn't archive content by content type regexp", async () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (readline as any).setResponses(['y']); - - const { mockGet, mockGetList, mockArchive, mockItemsList } = mockValues(); - - const argv = { - ...yargArgs, - ...config, - facet: 'schema:/test123/' - }; - await handler(argv); - - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockArchive).toBeCalledTimes(0); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), 'schema:http://test.com', { + status: Status.ACTIVE, + enrichItems: true + }); + expect(mockArchive).toHaveBeenCalledTimes(2); }); it('should archive content with ignoreError', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockGet, mockGetList, mockArchive, mockItemsList } = mockValues(true); + const { mockGet, mockArchive, mockGetContent } = mockValues(true); const argv = { ...yargArgs, @@ -609,16 +599,18 @@ describe('content-item archive command', () => { await handler(argv); expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockArchive).toBeCalledTimes(2); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + status: Status.ACTIVE, + enrichItems: true + }); + expect(mockArchive).toHaveBeenCalledTimes(2); }); it("shouldn't archive content with ignoreError", async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockGet, mockGetList, mockArchive, mockItemsList } = mockValues(true); + const { mockGet, mockArchive, mockGetContent } = mockValues(true); const argv = { ...yargArgs, @@ -628,16 +620,18 @@ describe('content-item archive command', () => { await handler(argv); expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockArchive).toBeCalledTimes(1); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + status: Status.ACTIVE, + enrichItems: true + }); + expect(mockArchive).toHaveBeenCalledTimes(1); }); it('should archive content items without asking if --force is provided', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['input', 'ignored']); - const { mockGet, mockGetList, mockArchive, mockItemsList } = mockValues(); + const { mockGet, mockArchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -647,9 +641,11 @@ describe('content-item archive command', () => { await handler(argv); expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockArchive).toBeCalledTimes(2); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + status: Status.ACTIVE, + enrichItems: true + }); + expect(mockArchive).toHaveBeenCalledTimes(2); }); it('should archive content items specified in the provided --revertLog', async () => { @@ -657,15 +653,20 @@ describe('content-item archive command', () => { (readline as any).setResponses(['y']); const logFileName = `temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`; - const log = '// Type log test file\n' + 'UNARCHIVE 1\n' + 'UNARCHIVE 2\n' + 'UNARCHIVE idMissing'; + const log = '// Type log test file\n' + 'UNARCHIVE 1\n' + 'UNARCHIVE 2\n' + 'UNARCHIVE idMissing\n'; const dir = dirname(logFileName); - if (!(await promisify(exists)(dir))) { + if (!existsSync(dir)) { await promisify(mkdir)(dir); } await promisify(writeFile)(logFileName, log); - const { mockGet, mockGetList, mockArchive, mockItemsList } = mockValues(); + const { mockArchive, mockItemGetById, contentItems } = mockValues(); + + (mockItemGetById as jest.Mock).mockReset(); + (mockItemGetById as jest.Mock).mockResolvedValueOnce(contentItems[0]); + (mockItemGetById as jest.Mock).mockResolvedValueOnce(contentItems[1]); + (mockItemGetById as jest.Mock).mockRejectedValue(new Error("Couldn't locate item")); const argv = { ...yargArgs, @@ -676,35 +677,42 @@ describe('content-item archive command', () => { }; await handler(argv); - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockArchive).toBeCalledTimes(2); + expect(mockItemGetById).toHaveBeenNthCalledWith(1, '1'); + expect(mockItemGetById).toHaveBeenNthCalledWith(2, '2'); + expect(mockItemGetById).toHaveBeenNthCalledWith(3, 'idMissing'); + expect(mockArchive).toHaveBeenCalledTimes(2); }); - it("shouldn't archive content items, getFolder error", async () => { + it('should not archive content items when getContent throws an error', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['input', 'ignored']); - const { mockFolderGet, mockArchive, mockItemsList } = mockValues(true); + const { mockArchive, mockGetContent } = mockValues(true); + + (mockGetContent as jest.Mock).mockReset(); + (mockGetContent as jest.Mock).mockRejectedValue(new Error('Simulated error')); const argv = { ...yargArgs, ...config, folderId: 'folder1' }; - await handler(argv); - expect(mockFolderGet).toBeCalledTimes(1); - expect(mockItemsList).not.toBeCalled(); - expect(mockArchive).not.toBeCalled(); + await expect(handler(argv)).rejects.toThrowErrorMatchingInlineSnapshot(`"Simulated error"`); + + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + folderId: 'folder1', + status: Status.ACTIVE, + enrichItems: true + }); + expect(mockArchive).not.toHaveBeenCalled(); }); - it("shouldn't archive content items, revertLog error", async () => { + it('should not archive content items when revertLog does not exist', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - if (await promisify(exists)(`temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`)) { + if (existsSync(`temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`)) { await promisify(unlink)(`temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`); } @@ -712,12 +720,12 @@ describe('content-item archive command', () => { const log = '// Type log test file\n' + 'UNARCHIVE 1\n' + 'UNARCHIVE 2\n' + 'UNARCHIVE idMissing'; const dir = dirname(logFileName); - if (!(await promisify(exists)(dir))) { + if (!existsSync(dir)) { await promisify(mkdir)(dir); } await promisify(writeFile)(logFileName, log); - const { mockGet, mockGetList, mockArchive, mockItemsList } = mockValues(true); + const { mockArchive, mockItemGetById, mockGetContent } = mockValues(true); const argv = { ...yargArgs, @@ -726,19 +734,21 @@ describe('content-item archive command', () => { force: true, revertLog: 'wrongFileName.log' }; - await handler(argv); - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockArchive).not.toBeCalled(); + await expect(handler(argv)).rejects.toThrowErrorMatchingInlineSnapshot( + `"ENOENT: no such file or directory, open 'wrongFileName.log'"` + ); + + expect(mockItemGetById).not.toHaveBeenCalled(); + expect(mockGetContent).not.toHaveBeenCalled(); + expect(mockArchive).not.toHaveBeenCalled(); }); it('should archive content items, write log file', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - if (await promisify(exists)(`temp_${process.env.JEST_WORKER_ID}/content-item-archive.log`)) { + if (existsSync(`temp_${process.env.JEST_WORKER_ID}/content-item-archive.log`)) { await promisify(unlink)(`temp_${process.env.JEST_WORKER_ID}/content-item-archive.log`); } @@ -756,9 +766,9 @@ describe('content-item archive command', () => { await handler(argv); expect(mockItemGetById).toHaveBeenCalled(); - expect(mockArchive).toBeCalled(); + expect(mockArchive).toHaveBeenCalled(); - const logExists = await promisify(exists)(`temp_${process.env.JEST_WORKER_ID}/content-item-archive.log`); + const logExists = existsSync(`temp_${process.env.JEST_WORKER_ID}/content-item-archive.log`); expect(logExists).toBeTruthy(); @@ -782,162 +792,85 @@ describe('content-item archive command', () => { await promisify(unlink)(`temp_${process.env.JEST_WORKER_ID}/content-item-archive.log`); }); - }); - - describe('getContentItems tests', () => { - it('should get content items by id', async () => { - const result = await getContentItems({ - client: dynamicContentClientFactory({ - ...config, - ...yargArgs - }), - id: '1', - hubId: 'hub1' - }); - - if (result) { - expect(result.contentItems.length).toBeGreaterThanOrEqual(1); - - expect(result.contentItems[0].id).toMatch('1'); - } - }); - it('should get content items all', async () => { - const result = await getContentItems({ - client: dynamicContentClientFactory({ - ...config, - ...yargArgs - }), - hubId: 'hub1' - }); - - if (result) { - expect(result.contentItems.length).toBe(2); - } - }); - - it('should get content items by repo', async () => { - const result = await getContentItems({ - client: dynamicContentClientFactory({ - ...config, - ...yargArgs - }), - hubId: 'hub1', - repoId: 'repo1' - }); - - if (result) { - expect(result.contentItems.length).toBe(2); - } - }); - - it('should get content items by folder', async () => { - const result = await getContentItems({ - client: dynamicContentClientFactory({ - ...config, - ...yargArgs - }), - hubId: 'hub1', - folderId: 'folder1' - }); - - if (result) { - expect(result.contentItems.length).toBe(2); - } - }); - }); - - describe('filterContentItems tests', () => { - it('should filter content items', async () => { - const { contentItems } = mockValues(); - - const result = await filterContentItems({ - contentItems - }); - - expect(result).toMatchObject({ - contentItems, - missingContent: false - }); - }); - - it('should filter content items by content type', async () => { - const { contentItems } = mockValues(); - - const result = await filterContentItems({ - contentItems, - facet: 'schema:/test\\.com/' - }); - - expect(result).toMatchObject({ - contentItems: [contentItems[0]], - missingContent: false - }); - }); + it('should update content item with no additional params when delivery key is set', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['y']); - it('should filter content items by content types', async () => { - const { contentItems } = mockValues(); + const { mockItemUpdate, contentItems } = mockValues(); - const result = await filterContentItems({ - contentItems, - facet: 'schema:/test.?\\.com/' - }); + contentItems[0].body._meta.deliveryKey = 'delivery-key'; + const argv = { + ...yargArgs, + ...config + }; + await handler(argv); - expect(result).toMatchObject({ - contentItems, - missingContent: false - }); + expect(mockItemUpdate).toHaveBeenCalledTimes(1); + // check we're not sending any update params + expect((mockItemUpdate as jest.Mock).mock.calls[0][1]).toEqual({}); }); - it('should filter content items by name', async () => { - const { contentItems } = mockValues(); + it('should update content item with no additional params when delivery keys is set', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['y']); - const result = await filterContentItems({ - contentItems, - facet: 'name:/item1/' - }); + const { mockItemUpdate, contentItems } = mockValues(); - if (result) { - expect(result.contentItems.length).toBeGreaterThanOrEqual(1); + contentItems[0].body._meta.deliveryKeys = { values: [{ value: 'delivery-key' }] }; + const argv = { + ...yargArgs, + ...config + }; + await handler(argv); - expect(result.contentItems[0].id).toMatch('1'); - } + expect(mockItemUpdate).toHaveBeenCalledTimes(1); + // check we're not sending any update params + expect((mockItemUpdate as jest.Mock).mock.calls[0][1]).toEqual({}); }); - }); - - describe('processItems tests', () => { - it('should archive content items', async () => { - const { contentItems, mockArchive } = mockValues(); + it('should update content item with ignoreSchemaValidation param', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - await processItems({ - contentItems, - allContent: true, - missingContent: false, - logFile: createLog('./logFile.log') - }); + const { mockItemUpdate, contentItems } = mockValues(); - expect(mockArchive).toBeCalledTimes(2); + contentItems[0].body._meta.deliveryKey = 'delivery-key'; + const argv = { + ...yargArgs, + ...config, + ignoreSchemaValidation: true + }; + await handler(argv); - if (await promisify(exists)('./logFile.log')) { - await promisify(unlink)('./logFile.log'); - } + expect(mockItemUpdate).toHaveBeenCalledTimes(1); + expect((mockItemUpdate as jest.Mock).mock.calls[0][1].ignoreSchemaValidation).toBe(true); }); it('should not archive content items', async () => { - jest.spyOn(global.console, 'log'); - - await processItems({ - contentItems: [], - allContent: true, - missingContent: false, - logFile: new FileLog() + const { mockGet, mockItemGetById, mockArchive } = mockValues(); + const logFile = new FileLog(); + const mockAppendFile = jest.fn(); + logFile.open = jest.fn().mockImplementation(() => { + return { + appendLine: mockAppendFile + }; }); + const argv = { + ...yargArgs, + ...config, + id: 'repo123', + logFile + }; - expect(console.log).toBeCalled(); - expect(console.log).toHaveBeenLastCalledWith('Nothing found to archive, aborting.'); + (mockItemGetById as jest.Mock).mockResolvedValue([]); + + await handler(argv); + + expect(mockGet).toHaveBeenCalled(); + expect(mockArchive).not.toHaveBeenCalled(); + expect(mockAppendFile).toHaveBeenCalled(); + expect(mockAppendFile).toHaveBeenLastCalledWith('Nothing found to archive, aborting'); }); }); }); diff --git a/src/commands/content-item/archive.ts b/src/commands/content-item/archive.ts index 23365054..891c5aa9 100644 --- a/src/commands/content-item/archive.ts +++ b/src/commands/content-item/archive.ts @@ -2,13 +2,15 @@ import { Arguments, Argv } from 'yargs'; import { ConfigurationParameters } from '../configure'; import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; import { ArchiveLog } from '../../common/archive/archive-log'; -import paginator from '../../common/dc-management-sdk-js/paginator'; -import { confirmArchive } from '../../common/archive/archive-helpers'; +import { confirmAllContent } from '../../common/content-item/confirm-all-content'; import ArchiveOptions from '../../common/archive/archive-options'; -import { ContentItem, DynamicContent, Status } from 'dc-management-sdk-js'; +import { ContentItem, Status } from 'dc-management-sdk-js'; import { getDefaultLogPath, createLog } from '../../common/log-helpers'; import { FileLog } from '../../common/file-log'; -import { applyFacet, withOldFilters } from '../../common/filter/facet'; +import { withOldFilters } from '../../common/filter/facet'; +import { getContent } from '../../common/filter/fetch-content'; +import { progressBar } from '../../common/progress-bar/progress-bar'; +import { getContentByIds } from '../../common/content-item/get-content-items-by-ids'; export const command = 'archive [id]'; @@ -77,247 +79,136 @@ export const builder = (yargs: Argv): void => { .option('schemaId', { type: 'string', hidden: true + }) + .option('ignoreSchemaValidation', { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during archive' }); }; -export const filterContentItems = async ({ - revertLog, - facet, - contentItems -}: { - revertLog?: string; - facet?: string; - contentItems: ContentItem[]; -}): Promise<{ contentItems: ContentItem[]; missingContent: boolean } | undefined> => { - try { - let missingContent = false; - - if (revertLog != null) { - const log = await new ArchiveLog().loadFromFile(revertLog); - const ids = log.getData('UNARCHIVE'); - const contentItemsFiltered = contentItems.filter(contentItem => ids.indexOf(contentItem.id || '') != -1); - - missingContent = contentItems.length !== ids.length; - - return { - contentItems: contentItemsFiltered, - missingContent - }; - } - - if (facet != null) { - const contentItemsFiltered = applyFacet(contentItems, facet); - - return { - contentItems: contentItemsFiltered, - missingContent - }; - } - - return { - contentItems, - missingContent - }; - } catch (err) { - console.log(err); - return { - contentItems: [], - missingContent: false - }; - } -}; - -export const getContentItems = async ({ - client, - id, - hubId, - repoId, - folderId, - revertLog, - facet -}: { - client: DynamicContent; - id?: string | string[]; - hubId: string; - repoId?: string | string[]; - folderId?: string | string[]; - revertLog?: string; - facet?: string; -}): Promise<{ contentItems: ContentItem[]; missingContent: boolean }> => { - try { - const contentItems: ContentItem[] = []; - - if (id != null) { - const itemIds = Array.isArray(id) ? id : [id]; - const items = await Promise.all(itemIds.map(id => client.contentItems.get(id))); - contentItems.push(...items); - - return { - contentItems, - missingContent: false - }; - } - - const hub = await client.hubs.get(hubId); - const repoIds = typeof repoId === 'string' ? [repoId] : repoId || []; - const folderIds = typeof folderId === 'string' ? [folderId] : folderId || []; - const contentRepositories = await (repoId != null - ? Promise.all(repoIds.map(id => client.contentRepositories.get(id))) - : paginator(hub.related.contentRepositories.list)); - - const folders = folderId != null ? await Promise.all(folderIds.map(id => client.folders.get(id))) : []; - - folderId != null - ? await Promise.all( - folders.map(async source => { - const items = await paginator(source.related.contentItems.list); - - contentItems.push(...items.filter(item => item.status == 'ACTIVE')); - }) - ) - : await Promise.all( - contentRepositories.map(async source => { - const items = await paginator(source.related.contentItems.list, { status: Status.ACTIVE }); - contentItems.push(...items); - }) - ); - - return ( - (await filterContentItems({ - revertLog, - facet, - contentItems - })) || { - contentItems: [], - missingContent: false - } - ); - } catch (err) { - console.log(err); - - return { - contentItems: [], - missingContent: false - }; - } -}; - -export const processItems = async ({ +const processItems = async ({ contentItems, - force, - silent, - logFile, - allContent, - missingContent, - ignoreError + log, + ignoreError, + ignoreSchemaValidation }: { contentItems: ContentItem[]; - force?: boolean; - silent?: boolean; - logFile: FileLog; - allContent: boolean; - missingContent: boolean; + log: FileLog; ignoreError?: boolean; -}): Promise => { - if (contentItems.length == 0) { - console.log('Nothing found to archive, aborting.'); - return; - } - - console.log('The following content items will be archived:'); - contentItems.forEach((contentItem: ContentItem) => { - console.log(` ${contentItem.label} (${contentItem.id})`); - }); - console.log(`Total: ${contentItems.length}`); - - if (!force) { - const yes = await confirmArchive('archive', 'content item', allContent, missingContent); - if (!yes) { - return; - } - } - - const log = logFile.open(); - - let successCount = 0; + ignoreSchemaValidation?: boolean; +}): Promise<{ failedArchives: ContentItem[] }> => { + const progress = progressBar(contentItems.length, 0, { title: 'Archiving content items' }); + const failedArchives = []; for (let i = 0; i < contentItems.length; i++) { try { const deliveryKey = contentItems[i].body._meta.deliveryKey; + const deliveryKeys = (contentItems[i].body._meta.deliveryKeys?.values || []).map( + (key: { value: string }) => key.value + ); let args = contentItems[i].id; - if (deliveryKey) { + if (deliveryKey || deliveryKeys.length) { contentItems[i].body._meta.deliveryKey = null; + contentItems[i].body._meta.deliveryKeys = null; + const updateParams = { ...(ignoreSchemaValidation ? { ignoreSchemaValidation: true } : {}) }; + contentItems[i] = await contentItems[i].related.update(contentItems[i], updateParams); - contentItems[i] = await contentItems[i].related.update(contentItems[i]); - - args += ` ${deliveryKey}`; + args += ` ${deliveryKey || ''} ${deliveryKeys.join(',')}`; } await contentItems[i].related.archive(); - + progress.increment(); log.addAction('ARCHIVE', `${args}`); - successCount++; } catch (e) { + failedArchives.push(contentItems[i]); + progress.increment(); log.addComment(`ARCHIVE FAILED: ${contentItems[i].id}`); log.addComment(e.toString()); if (ignoreError) { - log.warn(`Failed to archive ${contentItems[i].label} (${contentItems[i].id}), continuing.`, e); + log.warn(`\nFailed to archive ${contentItems[i].label} (${contentItems[i].id}), continuing.`, e); } else { - log.error(`Failed to archive ${contentItems[i].label} (${contentItems[i].id}), aborting.`, e); + progress.stop(); + log.error(`\nFailed to archive ${contentItems[i].label} (${contentItems[i].id}), aborting.`, e); break; } } } - await log.close(!silent); + progress.stop(); - console.log(`Archived ${successCount} content items.`); + return { failedArchives }; }; export const handler = async (argv: Arguments): Promise => { - const { id, logFile, force, silent, ignoreError, hubId, revertLog, repoId, folderId } = argv; + const { id, logFile, force, silent, ignoreError, hubId, revertLog, repoId, folderId, ignoreSchemaValidation } = argv; + const log = logFile.open(); const client = dynamicContentClientFactory(argv); - const facet = withOldFilters(argv.facet, argv); - const allContent = !id && !facet && !revertLog && !folderId && !repoId; if (repoId && id) { - console.log('ID of content item is specified, ignoring repository ID'); + log.appendLine('ID of content item is specified, ignoring repository ID'); } if (id && facet) { - console.log('Please specify either a facet or an ID - not both.'); + log.appendLine('Please specify either a facet or an ID - not both.'); return; } if (repoId && folderId) { - console.log('Folder is specified, ignoring repository ID'); + log.appendLine('Folder is specified, ignoring repository ID'); } if (allContent) { - console.log('No filter was given, archiving all content'); + log.appendLine('No filter was given, archiving all content'); } - const { contentItems, missingContent } = await getContentItems({ - client, - id, - hubId, - repoId, - folderId, - revertLog, - facet - }); + let ids: string[] = []; + + if (id) { + ids = Array.isArray(id) ? id : [id]; + } - await processItems({ + if (revertLog) { + const log = await new ArchiveLog().loadFromFile(revertLog); + ids = log.getData('UNARCHIVE'); + } + + const hub = await client.hubs.get(hubId); + const contentItems = ids.length + ? (await getContentByIds(client, ids)).filter(item => item.status === Status.ACTIVE) + : await getContent(client, hub, facet, { repoId, folderId, status: Status.ACTIVE, enrichItems: true }); + + if (!contentItems.length) { + log.appendLine('Nothing found to archive, aborting'); + return; + } + + const missingContentItems = ids.length > 0 ? Boolean(ids.length !== contentItems.length) : false; + log.appendLine(`Found ${contentItems.length} content items to archive`); + + if (!force) { + const yes = await confirmAllContent('archive', 'content item', allContent, missingContentItems); + if (!yes) { + return; + } + } + + const { failedArchives } = await processItems({ contentItems, - force, - silent, - logFile, - allContent, - missingContent, - ignoreError + log, + ignoreError, + ignoreSchemaValidation }); + + const failedArchiveMsg = failedArchives.length + ? `with ${failedArchives.length} failed archives - check logs for details` + : ``; + + log.appendLine(`Archived content items ${failedArchiveMsg}`); + + await log.close(!silent); }; // log format: diff --git a/src/commands/content-item/copy.spec.ts b/src/commands/content-item/copy.spec.ts index d61c05d9..2ce3dc25 100644 --- a/src/commands/content-item/copy.spec.ts +++ b/src/commands/content-item/copy.spec.ts @@ -37,12 +37,12 @@ describe('content-item copy command', () => { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('copy'); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); @@ -174,10 +174,16 @@ describe('content-item copy command', () => { type: 'string', hidden: true }); + + expect(spyOption).toHaveBeenCalledWith('ignoreSchemaValidation', { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during copy' + }); }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -213,7 +219,7 @@ describe('content-item copy command', () => { clearArray(revertCalls); }); - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('item', 'copy', process.platform); @@ -229,34 +235,25 @@ describe('content-item copy command', () => { const argv = { ...yargArgs, ...config, - srcRepo: 'repo1-id', - dstRepo: 'repo2-id', - dstHubId: 'hub2-id', dstClientId: 'acc2-id', dstSecret: 'acc2-secret', - facet: 'name:/./,schema:/./', - mapFile: 'map.json', force: false, validate: false, skipIncomplete: false, - lastPublish: true, publish: true, republish: true, - excludeKeys: true, media: true }; await handler(argv); expect(exportCalls.length).toEqual(1); - expect(importCalls.length).toEqual(1); - expect(exportCalls[0].clientId).toEqual(config.clientId); expect(exportCalls[0].clientSecret).toEqual(config.clientSecret); expect(exportCalls[0].hubId).toEqual(config.hubId); @@ -264,21 +261,79 @@ describe('content-item copy command', () => { expect(exportCalls[0].repoId).toEqual(argv.srcRepo); expect(exportCalls[0].publish).toEqual(argv.lastPublish); + expect(importCalls.length).toEqual(1); expect(importCalls[0].clientId).toEqual(argv.dstClientId); expect(importCalls[0].clientSecret).toEqual(argv.dstSecret); expect(importCalls[0].hubId).toEqual(argv.dstHubId); expect(importCalls[0].baseRepo).toEqual(argv.dstRepo); - expect(importCalls[0].mapFile).toEqual(argv.mapFile); expect(importCalls[0].force).toEqual(argv.force); expect(importCalls[0].validate).toEqual(argv.validate); expect(importCalls[0].skipIncomplete).toEqual(argv.skipIncomplete); - expect(importCalls[0].publish).toEqual(argv.publish); expect(importCalls[0].republish).toEqual(argv.republish); - expect(importCalls[0].excludeKeys).toEqual(argv.excludeKeys); expect(importCalls[0].media).toEqual(argv.media); + expect(importCalls[0].ignoreSchemaValidation).toBeUndefined(); + }); + + it('should call import with parameters to ignore content item schema validation', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const exportCalls: Arguments[] = (exporter as any).calls; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const importCalls: Arguments[] = (importer as any).calls; + + // TODO: mock handlers for export and import + const argv = { + ...yargArgs, + ...config, + srcRepo: 'repo1-id', + dstRepo: 'repo2-id', + dstHubId: 'hub2-id', + dstClientId: 'acc2-id', + dstSecret: 'acc2-secret', + facet: 'name:/./,schema:/./', + mapFile: 'map.json', + force: false, + validate: false, + skipIncomplete: false, + lastPublish: true, + publish: true, + republish: true, + excludeKeys: true, + media: true, + ignoreSchemaValidation: true + }; + await handler(argv); + + expect(exportCalls.length).toEqual(1); + expect(importCalls.length).toEqual(1); + expect(importCalls[0].ignoreSchemaValidation).toBe(true); + }); + + it('should forward to import-revert with parameters to ignore content item schema validation when revertLog is present.', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const exportCalls: Arguments[] = (exporter as any).calls; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const importCalls: Arguments[] = (importer as any).calls; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const revertCalls: Arguments[] = (reverter as any).calls; + + const argv = { + ...yargArgs, + ...config, + dstHubId: 'hub2-id', + dstClientId: 'acc2-id', + dstSecret: 'acc2-secret', + revertLog: Promise.resolve(new FileLog()), + ignoreSchemaValidation: true + }; + await handler(argv); + + expect(exportCalls.length).toEqual(0); + expect(importCalls.length).toEqual(0); + expect(revertCalls.length).toEqual(1); + expect(revertCalls[0].ignoreSchemaValidation).toBe(true); }); it('should forward to import-revert when revertLog is present.', async () => { diff --git a/src/commands/content-item/copy.ts b/src/commands/content-item/copy.ts index 06cba355..c62b1e04 100644 --- a/src/commands/content-item/copy.ts +++ b/src/commands/content-item/copy.ts @@ -152,6 +152,12 @@ export const builder = (yargs: Argv): void => { .option('schemaId', { type: 'string', hidden: true + }) + + .option('ignoreSchemaValidation', { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during copy' }); }; @@ -173,11 +179,12 @@ export const handler = async (argv: Arguments { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('export '); }); - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('item', 'export', process.platform); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); @@ -113,7 +113,7 @@ describe('content-item export command', () => { } } - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -361,36 +361,78 @@ describe('content-item export command', () => { const exists: ItemTemplate[] = [ // repo correct, label and type correct - { label: 'item-nameMatch2', repoId: 'repo1', typeSchemaUri: 'http://typeMatch3', folderPath: 'folder1' }, - { label: 'item-nameMatch3', repoId: 'repo1', typeSchemaUri: 'http://typeMatch5', folderPath: 'folder1/nested' }, + { + label: 'item-nameMatch2', + repoId: 'repo1', + typeSchemaUri: 'http://typeMatch3', + folderPath: 'folder1', + id: '0' + }, + { + label: 'item-nameMatch3', + repoId: 'repo1', + typeSchemaUri: 'http://typeMatch5', + folderPath: 'folder1/nested', + id: '1' + }, - { label: 'item-nameMatch7', repoId: 'repo2', typeSchemaUri: 'http://typeMatch7', folderPath: 'folder4' }, - { label: 'item-nameMatch8', repoId: 'repo2', typeSchemaUri: 'http://typeMatch6', folderPath: 'folder4/nested' } + { + label: 'item-nameMatch7', + repoId: 'repo2', + typeSchemaUri: 'http://typeMatch7', + folderPath: 'folder4', + id: '2' + }, + { + label: 'item-nameMatch8', + repoId: 'repo2', + typeSchemaUri: 'http://typeMatch6', + folderPath: 'folder4/nested', + id: '3' + } ]; const skips: ItemTemplate[] = [ // repo correct, type filtered out - { label: 'item-nameMatch5', repoId: 'repo2', typeSchemaUri: 'http://type3', folderPath: 'folder3' }, + { label: 'item-nameMatch5', repoId: 'repo2', typeSchemaUri: 'http://type3', folderPath: 'folder3', id: '4' }, // repo correct, name filtered out - { label: 'item-name7', repoId: 'repo2', typeSchemaUri: 'http://typeMatch3', folderPath: 'folder3' }, - { label: 'item-name8', repoId: 'repo2', typeSchemaUri: 'http://typeMatch5', folderPath: 'folder3/nested' }, + { label: 'item-name7', repoId: 'repo2', typeSchemaUri: 'http://typeMatch3', folderPath: 'folder3', id: '5' }, + { + label: 'item-name8', + repoId: 'repo2', + typeSchemaUri: 'http://typeMatch5', + folderPath: 'folder3/nested', + id: '6' + }, // folder correct, type filtered out - { label: 'item-nameMatch6', repoId: 'repo1', typeSchemaUri: 'http://type3', folderPath: 'folder1' }, + { label: 'item-nameMatch6', repoId: 'repo1', typeSchemaUri: 'http://type3', folderPath: 'folder1', id: '7' }, // folder correct, name filtered out - { label: 'item-name7', repoId: 'repo1', typeSchemaUri: 'http://typeMatch3', folderPath: 'folder1' }, - { label: 'item-name8', repoId: 'repo1', typeSchemaUri: 'http://typeMatch5', folderPath: 'folder1/nested' }, + { label: 'item-name7', repoId: 'repo1', typeSchemaUri: 'http://typeMatch3', folderPath: 'folder1', id: '8' }, + { + label: 'item-name8', + repoId: 'repo1', + typeSchemaUri: 'http://typeMatch5', + folderPath: 'folder1/nested', + id: '9' + }, // type and name correct/incorrect, repo and folder incorrect - { label: 'item1', repoId: 'repo1', typeSchemaUri: 'http://type2' }, - { label: 'item-nameMatch1', repoId: 'repo1', typeSchemaUri: 'http://typeMatch2' }, - { label: 'item4', repoId: 'repo1', typeSchemaUri: 'http://type4', folderPath: 'folder2' }, - { label: 'item-nameMatch4', repoId: 'repo1', typeSchemaUri: 'http://typeMatch4', folderPath: 'folder2' }, + { label: 'item1', repoId: 'repo1', typeSchemaUri: 'http://type2', id: '10' }, + { label: 'item-nameMatch1', repoId: 'repo1', typeSchemaUri: 'http://typeMatch2', id: '11' }, + { label: 'item4', repoId: 'repo1', typeSchemaUri: 'http://type4', folderPath: 'folder2', id: '12' }, + { + label: 'item-nameMatch4', + repoId: 'repo1', + typeSchemaUri: 'http://typeMatch4', + folderPath: 'folder2', + id: '13' + }, // folder correct, both filtered out - { label: 'item5', repoId: 'repo1', typeSchemaUri: 'http://type1', folderPath: 'folder1' } + { label: 'item5', repoId: 'repo1', typeSchemaUri: 'http://type1', folderPath: 'folder1', id: '14' } ]; const templates = skips.concat(exists); diff --git a/src/commands/content-item/export.ts b/src/commands/content-item/export.ts index 83f65899..57a939d5 100644 --- a/src/commands/content-item/export.ts +++ b/src/commands/content-item/export.ts @@ -16,6 +16,7 @@ import { ContentMapping } from '../../common/content-mapping'; import { createLog, getDefaultLogPath } from '../../common/log-helpers'; import { AmplienceSchemaValidator, defaultSchemaLookup } from '../../common/content-item/amplience-schema-validator'; import { applyFacet, withOldFilters } from '../../common/filter/facet'; +import { fetchContent } from '../../common/filter/fetch-content'; interface PublishedContentItem { lastPublishedVersion?: number; @@ -109,6 +110,7 @@ const getContentItems = async ( log: FileLog, repoId?: string | string[], folderId?: string | string[], + facet?: string, publish?: boolean ): Promise<{ path: string; item: ContentItem }[]> => { const items: { path: string; item: ContentItem }[] = []; @@ -116,6 +118,8 @@ const getContentItems = async ( const folderIds = typeof folderId === 'string' ? [folderId] : folderId || []; const repoItems: ContentItem[] = []; + const repoFolders = new Set(); + const itemsByFolderId = new Map(); const repoIds = typeof repoId === 'string' ? [repoId] : repoId || []; @@ -135,12 +139,29 @@ const getContentItems = async ( folderIds.push(folder.id as string); } folderToPathMap.set(folder.id as string, join(baseDir, `${sanitize(folder.name as string)}/`)); + repoFolders.add(folder.id as string); }); - // Add content items in repo base folder. Cache the other items so we don't have to request them again. + // Add content items from this repo. let newItems: ContentItem[]; try { - const allItems = await paginator(repository.related.contentItems.list, { status: Status.ACTIVE }); + const allItems = await fetchContent(client, hub, facet, { + repoId: repository.id, + status: Status.ACTIVE, + enrichItems: true + }); + + for (const item of allItems) { + if (item.folderId != null) { + let folderItems = itemsByFolderId.get(item.folderId); + if (folderItems == null) { + folderItems = []; + itemsByFolderId.set(item.folderId, folderItems); + } + + folderItems.push(item); + } + } Array.prototype.push.apply(repoItems, allItems); newItems = allItems.filter(item => item.folderId == null); @@ -149,7 +170,10 @@ const getContentItems = async ( continue; } - Array.prototype.push.apply(items, newItems.map(item => ({ item, path: baseDir }))); + Array.prototype.push.apply( + items, + newItems.map(item => ({ item, path: baseDir })) + ); } const parallelism = 10; @@ -163,39 +187,52 @@ const getContentItems = async ( let baseFolder = true; while (processFolders.length > 0) { - const promises = processFolders.map( - async (folder: Folder): Promise => { - if (baseFolder) { - if (!folderToPathMap.has(folder.id as string)) { - folderToPathMap.set(folder.id as string, specifyBasePaths ? `${sanitize(folder.name as string)}/` : ''); - } - } - const path = await getOrAddFolderPath(folderToPathMap, client, folder, log); - log.appendLine(`Processing ${path}...`); - - let newItems: ContentItem[]; - // If we already have seen items in this folder, use those. Otherwise try get them explicitly. - // This may happen for folders in selected repositories if they are empty, but it will be a no-op (and is unavoidable). - newItems = repoItems.filter(item => item.folderId == folder.id); - if (newItems.length == 0) { - log.appendLine(`Fetching additional folder: ${folder.name}`); - try { - newItems = (await paginator(folder.related.contentItems.list)).filter(item => item.status === 'ACTIVE'); - } catch (e) { - log.warn(`Could not get items from folder ${folder.name} (${folder.id})`, e); - return; - } + const promises = processFolders.map(async (folder: Folder): Promise => { + if (baseFolder) { + if (!folderToPathMap.has(folder.id as string)) { + folderToPathMap.set(folder.id as string, specifyBasePaths ? `${sanitize(folder.name as string)}/` : ''); } - Array.prototype.push.apply(items, newItems.map(item => ({ item, path: path }))); - + } + const path = await getOrAddFolderPath(folderToPathMap, client, folder, log); + log.appendLine(`Processing ${path}...`); + + // If we already have seen items in this folder, use those. Otherwise try get them explicitly. + // This may happen for folders in selected repositories if they are empty, but it will be a no-op (and is unavoidable). + const folderItemsObtained = repoFolders.has(folder.id as string); + let newItems: ContentItem[] | undefined; + if (!folderItemsObtained) { + log.appendLine(`Fetching additional folder: ${folder.name}`); try { - const subfolders = await paginator(folder.related.folders.list); - Array.prototype.push.apply(nextFolders, subfolders); + newItems = (await paginator(folder.related.contentItems.list)).filter(item => item.status === 'ACTIVE'); } catch (e) { - log.warn(`Could not get subfolders from folder ${folder.name} (${folder.id})`, e); + log.warn(`Could not get items from folder ${folder.name} (${folder.id})`, e); + return; + } + } else { + newItems = itemsByFolderId.get(folder.id as string); + } + + if (newItems) { + Array.prototype.push.apply( + items, + newItems.map(item => ({ item, path: path })) + ); + } + + try { + const subfolders = await paginator(folder.related.folders.list); + + if (folderItemsObtained) { + for (const subfolder of subfolders) { + repoFolders.add(subfolder.id as string); + } } + + Array.prototype.push.apply(nextFolders, subfolders); + } catch (e) { + log.warn(`Could not get subfolders from folder ${folder.name} (${folder.id})`, e); } - ); + }); await Promise.all(promises); @@ -231,11 +268,14 @@ export const handler = async (argv: Arguments item.item), facet); + const newItems = applyFacet( + items.map(item => item.item), + facet + ); if (newItems.length !== items.length) { items = newItems.map(newItem => items.find(item => item.item === newItem) as { item: ContentItem; path: string }); diff --git a/src/commands/content-item/import-revert.spec.ts b/src/commands/content-item/import-revert.spec.ts index 1cbbdbef..cd4ecd46 100644 --- a/src/commands/content-item/import-revert.spec.ts +++ b/src/commands/content-item/import-revert.spec.ts @@ -21,7 +21,7 @@ function rimraf(dir: string): Promise { }); } -describe('revert tests', function() { +describe('revert tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -130,6 +130,79 @@ describe('revert tests', function() { await rimraf(`temp_${process.env.JEST_WORKER_ID}/revert/createImport.txt`); }); + test('Reverting an import on top of existing content should revert to an older version with no content item update parameters', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses([]); + + await createLog( + `temp_${process.env.JEST_WORKER_ID}/revert/createImport.txt`, + 'UPDATE id1 1 2\nUPDATE id2 3 4\nCREATE id3\nSUCCESS' + ); + + // Create content to import + + const templates: ItemTemplate[] = [ + { id: 'id1', label: 'item1', repoId: 'repo', typeSchemaUri: 'http://type', version: 2 } + ]; + + const mockContent = new MockContent(dynamicContentClientFactory as jest.Mock); + mockContent.createMockRepository('repo'); + mockContent.registerContentType('http://type', 'type', 'repo'); + mockContent.importItemTemplates(templates); + + const argv = { + ...yargArgs, + ...config, + revertLog: openRevertLog(`temp_${process.env.JEST_WORKER_ID}/revert/createImport.txt`), + dir: '.' + }; + await revert(argv); + + expect(mockContent.metrics.itemsUpdated).toEqual(1); + expect(mockContent.metrics.itemsArchived).toEqual(0); + expect(mockContent.items[0].related.update).toHaveBeenCalledTimes(1); + expect((mockContent.items[0].related.update as jest.Mock).mock.calls[0][1]).toEqual({}); + + await rimraf(`temp_${process.env.JEST_WORKER_ID}/revert/createImport.txt`); + }); + + test('Reverting an import on top of existing content should revert to an older version with ignore schema validation content item update parameter', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses([]); + + await createLog( + `temp_${process.env.JEST_WORKER_ID}/revert/createImport.txt`, + 'UPDATE id1 1 2\nUPDATE id2 3 4\nCREATE id3\nSUCCESS' + ); + + // Create content to import + + const templates: ItemTemplate[] = [ + { id: 'id1', label: 'item1', repoId: 'repo', typeSchemaUri: 'http://type', version: 2 } + ]; + + const mockContent = new MockContent(dynamicContentClientFactory as jest.Mock); + mockContent.createMockRepository('repo'); + mockContent.registerContentType('http://type', 'type', 'repo'); + mockContent.importItemTemplates(templates); + + const argv = { + ...yargArgs, + ...config, + revertLog: openRevertLog(`temp_${process.env.JEST_WORKER_ID}/revert/createImport.txt`), + dir: '.', + ignoreSchemaValidation: true + }; + await revert(argv); + + expect(mockContent.metrics.itemsUpdated).toEqual(1); + expect(mockContent.metrics.itemsArchived).toEqual(0); + expect(mockContent.items[0].related.update).toHaveBeenCalledTimes(1); + expect((mockContent.items[0].related.update as jest.Mock).mock.calls[0][1].ignoreSchemaValidation).toBe(true); + + await rimraf(`temp_${process.env.JEST_WORKER_ID}/revert/createImport.txt`); + }); + test('Attempting to revert an import of content that has since changed should warn the user and continue on prompt.', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); diff --git a/src/commands/content-item/import-revert.ts b/src/commands/content-item/import-revert.ts index 31bbd141..c33e217e 100644 --- a/src/commands/content-item/import-revert.ts +++ b/src/commands/content-item/import-revert.ts @@ -69,8 +69,9 @@ export const revert = async (argv: Arguments { const hasBeenArchived = entry.item.status !== 'ACTIVE' ? ', has been archived)' : ''; - const summary = `(modified ${(entry.item.version as number) - - entry.newVersion} times since import${hasBeenArchived})`; + const summary = `(modified ${ + (entry.item.version as number) - entry.newVersion + } times since import${hasBeenArchived})`; console.log(` ${entry.item.label} ${summary}`); }); @@ -110,7 +111,8 @@ export const revert = async (argv: Arguments { + fn(contentItems); +}); +const mockCheck = jest.fn().mockImplementation((publishingJob, fn) => { + fn(new PublishingJob({ state: PublishingJobStatus.COMPLETED })); +}); jest.mock('readline'); jest.mock('./import-revert'); jest.mock('../../services/dynamic-content-client-factory'); -jest.mock('../../common/import/publish-queue'); jest.mock('../../common/media/media-rewriter'); jest.mock('../../common/log-helpers', () => ({ ...jest.requireActual('../../common/log-helpers'), getDefaultLogPath: jest.fn() })); +jest.mock('../../common/publishing/content-item-publishing-service', () => { + return { + ContentItemPublishingService: jest.fn().mockImplementation(() => { + return { + publish: mockPublish, + onIdle: jest.fn() + }; + }) + }; +}); +jest.mock('../../common/publishing/content-item-publishing-job-service', () => { + return { + ContentItemPublishingJobService: jest.fn().mockImplementation(() => { + return { + check: mockCheck, + onIdle: jest.fn() + }; + }) + }; +}); function rimraf(dir: string): Promise { return new Promise((resolve): void => { @@ -38,22 +64,22 @@ describe('content-item import command', () => { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('import '); }); - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('item', 'import', process.platform); }); - it('should generate a default mapping path containing the given name', function() { + it('should generate a default mapping path containing the given name', function () { expect(getDefaultMappingPath('hub-1').indexOf('hub-1')).not.toEqual(-1); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); @@ -137,10 +163,16 @@ describe('content-item import command', () => { describe: 'Path to a log file to write to.', coerce: createLog }); + + expect(spyOption).toHaveBeenCalledWith('ignoreSchemaValidation', { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during import' + }); }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -156,11 +188,9 @@ describe('content-item import command', () => { }; beforeEach(async () => { + jest.clearAllMocks(); jest.mock('readline'); jest.mock('../../services/dynamic-content-client-factory'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const calls = (publish as any).publishCalls; - calls.splice(0, calls.length); }); beforeAll(async () => { @@ -662,7 +692,12 @@ describe('content-item import command', () => { await createContent(`temp_${process.env.JEST_WORKER_ID}/import/ref/`, templates, false); // Add an existing mapping for the two items in "oldTemplates". - const existingMapping = { contentItems: [['ref1', 'new1'], ['ref2', 'new2']] }; + const existingMapping = { + contentItems: [ + ['ref1', 'new1'], + ['ref2', 'new2'] + ] + }; await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/import/ref/`); await rimraf(`temp_${process.env.JEST_WORKER_ID}/import/ref.json`); await promisify(writeFile)(`temp_${process.env.JEST_WORKER_ID}/import/ref.json`, JSON.stringify(existingMapping)); @@ -811,7 +846,12 @@ describe('content-item import command', () => { await createContent(`temp_${process.env.JEST_WORKER_ID}/import/mapping/`, oldTemplates.concat(templates), false); // Add an existing mapping for the two items in "oldTemplates". - const existingMapping = { contentItems: [['old1', 'new1'], ['old2', 'new2']] }; + const existingMapping = { + contentItems: [ + ['old1', 'new1'], + ['old2', 'new2'] + ] + }; await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/import/mapping/`); await rimraf(`temp_${process.env.JEST_WORKER_ID}/import/mapping.json`); await promisify(writeFile)( @@ -922,7 +962,12 @@ describe('content-item import command', () => { ); // Add an existing mapping for the two items in "oldTemplates". - const existingMapping = { contentItems: [['old1', 'new1'], ['old2', 'new2']] }; + const existingMapping = { + contentItems: [ + ['old1', 'new1'], + ['old2', 'new2'] + ] + }; await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/import/force/`); await rimraf(`temp_${process.env.JEST_WORKER_ID}/import/force.json`); await promisify(writeFile)( @@ -1148,13 +1193,18 @@ describe('content-item import command', () => { baseRepo: 'targetRepo', publish: true }; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['Y']); + await handler(argv); const matches = await mockContent.filterMatch(templates, '', false); expect(matches.length).toEqual(templates.length); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - expect((publish as any).publishCalls.length).toEqual(2); + + expect(mockPublish).toHaveBeenCalledTimes(2); + expect(mockCheck).toHaveBeenCalledTimes(2); await rimraf(`temp_${process.env.JEST_WORKER_ID}/import/publish/`); }); @@ -1202,16 +1252,16 @@ describe('content-item import command', () => { baseRepo: 'targetRepo', publish: true }; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['Y']); + await handler(argv); // check items were created appropriately - expect(mockContent.metrics.itemsCreated).toEqual(4); expect(mockContent.metrics.itemsUpdated).toEqual(3); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - expect((publish as any).publishCalls.length).toEqual(1); // One of the circular dependancies will be published. - const matches = await mockContent.filterMatch(templates, '', false); expect(matches.length).toEqual(templates.length); @@ -1274,6 +1324,36 @@ describe('content-item import command', () => { await rimraf(`temp_${process.env.JEST_WORKER_ID}/import/depNull/`); }); + it('should import invalid content items when ignoreSchemaValidation is set ', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['y']); + + const templates: ItemTemplate[] = [ + { label: 'item1', repoId: 'repo', typeSchemaUri: 'http://type', body: dependsOn(['id2']) } + ]; + + await createContent(`temp_${process.env.JEST_WORKER_ID}/import/invalid/`, templates, false); + + const mockContent = new MockContent(dynamicContentClientFactory as jest.Mock); + mockContent.createMockRepository('targetRepo'); + mockContent.registerContentType('http://type', 'type', 'targetRepo', dependantType(1)); + + const argv = { + ...yargArgs, + ...config, + dir: `temp_${process.env.JEST_WORKER_ID}/import/invalid/`, + mapFile: `temp_${process.env.JEST_WORKER_ID}/import/invalid.json`, + baseRepo: 'targetRepo', + ignoreSchemaValidation: true + }; + await handler(argv); + + expect(mockContent.metrics.itemsCreated).toEqual(1); + expect(mockContent.metrics.itemsUpdated).toEqual(1); + + await rimraf(`temp_${process.env.JEST_WORKER_ID}/import/invalid/`); + }); + it('should abort when failing to create content', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses([]); @@ -1361,5 +1441,67 @@ describe('content-item import command', () => { await rimraf(`temp_${process.env.JEST_WORKER_ID}/import/media1/`); }); + + it('should create and update content items ignoring schema validation', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['y']); + const oldTemplates: ItemTemplate[] = [ + { id: 'old1', label: 'item1', repoId: 'repo', typeSchemaUri: 'http://type' } + ]; + + const newTemplates = oldTemplates.map(old => ({ ...old, id: 'new' + (old.id as string)[3] })); + + const templates: ItemTemplate[] = [ + { id: 'old2', label: 'item2', repoId: 'repo', typeSchemaUri: 'http://type', folderPath: 'folderTest' } + ]; + + oldTemplates.forEach(template => (template.label += 'updated')); + + await createContent(`temp_${process.env.JEST_WORKER_ID}/import/mapping/`, oldTemplates.concat(templates), false); + + const existingMapping = { + contentItems: [['old1', 'new1']] + }; + await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/import/mapping/`); + await rimraf(`temp_${process.env.JEST_WORKER_ID}/import/mapping.json`); + await promisify(writeFile)( + `temp_${process.env.JEST_WORKER_ID}/import/mapping.json`, + JSON.stringify(existingMapping) + ); + + const mockContent = new MockContent(dynamicContentClientFactory as jest.Mock); + mockContent.createMockRepository('repo'); + mockContent.registerContentType('http://type', 'type', 'repo'); + mockContent.importItemTemplates(newTemplates); + + mockContent.metrics.reset(); + + const argv = { + ...yargArgs, + ...config, + dir: `temp_${process.env.JEST_WORKER_ID}/import/mapping/`, + mapFile: `temp_${process.env.JEST_WORKER_ID}/import/mapping.json`, + baseRepo: 'repo', + ignoreSchemaValidation: true + }; + await handler(argv); + + newTemplates.forEach(template => (template.label += 'updated')); + + const matches = await mockContent.filterMatch(templates.concat(newTemplates), '', false); + + expect(matches.length).toEqual(2); + expect(mockContent.metrics.itemsCreated).toEqual(1); + expect( + (mockContent.repos[0].repo.related.contentItems.create as jest.Mock).mock.calls[0][1].ignoreSchemaValidation + ).toBe(true); + expect(mockContent.metrics.itemsUpdated).toEqual(1); + expect((mockContent.items[0].related.update as jest.Mock).mock.calls[0][1].ignoreSchemaValidation).toBe(true); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((readline as any).responsesLeft()).toEqual(0); + + await rimraf(`temp_${process.env.JEST_WORKER_ID}/import/mapping/`); + }); }); }); diff --git a/src/commands/content-item/import.ts b/src/commands/content-item/import.ts index c4fddadf..fb9e5351 100644 --- a/src/commands/content-item/import.ts +++ b/src/commands/content-item/import.ts @@ -5,7 +5,7 @@ import { revert } from './import-revert'; import { FileLog } from '../../common/file-log'; import { dirname, basename, join, relative, resolve, extname } from 'path'; -import { lstat, readdir, readFile } from 'fs'; +import { lstat, readdir, readFile } from 'graceful-fs'; import { promisify } from 'util'; import { ImportItemBuilderOptions } from '../../interfaces/import-item-builder-options.interface'; import paginator from '../../common/dc-management-sdk-js/paginator'; @@ -17,7 +17,8 @@ import { ContentRepository, ContentType, ContentTypeSchema, - Status + Status, + PublishingJob } from 'dc-management-sdk-js'; import { ContentMapping } from '../../common/content-mapping'; import { @@ -31,8 +32,12 @@ import { Body } from '../../common/content-item/body'; import { AmplienceSchemaValidator, defaultSchemaLookup } from '../../common/content-item/amplience-schema-validator'; import { createLog, getDefaultLogPath } from '../../common/log-helpers'; import { asyncQuestion } from '../../common/question-helpers'; -import { PublishQueue } from '../../common/import/publish-queue'; import { MediaRewriter } from '../../common/media/media-rewriter'; +import { progressBar } from '../../common/progress-bar/progress-bar'; +import { ContentItemPublishingService } from '../../common/publishing/content-item-publishing-service'; +import PublishOptions from '../../common/publish/publish-options'; +import { ContentItemPublishingJobService } from '../../common/publishing/content-item-publishing-job-service'; +import { PublishingJobStatus } from 'dc-management-sdk-js/build/main/lib/model/PublishingJobStatus'; export function getDefaultMappingPath(name: string, platform: string = process.platform): string { return join( @@ -129,6 +134,12 @@ export const builder = (yargs: Argv): void => { default: LOG_FILENAME, describe: 'Path to a log file to write to.', coerce: createLog + }) + + .option('ignoreSchemaValidation', { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during import' }); }; @@ -212,7 +223,6 @@ getOrCreateFolderCached = async (context: ImportContext, path: string): Promise< const traverseRecursive = async (path: string, action: (path: string) => Promise): Promise => { const dir = await promisify(readdir)(path); - await Promise.all( dir.map(async (contained: string) => { contained = join(path, contained); @@ -231,7 +241,8 @@ const createOrUpdateContent = async ( client: DynamicContent, repo: ContentRepository, existing: string | ContentItem | null, - item: ContentItem + item: ContentItem, + argv: Arguments ): Promise => { let oldItem: ContentItem | null = null; if (typeof existing === 'string') { @@ -249,8 +260,12 @@ const createOrUpdateContent = async ( let locale = item.locale; item.locale = undefined; + const upsertParams = { + ...(argv.ignoreSchemaValidation ? { ignoreSchemaValidation: true } : {}) + }; + if (oldItem == null) { - result = { newItem: await repo.related.contentItems.create(item), oldVersion: 0 }; + result = { newItem: await repo.related.contentItems.create(item, upsertParams), oldVersion: 0 }; } else { const oldVersion = oldItem.version || 0; item.version = oldItem.version; @@ -258,7 +273,7 @@ const createOrUpdateContent = async ( // If an item is archived, it must be unarchived before updating it. oldItem = await oldItem.related.unarchive(); } - result = { newItem: await oldItem.related.update(item), oldVersion }; + result = { newItem: await oldItem.related.update(item, upsertParams), oldVersion }; } if (locale != null && result.newItem.locale != locale) { @@ -394,6 +409,7 @@ const prepareContentForImport = async ( if (argv.excludeKeys) { delete filteredContent.body._meta.deliveryKey; + delete filteredContent.body._meta.deliveryKeys; } schemaNames.add(contentJSON.body._meta.schema); @@ -547,7 +563,7 @@ const prepareContentForImport = async ( } catch (e) { log.error( `Failed to rewrite media links. Make sure your client is properly configured, or remove the --media flag.`, - e + e.message ); return null; } @@ -624,8 +640,8 @@ const prepareContentForImport = async ( tree.removeContent(invalidContentItems); } else { const validator = new AmplienceSchemaValidator(defaultSchemaLookup(types, schemas)); - const mustSkip: ItemContentDependancies[] = []; + await Promise.all( invalidContentItems.map(async item => { tree.removeContentDependanciesFromBody( @@ -633,13 +649,15 @@ const prepareContentForImport = async ( item.dependancies.map(dependancy => dependancy.dependancy) ); - try { - const errors = await validator.validate(item.owner.content.body); - if (errors.length > 0) { - mustSkip.push(item); + if (!argv.ignoreSchemaValidation) { + try { + const errors = await validator.validate(item.owner.content.body); + if (errors.length > 0) { + mustSkip.push(item); + } + } catch { + // Just ignore invalid schema for now. } - } catch { - // Just ignore invalid schema for now. } }) ); @@ -721,6 +739,10 @@ const importTree = async ( log.appendLine(`Importing content item failed, aborting. Error: ${error.toString()}`); }; + const importProgress = progressBar(tree.all.length - tree.circularLinks.length, 0, { + title: 'Importing content items' + }); + let publishable: { item: ContentItem; node: ItemContentDependancies }[] = []; for (let i = 0; i < tree.levels.length; i++) { @@ -745,11 +767,13 @@ const importTree = async ( client, item.owner.repo, mapping.getContentItem(originalId as string) || null, - content + content, + argv ); newItem = result.newItem; oldVersion = result.oldVersion; } catch (e) { + importProgress.stop(); log.error(`Failed creating ${content.label}:`, e); abort(e); return false; @@ -767,8 +791,11 @@ const importTree = async ( } mapping.registerContentItem(originalId as string, newItem.id as string); + + importProgress.increment(); } } + importProgress.stop(); // Filter publishables to remove items that will be published as part of another publish. // Cuts down on unnecessary requests. @@ -796,11 +823,13 @@ const importTree = async ( // Create circular dependancies with all the mappings we have, and update the mapping. // Do a second pass that updates the existing assets to point to the new ones. + const newDependants: ContentItem[] = []; for (let pass = 0; pass < 2; pass++) { const mode = pass === 0 ? 'Creating' : 'Resolving'; log.appendLine(`${mode} circular dependants.`); + const dependantsProgress = progressBar(tree.circularLinks.length, 0, { title: 'Importing content items' }); for (let i = 0; i < tree.circularLinks.length; i++) { const item = tree.circularLinks[i]; @@ -820,11 +849,13 @@ const importTree = async ( client, item.owner.repo, newDependants[i] || mapping.getContentItem(originalId as string), - content + content, + argv ); newItem = result.newItem; oldVersion = result.oldVersion; } catch (e) { + dependantsProgress.stop(); log.error(`Failed creating ${content.label}:`, e); abort(e); return false; @@ -847,39 +878,70 @@ const importTree = async ( publishable.push({ item: newItem, node: item }); } } + dependantsProgress.increment(); } + dependantsProgress.stop(); } if (argv.publish) { - const pubQueue = new PublishQueue(argv); log.appendLine(`Publishing ${publishable.length} items. (${publishChildren} children included)`); + const publishingService = new ContentItemPublishingService(); + const contentItemPublishJobs: [ContentItem, PublishingJob][] = []; + const publishProgress = progressBar(publishable.length, 0, { title: 'Publishing content items' }); + for (let i = 0; i < publishable.length; i++) { const item = publishable[i].item; try { - await pubQueue.publish(item); - log.appendLine(`Started publish for ${item.label}.`); + await publishingService.publish(item, (contentItem, publishingJob) => { + contentItemPublishJobs.push([contentItem, publishingJob]); + log.addComment(`Initiated publish for "${item.label}"`); + publishProgress.increment(); + }); } catch (e) { - log.appendLine(`Failed to initiate publish for ${item.label}: ${e.toString()}`); + log.appendLine(`\nFailed to initiate publish for ${item.label}: ${e.toString()}`); + publishProgress.increment(); } } - log.appendLine(`Waiting for all publishes to complete...`); - await pubQueue.waitForAll(); + log.addComment(`Waiting for publishes to be requested`); + await publishingService.onIdle(); + publishProgress.stop(); - log.appendLine(`Finished publishing, with ${pubQueue.failedJobs.length} failed publishes total.`); - pubQueue.failedJobs.forEach(job => { - log.appendLine(` - ${job.item.label}`); - }); + const checkPublishJobs = async () => + await asyncQuestion( + 'All publishes have been requested, would you like to wait for all publishes to complete? (y/n)' + ); + + if (argv.force || (await checkPublishJobs())) { + log.addComment(`Checking publishing jobs`); + const publishingJobService = new ContentItemPublishingJobService(client); + const checkPublishProgress = progressBar(contentItemPublishJobs.length, 0, { + title: 'Content items publishes complete' + }); + + for (const [contentItem, publishingJob] of contentItemPublishJobs) { + publishingJobService.check(publishingJob, async resolvedPublishingJob => { + log.addComment(`Finished checking publish job for ${contentItem.label}`); + if (resolvedPublishingJob.state === PublishingJobStatus.FAILED) { + log.appendLine(`\nFailed to publish ${contentItem.label}: ${resolvedPublishingJob.publishErrorStatus}`); + } + checkPublishProgress.increment(); + }); + } + + await publishingJobService.onIdle(); + checkPublishProgress.stop(); + } + log.appendLine('Publishing complete'); } - log.appendLine('Done!'); return true; }; export const handler = async ( - argv: Arguments + argv: Arguments ): Promise => { if (await argv.revertLog) { return revert(argv); @@ -920,7 +982,7 @@ export const handler = async ( mapFile = getDefaultMappingPath(importTitle); } - if (mapping.load(mapFile)) { + if (await mapping.load(mapFile)) { log.appendLine(`Existing mapping loaded from '${mapFile}', changes will be saved back to it.`); } else { log.appendLine(`Creating new mapping file at '${mapFile}'.`); diff --git a/src/commands/content-item/move.spec.ts b/src/commands/content-item/move.spec.ts index c8d6b72f..3674d834 100644 --- a/src/commands/content-item/move.spec.ts +++ b/src/commands/content-item/move.spec.ts @@ -44,12 +44,12 @@ describe('content-item move command', () => { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('move'); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); @@ -132,6 +132,26 @@ describe('content-item move command', () => { describe: 'Skip any content item that has one or more missing dependancy.' }); + expect(spyOption).toHaveBeenCalledWith('lastPublish', { + type: 'boolean', + boolean: true, + describe: 'When available, export the last published version of a content item rather than its newest version.' + }); + + expect(spyOption).toHaveBeenCalledWith('publish', { + type: 'boolean', + boolean: true, + describe: + 'Publish any content items that either made a new version on import, or were published more recently in the JSON.' + }); + + expect(spyOption).toHaveBeenCalledWith('republish', { + type: 'boolean', + boolean: true, + describe: + 'Republish content items regardless of whether the import changed them or not. (--publish not required)' + }); + expect(spyOption).toHaveBeenCalledWith('excludeKeys', { type: 'boolean', boolean: true, @@ -161,10 +181,16 @@ describe('content-item move command', () => { type: 'string', hidden: true }); + + expect(spyOption).toHaveBeenCalledWith('ignoreSchemaValidation', { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during move' + }); }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -198,7 +224,7 @@ describe('content-item move command', () => { await promisify(writeFile)(logFileName, log); } - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('item', 'move', process.platform); @@ -235,6 +261,9 @@ describe('content-item move command', () => { facet: 'name:/./,schema/./', + publish: true, + lastPublish: true, + mapFile: 'map.json', force: false, validate: false, @@ -260,6 +289,9 @@ describe('content-item move command', () => { expect(copyCalls[0].skipIncomplete).toEqual(argv.skipIncomplete); expect(copyCalls[0].media).toEqual(argv.media); + expect(copyCalls[0].publish).toEqual(argv.publish); + expect(copyCalls[0].lastPublish).toEqual(argv.lastPublish); + expect(argv.exportedIds).toEqual(exportIds); expect(mockContent.metrics.itemsArchived).toEqual(2); @@ -341,6 +373,59 @@ describe('content-item move command', () => { rimraf(`temp_${process.env.JEST_WORKER_ID}/move/moveRevert.txt`); }); + it('should attempt to unarchive based on MOVE actions when passing a revert log and ignore content item schema validation flag', async () => { + const copyCalls: Arguments[] = copierAny.calls; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const revertCalls: Arguments[] = (reverter as any).calls; + + copyCalls.splice(0, copyCalls.length); + revertCalls.splice(0, revertCalls.length); + + await createLog(`temp_${process.env.JEST_WORKER_ID}/move/moveRevert.txt`, 'MOVED id1\n'); + + // Create content to revert + + const templates: ItemTemplate[] = [ + { id: 'id1', label: 'item1', repoId: 'repo', typeSchemaUri: 'http://type', status: 'ARCHIVED' } + ]; + + const mockContent = new MockContent(dynamicContentClientFactory as jest.Mock); + mockContent.createMockRepository('repo'); + mockContent.registerContentType('http://type', 'type', 'repo'); + mockContent.importItemTemplates(templates); + + const argv: Arguments = { + ...yargArgs, + ...config, + dstHubId: 'hub2-id', + dstClientId: 'acc2-id', + dstSecret: 'acc2-secret', + revertLog: openRevertLog(`temp_${process.env.JEST_WORKER_ID}/move/moveRevert.txt`), + ignoreSchemaValidation: true + }; + + await handler(argv); + + expect(mockContent.metrics.itemsUnarchived).toEqual(1); + expect(copyCalls.length).toEqual(0); + + expect(revertCalls.length).toEqual(1); + expect(revertCalls[0]).toEqual({ + $0: '', + _: [], + json: true, + clientId: 'acc2-id', + clientSecret: 'acc2-secret', + dir: '', + hubId: 'hub2-id', + revertLog: expect.any(Promise), + logFile: expect.any(FileLog), + ignoreSchemaValidation: true + }); + + rimraf(`temp_${process.env.JEST_WORKER_ID}/move/moveRevert.txt`); + }); + it('should revert uninterrupted when fetching an item fails', async () => { const copyCalls: Arguments[] = copierAny.calls; diff --git a/src/commands/content-item/move.ts b/src/commands/content-item/move.ts index df67d249..b1a99167 100644 --- a/src/commands/content-item/move.ts +++ b/src/commands/content-item/move.ts @@ -145,6 +145,12 @@ export const builder = (yargs: Argv): void => { .option('schemaId', { type: 'string', hidden: true + }) + + .option('ignoreSchemaValidation', { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during move' }); }; @@ -204,15 +210,13 @@ export const handler = async (argv: Arguments { + fn(contentItems, new PublishingJob({ state: PublishingJobStatus.CREATED })); +}); +const mockCheck = jest.fn().mockImplementation((publishingJob, fn) => { + fn(new PublishingJob({ state: PublishingJobStatus.COMPLETED })); +}); +const mockPublishOnIdle = jest.fn().mockImplementation(() => Promise.resolve()); +const mockCheckOnIdle = jest.fn().mockImplementation(() => Promise.resolve()); + +const confirmAllContentSpy = jest.spyOn(confirmAllContentModule, 'confirmAllContent'); +const asyncQuestionSpy = jest.spyOn(questionHelpers, 'asyncQuestion'); + +jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../common/log-helpers'); +jest.mock('../../common/filter/fetch-content'); +jest.mock('../../common/content-item/get-content-items-by-ids', () => { + return { + getContentByIds: jest.fn() + }; +}); +jest.mock('../../common/publishing/content-item-publishing-service', () => { + return { + ContentItemPublishingService: jest.fn().mockImplementation(() => { + return { + publish: mockPublish, + onIdle: mockPublishOnIdle + }; + }) + }; +}); +jest.mock('../../common/publishing/content-item-publishing-job-service', () => { + return { + ContentItemPublishingJobService: jest.fn().mockImplementation(() => { + return { + check: mockCheck, + onIdle: mockCheckOnIdle + }; + }) + }; +}); + +describe('publish tests', () => { + describe('builder tests', () => { + it('should configure yargs', function () { + const argv = Yargs(process.argv.slice(2)); + const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); + const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); + + builder(argv); + + expect(spyPositional).toHaveBeenCalledWith('id', { + type: 'string', + describe: + 'The ID of a content item to be published. If id is not provided, this command will publish ALL content items through all content repositories in the hub.' + }); + + expect(spyOption).toHaveBeenCalledWith('repoId', { + type: 'string', + describe: 'The ID of a content repository to search items in to be published.', + requiresArg: false + }); + + expect(spyOption).toHaveBeenCalledWith('folderId', { + type: 'string', + describe: 'The ID of a folder to search items in to be published.', + requiresArg: false + }); + + expect(spyOption).toHaveBeenCalledWith('facet', { + type: 'string', + describe: + "Publish content matching the given facets. Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values. A regex can be provided for text filters, surrounded with forward slashes. For more examples, see the readme." + }); + + expect(spyOption).toHaveBeenCalledWith('f', { + type: 'boolean', + boolean: true, + describe: 'If present, there will be no confirmation prompt before publishing the found content.' + }); + + expect(spyOption).toHaveBeenCalledWith('s', { + type: 'boolean', + boolean: true, + describe: 'If present, no log file will be produced.' + }); + + expect(spyOption).toHaveBeenCalledWith('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: coerceLog + }); + }); + }); + + describe('handler', () => { + const HUB_ID = '67d1c1c7642fa239dbe15164'; + const CONTENT_ITEM_ID = 'c5b659df-680e-4711-bfbe-84eaa10d76cc'; + const globalArgs = { + $0: 'test', + _: ['test'], + json: true, + clientId: 'client-id', + clientSecret: 'client-secret', + hubId: HUB_ID + }; + + const mockAppendLine = jest.fn(); + const mockLog = { + open: jest.fn().mockReturnValue({ + appendLine: mockAppendLine, + addComment: jest.fn(), + close: jest.fn() + }) + } as unknown as FileLog; + + beforeEach(() => { + jest.clearAllMocks(); + confirmAllContentSpy.mockResolvedValue(true); + asyncQuestionSpy.mockResolvedValue(true); + }); + + it('should publish content item by id', async () => { + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContentByIds as unknown as jest.Mock).mockResolvedValue([ + new ContentItem({ id: CONTENT_ITEM_ID, body: { _meta: {} } }) + ]); + + mockPublish.mockImplementation((contentItem, fn) => { + fn(new Job({ id: '68e5289f0aba3024bde050f9', status: 'COMPLETE' })); + }); + + await handler({ + ...globalArgs, + id: CONTENT_ITEM_ID, + logFile: mockLog + }); + + expect(getContentByIds).toHaveBeenCalledWith(expect.any(Object), [CONTENT_ITEM_ID]); + expect(mockPublish).toHaveBeenCalledTimes(1); + expect(mockPublish).toHaveBeenCalledWith(expect.any(ContentItem), expect.any(Function)); + expect(mockPublishOnIdle).toHaveBeenCalledTimes(1); + expect(mockCheck).toHaveBeenCalledTimes(1); + expect(mockCheckOnIdle).toHaveBeenCalledTimes(1); + }); + it('should publish content items by query', async () => { + const REPOSITORY_ID = '67d1c1cf642fa239dbe15165'; + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContent as unknown as jest.Mock).mockResolvedValue([ + new ContentItem({ id: CONTENT_ITEM_ID, body: { _meta: {} } }) + ]); + + mockPublish.mockImplementation((contentItem, fn) => { + fn(new Job({ id: '68e5289f0aba3024bde050f9', status: 'COMPLETE' })); + }); + + await handler({ + ...globalArgs, + repoId: REPOSITORY_ID, + logFile: mockLog + }); + + expect(getContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Hub), undefined, { + enrichItems: true, + folderId: undefined, + repoId: REPOSITORY_ID, + status: 'ACTIVE' + }); + expect(mockPublish).toHaveBeenCalledTimes(1); + expect(mockPublish).toHaveBeenCalledWith(expect.any(ContentItem), expect.any(Function)); + expect(mockPublishOnIdle).toHaveBeenCalledTimes(1); + expect(mockCheck).toHaveBeenCalledTimes(1); + expect(mockCheckOnIdle).toHaveBeenCalledTimes(1); + }); + + it('should process all items while filtering out any dependencies and call publish', async () => { + const contentItemWithDependency = new ContentItem({ + id: 'da2ee918-34c3-4fc1-ae05-111111111111', + label: 'Publish me', + body: { + _meta: {}, + dependency: { + _meta: { schema: 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-link' }, + contentType: 'http://bigcontent.io/cms/schema/v1/text', + id: 'da2ee918-34c3-4fc1-ae05-222222222222' + } + } + }); + const contentItemDependency = new ContentItem({ + id: 'da2ee918-34c3-4fc1-ae05-222222222222', + label: 'No need to publish me', + body: { _meta: {} } + }); + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContentByIds as unknown as jest.Mock).mockResolvedValue([contentItemWithDependency, contentItemDependency]); + + mockPublish.mockImplementation((contentItem, fn) => { + fn(new Job({ id: '68e5289f0aba3024bde050f9', status: 'COMPLETE' })); + }); + + await handler({ + ...globalArgs, + id: [contentItemWithDependency.id, contentItemDependency.id], + logFile: mockLog + }); + + expect(mockPublish).toHaveBeenCalledTimes(1); + expect(mockPublish).toHaveBeenCalledWith(contentItemWithDependency, expect.any(Function)); + expect(mockPublishOnIdle).toHaveBeenCalledTimes(1); + expect(mockCheck).toHaveBeenCalledTimes(1); + expect(mockCheckOnIdle).toHaveBeenCalledTimes(1); + }); + + it('should exit before processing content items if confirmation to proceed is rejected', async () => { + confirmAllContentSpy.mockResolvedValue(false); + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContentByIds as unknown as jest.Mock).mockResolvedValue([ + new ContentItem({ id: CONTENT_ITEM_ID, body: { _meta: {} } }) + ]); + + await handler({ + ...globalArgs, + id: CONTENT_ITEM_ID, + logFile: mockLog + }); + expect(mockPublish).not.toHaveBeenCalled(); + expect(mockPublishOnIdle).not.toHaveBeenCalled(); + expect(mockCheck).not.toHaveBeenCalled(); + expect(mockCheckOnIdle).not.toHaveBeenCalled(); + }); + + it('should not check publishing jobs if check question is rejected', async () => { + asyncQuestionSpy.mockResolvedValue(false); + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContentByIds as unknown as jest.Mock).mockResolvedValue([ + new ContentItem({ id: 'CONTENT_ITEM_ID_ZZZZZZZZZ', body: { _meta: {} } }) + ]); + + mockPublish.mockImplementation((contentItem, fn) => { + fn(new Job({ id: '68e5289f0aba3024bde050f9', status: 'COMPLETE' })); + }); + + await handler({ + ...globalArgs, + id: 'CONTENT_ITEM_ID_ZZZZZZZZZ', + logFile: mockLog + }); + + expect(mockPublish).toHaveBeenCalledTimes(1); + expect(mockPublishOnIdle).toHaveBeenCalledTimes(1); + expect(mockCheck).not.toHaveBeenCalled(); + expect(mockCheckOnIdle).not.toHaveBeenCalled(); + }); + + it('should exit early if ID or query args are not passed', async () => { + await handler({ + ...globalArgs, + id: CONTENT_ITEM_ID, + facet: 'mock-facet', + logFile: mockLog + }); + expect(mockAppendLine).toHaveBeenCalledWith('Please specify either a facet or an ID - not both'); + expect(mockPublish).not.toHaveBeenCalled(); + expect(mockPublishOnIdle).not.toHaveBeenCalled(); + expect(mockCheck).not.toHaveBeenCalled(); + expect(mockCheckOnIdle).not.toHaveBeenCalled(); + }); + + it('should exit early if no content items', async () => { + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContentByIds as unknown as jest.Mock).mockResolvedValue([]); + await handler({ + ...globalArgs, + id: CONTENT_ITEM_ID, + logFile: mockLog + }); + expect(mockAppendLine).toHaveBeenCalledWith('Nothing found to publish, aborting'); + expect(mockPublish).not.toHaveBeenCalled(); + expect(mockPublishOnIdle).not.toHaveBeenCalled(); + expect(mockCheck).not.toHaveBeenCalled(); + expect(mockCheckOnIdle).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/src/commands/content-item/publish.ts b/src/commands/content-item/publish.ts new file mode 100644 index 00000000..ffc58820 --- /dev/null +++ b/src/commands/content-item/publish.ts @@ -0,0 +1,200 @@ +import { Arguments, Argv } from 'yargs'; +import { ConfigurationParameters } from '../configure'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { confirmAllContent } from '../../common/content-item/confirm-all-content'; +import PublishOptions from '../../common/publish/publish-options'; +import { ContentItem, DynamicContent, PublishingJob, Status } from 'dc-management-sdk-js'; +import { getDefaultLogPath, createLog } from '../../common/log-helpers'; +import { FileLog } from '../../common/file-log'; +import { withOldFilters } from '../../common/filter/facet'; +import { getContent } from '../../common/filter/fetch-content'; +import { asyncQuestion } from '../../common/question-helpers'; +import { ContentItemPublishingService } from '../../common/publishing/content-item-publishing-service'; +import { ContentItemPublishingJobService } from '../../common/publishing/content-item-publishing-job-service'; +import { PublishingJobStatus } from 'dc-management-sdk-js/build/main/lib/model/PublishingJobStatus'; +import { progressBar } from '../../common/progress-bar/progress-bar'; +import { getContentByIds } from '../../common/content-item/get-content-items-by-ids'; +import { dedupeContentItems } from '../../common/content-item/dedupe-content-items'; + +export const command = 'publish [id]'; + +export const desc = 'Publish Content Items'; + +export const LOG_FILENAME = (platform: string = process.platform): string => + getDefaultLogPath('content-item', 'publish', platform); + +export const coerceLog = (logFile: string): FileLog => createLog(logFile, 'Content Items Publish Log'); + +export const builder = (yargs: Argv): void => { + yargs + .positional('id', { + type: 'string', + describe: + 'The ID of a content item to be published. If id is not provided, this command will publish ALL content items through all content repositories in the hub.' + }) + .option('repoId', { + type: 'string', + describe: 'The ID of a content repository to search items in to be published.', + requiresArg: false + }) + .option('folderId', { + type: 'string', + describe: 'The ID of a folder to search items in to be published.', + requiresArg: false + }) + .option('facet', { + type: 'string', + describe: + "Publish content matching the given facets. Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values. A regex can be provided for text filters, surrounded with forward slashes. For more examples, see the readme." + }) + .alias('f', 'force') + .option('f', { + type: 'boolean', + boolean: true, + describe: 'If present, there will be no confirmation prompt before publishing the found content.' + }) + .alias('s', 'silent') + .option('s', { + type: 'boolean', + boolean: true, + describe: 'If present, no log file will be produced.' + }) + .option('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: coerceLog + }) + .option('name', { + type: 'string', + hidden: true + }); +}; + +const processItems = async ({ + client, + contentItems, + force, + log +}: { + client: DynamicContent; + contentItems: ContentItem[]; + force?: boolean; + log: FileLog; +}): Promise => { + const dedupedContentItems = dedupeContentItems(contentItems); + + log.appendLine( + `Publishing ${dedupedContentItems.length} item(s) (ignoring ${contentItems.length - dedupedContentItems.length} duplicate child item(s))` + ); + + const publishingService = new ContentItemPublishingService(); + const contentItemPublishJobs: [ContentItem, PublishingJob][] = []; + const publishProgress = progressBar(dedupedContentItems.length, 0, { title: 'Publishing content items' }); + for (const item of dedupedContentItems) { + try { + await publishingService.publish(item, (contentItem, publishingJob) => { + contentItemPublishJobs.push([contentItem, publishingJob]); + log.addComment(`Initiated publish for "${item.label}"`); + publishProgress.increment(); + }); + } catch (e) { + log.appendLine(`\nFailed to initiate publish for ${item.label}: ${e.toString()}`); + publishProgress.increment(); + } + } + + await publishingService.onIdle(); + publishProgress.stop(); + + const checkPublishJobs = async () => + await asyncQuestion( + 'All publishes have been requested, would you like to wait for all publishes to complete? (y/n)' + ); + + if (force || (await checkPublishJobs())) { + log.appendLine(`Checking publishing state for ${contentItemPublishJobs.length} items.`); + const checkPublishProgress = progressBar(contentItemPublishJobs.length, 0, { + title: 'Content items publishes complete' + }); + + const publishingJobService = new ContentItemPublishingJobService(client); + + for (const [contentItem, publishingJob] of contentItemPublishJobs) { + publishingJobService.check(publishingJob, async resolvedPublishingJob => { + log.addComment(`Finished checking publish job for ${contentItem.label}`); + if (resolvedPublishingJob.state === PublishingJobStatus.FAILED) { + log.appendLine(`\nFailed to publish ${contentItem.label}: ${resolvedPublishingJob.publishErrorStatus}`); + } + checkPublishProgress.increment(); + }); + } + + await publishingJobService.onIdle(); + checkPublishProgress.stop(); + } +}; + +export const handler = async (argv: Arguments): Promise => { + const { id, logFile, force, silent, hubId, repoId, folderId } = argv; + const log = logFile.open(); + const client = dynamicContentClientFactory(argv); + const facet = withOldFilters(argv.facet, argv); + const allContent = !id && !facet && !folderId && !repoId; + + if (repoId && id) { + log.appendLine('ID of content item is specified, ignoring repository ID'); + } + + if (id && facet) { + log.appendLine('Please specify either a facet or an ID - not both'); + return; + } + + if (repoId && folderId) { + log.appendLine('Folder is specified, ignoring repository ID'); + } + + if (allContent) { + log.appendLine('No filter was given, publishing all content'); + } + + let ids: string[] = []; + + if (id) { + ids = Array.isArray(id) ? id : [id]; + } + + const hub = await client.hubs.get(hubId); + const contentItems = + ids.length > 0 + ? await getContentByIds(client, ids) + : await getContent(client, hub, facet, { repoId, folderId, status: Status.ACTIVE, enrichItems: true }); + + if (!contentItems.length) { + log.appendLine('Nothing found to publish, aborting'); + return; + } + + const missingContentItems = ids.length > 0 ? Boolean(ids.length !== contentItems.length) : false; + + log.appendLine(`Found ${contentItems.length} content items to publish (including duplicate child items)\n`); + + if (!force) { + const yes = await confirmAllContent('publish', 'content items', allContent, missingContentItems); + if (!yes) { + return; + } + } + + await processItems({ + client, + contentItems, + force, + log + }); + + log.appendLine(`Publishing complete`); + + await log.close(!silent); +}; diff --git a/src/commands/content-item/sync.service.spec.ts b/src/commands/content-item/sync.service.spec.ts new file mode 100644 index 00000000..34b129a8 --- /dev/null +++ b/src/commands/content-item/sync.service.spec.ts @@ -0,0 +1,87 @@ +import { ContentItem, Hub, Job } from 'dc-management-sdk-js'; +import { ContentItemSyncService } from './sync.service'; + +const createMockHub = (id: string) => { + return { ...new Hub({ id }), ...{ related: { jobs: { createDeepSyncJob: jest.fn(), get: jest.fn() } } } }; +}; + +describe('sync.service', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('ContentItemSyncService', () => { + describe('sync', () => { + it('should add a content item sync job to the queue and process the queue item', async () => { + const JOB_ID = '68e5289f0aba3024bde050f9'; + const DEST_HUB_ID = '67d2a201642fa239dbe1523d'; + const CONTENT_ITEM_ID = 'c5b659df-680e-4711-bfbe-84eaa10d76cc'; + const contentItem = new ContentItem({ id: CONTENT_ITEM_ID, label: 'sync service test' }); + const hub = createMockHub(CONTENT_ITEM_ID); + + hub.related.jobs.createDeepSyncJob.mockResolvedValue(new Job({ jobId: JOB_ID })); + hub.related.jobs.get.mockResolvedValue(new Job({ id: JOB_ID, status: 'COMPLETED' })); + + const syncService = new ContentItemSyncService(); + syncService.sync(DEST_HUB_ID, hub as unknown as Hub, contentItem, () => {}); + await syncService.onIdle(); + + expect(hub.related.jobs.createDeepSyncJob).toHaveBeenCalledWith({ + label: `dc-cli content item: sync service test`, + ignoreSchemaValidation: true, + destinationHubId: DEST_HUB_ID, + input: { rootContentItemIds: [CONTENT_ITEM_ID] } + }); + expect(hub.related.jobs.get).toHaveBeenNthCalledWith(1, JOB_ID); + expect(syncService.failedJobs.length).toEqual(0); + }); + it('should add a content item sync job to the queue, process and wait for a completed job', async () => { + const JOB_ID = '68e5289f0aba3024bde050f9'; + const DEST_HUB_ID = '67d2a201642fa239dbe1523d'; + const CONTENT_ITEM_ID = 'c5b659df-680e-4711-bfbe-84eaa10d76cc'; + const contentItem = new ContentItem({ id: CONTENT_ITEM_ID, label: 'sync service test' }); + const hub = createMockHub(CONTENT_ITEM_ID); + + hub.related.jobs.createDeepSyncJob.mockResolvedValue(new Job({ jobId: JOB_ID })); + hub.related.jobs.get + .mockResolvedValueOnce(new Job({ id: JOB_ID, status: 'IN_PROGRESS' })) + .mockResolvedValueOnce(new Job({ id: JOB_ID, status: 'COMPLETED' })); + + const syncService = new ContentItemSyncService(); + syncService.sync(DEST_HUB_ID, hub as unknown as Hub, contentItem, () => {}); + await syncService.onIdle(); + + expect(hub.related.jobs.createDeepSyncJob).toHaveBeenCalledWith({ + label: `dc-cli content item: sync service test`, + ignoreSchemaValidation: true, + destinationHubId: DEST_HUB_ID, + input: { rootContentItemIds: [CONTENT_ITEM_ID] } + }); + expect(hub.related.jobs.get).toHaveBeenNthCalledWith(2, JOB_ID); + expect(syncService.failedJobs.length).toEqual(0); + }); + it('should add a content item sync job to the queue, process and store a failed job', async () => { + const JOB_ID = '68e5289f0aba3024bde050f9'; + const DEST_HUB_ID = '67d2a201642fa239dbe1523d'; + const CONTENT_ITEM_ID = 'c5b659df-680e-4711-bfbe-84eaa10d76cc'; + const contentItem = new ContentItem({ id: CONTENT_ITEM_ID, label: 'sync service test' }); + const hub = createMockHub(CONTENT_ITEM_ID); + + hub.related.jobs.createDeepSyncJob.mockResolvedValue(new Job({ jobId: JOB_ID })); + hub.related.jobs.get.mockResolvedValueOnce(new Job({ id: JOB_ID, status: 'FAILED' })); + + const syncService = new ContentItemSyncService(); + syncService.sync(DEST_HUB_ID, hub as unknown as Hub, contentItem, () => {}); + await syncService.onIdle(); + + expect(hub.related.jobs.createDeepSyncJob).toHaveBeenCalledWith({ + label: `dc-cli content item: sync service test`, + ignoreSchemaValidation: true, + destinationHubId: DEST_HUB_ID, + input: { rootContentItemIds: [CONTENT_ITEM_ID] } + }); + expect(hub.related.jobs.get).toHaveBeenNthCalledWith(1, JOB_ID); + expect(syncService.failedJobs.length).toEqual(1); + }); + }); + }); +}); diff --git a/src/commands/content-item/sync.service.ts b/src/commands/content-item/sync.service.ts new file mode 100644 index 00000000..52fc7d4c --- /dev/null +++ b/src/commands/content-item/sync.service.ts @@ -0,0 +1,52 @@ +import { ContentItem, CreateDeepSyncJobRequest, Hub, Job } from 'dc-management-sdk-js'; +import { BurstableQueue } from '../../common/burstable-queue/burstable-queue'; +import { setTimeout } from 'node:timers/promises'; + +const DELAY = 200; + +export class ContentItemSyncService { + private queue; + private _failedJobs: Job[] = []; + + constructor() { + this.queue = new BurstableQueue({ concurrency: 1 }); + } + + sync(destinationHubId: string, hub: Hub, contentItem: ContentItem, action: (job: Job) => void): void { + this.queue.add(async () => { + const createSyncJob = await hub.related.jobs.createDeepSyncJob( + new CreateDeepSyncJobRequest({ + label: `dc-cli content item: ${contentItem.label}`, + ignoreSchemaValidation: true, + destinationHubId, + input: { rootContentItemIds: [contentItem.id] } + }) + ); + + const completedJob = await this.waitForJobCompletion(createSyncJob.jobId, hub); + + if (completedJob.status === 'FAILED') { + this._failedJobs.push(completedJob); + } + + action(completedJob); + }); + } + + private async waitForJobCompletion(jobId: string, hub: Hub): Promise { + let syncJob = await hub.related.jobs.get(jobId); + while (syncJob.status === 'CREATED' || syncJob.status === 'IN_PROGRESS') { + await setTimeout(DELAY); + syncJob = await hub.related.jobs.get(syncJob.id); + } + return syncJob; + } + + async onIdle(): Promise { + return this.queue.onIdle(); + } + + get failedJobs(): Job[] { + return this._failedJobs; + } +} diff --git a/src/commands/content-item/sync.spec.ts b/src/commands/content-item/sync.spec.ts new file mode 100644 index 00000000..b0893c3d --- /dev/null +++ b/src/commands/content-item/sync.spec.ts @@ -0,0 +1,207 @@ +import Yargs from 'yargs/yargs'; +import readline from 'readline'; +import { builder, coerceLog, command, handler, LOG_FILENAME } from './sync'; +import { FileLog } from '../../common/file-log'; + +import { getContentByIds } from '../../common/content-item/get-content-items-by-ids'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { ContentItem, Hub, Job } from 'dc-management-sdk-js'; +import { getContent } from '../../common/filter/fetch-content'; + +jest.mock('readline'); + +const mockSync = jest.fn(); +const mockOnIdle = jest.fn(); +const mockFailedJobs = jest.fn(); +jest.mock('./sync.service', () => { + return { + ContentItemSyncService: jest.fn().mockImplementation(() => { + return { + sync: mockSync, + onIdle: mockOnIdle, + failedJobs: mockFailedJobs + }; + }) + }; +}); + +jest.mock('../../common/content-item/get-content-items-by-ids', () => { + return { + getContentByIds: jest.fn() + }; +}); +jest.mock('../../common/filter/fetch-content', () => { + return { + getContent: jest.fn() + }; +}); +jest.mock('../../services/dynamic-content-client-factory'); + +describe('content-item sync', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should command should defined', function () { + expect(command).toEqual('sync [id]'); + }); + + describe('builder', () => { + it('should configure command arguments', () => { + const argv = Yargs(process.argv.slice(2)); + const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); + const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); + + builder(argv); + + expect(spyPositional).toHaveBeenCalledWith('id', { + type: 'string', + describe: `The ID of a content item to sync. If id is not provided, this command will sync ALL content items through all content repositories in the hub.` + }); + + expect(spyOption).toHaveBeenCalledWith('repoId', { + type: 'string', + describe: 'The ID of a content repository to search items in to be sync.', + requiresArg: false + }); + + expect(spyOption).toHaveBeenCalledWith('folderId', { + type: 'string', + describe: 'The ID of a folder to search items in to be sync.', + requiresArg: false + }); + + expect(spyOption).toHaveBeenCalledWith('facet', { + type: 'string', + describe: + "Publish content matching the given facets. Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values. A regex can be provided for text filters, surrounded with forward slashes. For more examples, see the readme." + }); + + expect(spyOption).toHaveBeenCalledWith('f', { + type: 'boolean', + boolean: true, + describe: 'If present, there will be no confirmation prompt before publishing the found content.' + }); + + expect(spyOption).toHaveBeenCalledWith('s', { + type: 'boolean', + boolean: true, + describe: 'If present, no log file will be produced.' + }); + + expect(spyOption).toHaveBeenCalledWith('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: coerceLog + }); + + expect(spyOption).toHaveBeenCalledWith('destinationHubId', { + type: 'string', + describe: 'The ID of a destination hub to sync with.', + requiresArg: true, + demandOption: true + }); + }); + }); + + describe('handler', () => { + const HUB_ID = '67d1c1c7642fa239dbe15164'; + const DEST_HUB_ID = '67d2a201642fa239dbe1523d'; + const globalArgs = { + $0: 'test', + _: ['test'], + json: true, + clientId: 'client-id', + clientSecret: 'client-secret', + hubId: HUB_ID + }; + + const mockLog = { + open: jest.fn().mockReturnValue({ + appendLine: jest.fn(), + addComment: jest.fn(), + close: jest.fn() + }) + } as unknown as FileLog; + + it('should sync content item by id', async () => { + const CONTENT_ITEM_ID = 'c5b659df-680e-4711-bfbe-84eaa10d76cc'; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['y']); + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContentByIds as unknown as jest.Mock).mockResolvedValue([ + new ContentItem({ id: CONTENT_ITEM_ID, body: { _meta: {} } }) + ]); + + mockSync.mockImplementation((destinationHubId, hub, contentItem, fn) => { + fn(new Job({ id: '68e5289f0aba3024bde050f9', status: 'COMPLETE' })); + }); + + mockFailedJobs.mockReturnValue(0); + + await handler({ + ...globalArgs, + id: CONTENT_ITEM_ID, + destinationHubId: DEST_HUB_ID, + logFile: mockLog + }); + + expect(getContentByIds).toHaveBeenCalledWith(expect.any(Object), [CONTENT_ITEM_ID]); + expect(mockSync).toHaveBeenCalledTimes(1); + expect(mockSync).toHaveBeenCalledWith( + DEST_HUB_ID, + expect.any(Hub), + expect.any(ContentItem), + expect.any(Function) + ); + }); + it('should sync content items by query', async () => { + const CONTENT_ITEM_ID = 'c5b659df-680e-4711-bfbe-84eaa10d76cc'; + const REPOSITORY_ID = 'c5b659df-680e-4711-bfbe-84eaa10d76cc'; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['y']); + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContent as unknown as jest.Mock).mockResolvedValue([ + new ContentItem({ id: CONTENT_ITEM_ID, body: { _meta: {} } }) + ]); + + mockSync.mockImplementation((destinationHubId, hub, contentItem, fn) => { + fn(new Job({ id: '68e5289f0aba3024bde050f9', status: 'COMPLETE' })); + }); + + mockFailedJobs.mockReturnValue(0); + + await handler({ + ...globalArgs, + repoId: REPOSITORY_ID, + destinationHubId: DEST_HUB_ID, + logFile: mockLog + }); + + expect(getContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Hub), undefined, { + repoId: REPOSITORY_ID, + folderId: undefined, + enrichItems: true, + status: 'ACTIVE' + }); + expect(mockSync).toHaveBeenCalledTimes(1); + expect(mockSync).toHaveBeenCalledWith( + DEST_HUB_ID, + expect.any(Hub), + expect.any(ContentItem), + expect.any(Function) + ); + }); + }); +}); diff --git a/src/commands/content-item/sync.ts b/src/commands/content-item/sync.ts new file mode 100644 index 00000000..05827ae8 --- /dev/null +++ b/src/commands/content-item/sync.ts @@ -0,0 +1,166 @@ +import { Arguments, Argv } from 'yargs'; +import { ConfigurationParameters } from '../configure'; +import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { FileLog } from '../../common/file-log'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { withOldFilters } from '../../common/filter/facet'; +import { Job, Status } from 'dc-management-sdk-js'; +import { getContent } from '../../common/filter/fetch-content'; +import { confirmAllContent } from '../../common/content-item/confirm-all-content'; +import { progressBar } from '../../common/progress-bar/progress-bar'; +import { ContentItemSyncService } from './sync.service'; +import { dedupeContentItems } from '../../common/content-item/dedupe-content-items'; +import { getContentByIds } from '../../common/content-item/get-content-items-by-ids'; + +export const LOG_FILENAME = (platform: string = process.platform): string => + getDefaultLogPath('content-item', 'sync', platform); + +export const coerceLog = (logFile: string): FileLog => createLog(logFile, 'Content Items Sync Log'); + +export const command = 'sync [id]'; + +export const desc = 'Sync Content Items'; + +export const builder = (yargs: Argv): void => { + yargs + .positional('id', { + type: 'string', + describe: `The ID of a content item to sync. If id is not provided, this command will sync ALL content items through all content repositories in the hub.` + }) + .option('repoId', { + type: 'string', + describe: 'The ID of a content repository to search items in to be sync.', + requiresArg: false + }) + .option('folderId', { + type: 'string', + describe: 'The ID of a folder to search items in to be sync.', + requiresArg: false + }) + .option('facet', { + type: 'string', + describe: + "Publish content matching the given facets. Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values. A regex can be provided for text filters, surrounded with forward slashes. For more examples, see the readme." + }) + .alias('f', 'force') + .option('f', { + type: 'boolean', + boolean: true, + describe: 'If present, there will be no confirmation prompt before publishing the found content.' + }) + .alias('s', 'silent') + .option('s', { + type: 'boolean', + boolean: true, + describe: 'If present, no log file will be produced.' + }) + .option('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: coerceLog + }) + .option('destinationHubId', { + type: 'string', + describe: 'The ID of a destination hub to sync with.', + requiresArg: true, + demandOption: true + }); +}; + +export default interface SyncOptions { + id?: string; + repoId?: string | string[]; + folderId?: string | string[]; + facet?: string; + logFile: FileLog; + force?: boolean; + silent?: boolean; + destinationHubId: string; +} + +export const handler = async (argv: Arguments): Promise => { + const { id, logFile, force, silent, hubId, repoId, folderId, destinationHubId } = argv; + const log = logFile.open(); + const client = dynamicContentClientFactory(argv); + const facet = withOldFilters(argv.facet, argv); + const allContent = !id && !facet && !folderId && !repoId; + + if (repoId && id) { + log.appendLine('ID of content item is specified, ignoring repository ID'); + } + + if (id && facet) { + log.appendLine('Please specify either a facet or an ID - not both'); + return; + } + + if (repoId && folderId) { + log.appendLine('Folder is specified, ignoring repository ID'); + } + + if (allContent) { + log.appendLine('No filter was given, syncing all content'); + } + + const hub = await client.hubs.get(hubId); + + let ids: string[] = []; + + if (id) { + ids = Array.isArray(id) ? id : [id]; + } + + const contentItems = + ids.length > 0 + ? await getContentByIds(client, ids) + : await getContent(client, hub, facet, { repoId, folderId, status: Status.ACTIVE, enrichItems: true }); + + if (!contentItems.length) { + log.appendLine('Nothing found to sync, aborting'); + return; + } + + const dedupedContentItems = dedupeContentItems(contentItems); + + log.appendLine( + `Found ${dedupedContentItems.length} item(s) to sync (ignoring ${contentItems.length - dedupedContentItems.length} duplicate child item(s))` + ); + + const missingContentItems = ids.length > 0 ? Boolean(ids.length !== contentItems.length) : false; + + if (!force) { + const yes = await confirmAllContent('sync', 'content items', allContent, missingContentItems); + if (!yes) { + return; + } + } + + log.appendLine(`Syncing ${dedupedContentItems.length} item(s)`); + + const progress = progressBar(dedupedContentItems.length, 0, { title: 'Syncing content items' }); + const syncService = new ContentItemSyncService(); + + dedupedContentItems.forEach(contentItem => { + log.addComment(`Requesting content item sync: ${contentItem.label}`); + syncService.sync(destinationHubId, hub, contentItem, (syncJob: Job) => { + progress.increment(); + const logComment = + syncJob.status === 'FAILED' + ? `Failed content item sync job ${syncJob.id}: ${JSON.stringify(syncJob.errors)}` + : `Content item synced: ${contentItem.label} (jobId: ${syncJob.id})`; + + log.addComment(logComment); + }); + }); + + await syncService.onIdle(); + progress.stop(); + + const failedJobCount = syncService.failedJobs.length; + const failedJobsMsg = failedJobCount ? `with ${failedJobCount} failed jobs - check logs for details` : ``; + + log.appendLine(`Sync complete ${failedJobsMsg}`); + + await log.close(!silent); +}; diff --git a/src/commands/content-item/tree.spec.ts b/src/commands/content-item/tree.spec.ts index 3b9308fe..d7c31099 100644 --- a/src/commands/content-item/tree.spec.ts +++ b/src/commands/content-item/tree.spec.ts @@ -34,12 +34,12 @@ describe('content-item tree command', () => { jest.resetAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('tree '); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); @@ -52,7 +52,7 @@ describe('content-item tree command', () => { }); }); - describe('firstSecondThird tests', function() { + describe('firstSecondThird tests', function () { it('should return 0 for the first item in a list, above size 1', () => { expect(firstSecondThird(0, 2)).toEqual(0); expect(firstSecondThird(0, 3)).toEqual(0); @@ -73,7 +73,7 @@ describe('content-item tree command', () => { }); }); - describe('fillWhitespace tests', function() { + describe('fillWhitespace tests', function () { it('should fill space characters only after the original string with the given character up to the length', () => { expect(fillWhitespace(' ', ' ', '-', 4)).toEqual(' '); expect(fillWhitespace(' ', ' ', '-', 8)).toEqual(' ----'); @@ -88,7 +88,7 @@ describe('content-item tree command', () => { }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -138,7 +138,7 @@ describe('content-item tree command', () => { ); }; - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('item', 'tree', process.platform); diff --git a/src/commands/content-item/unarchive.spec.ts b/src/commands/content-item/unarchive.spec.ts index abc98bdc..69d858d6 100644 --- a/src/commands/content-item/unarchive.spec.ts +++ b/src/commands/content-item/unarchive.spec.ts @@ -1,25 +1,29 @@ -import { - builder, - command, - handler, - LOG_FILENAME, - filterContentItems, - getContentItems, - processItems -} from './unarchive'; +import { builder, command, handler, LOG_FILENAME, coerceLog } from './unarchive'; import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; -import { ContentRepository, ContentItem, Folder } from 'dc-management-sdk-js'; +import { ContentRepository, ContentItem, Folder, Status } from 'dc-management-sdk-js'; import Yargs from 'yargs/yargs'; import readline from 'readline'; import MockPage from '../../common/dc-management-sdk-js/mock-page'; import { dirname } from 'path'; import { promisify } from 'util'; -import { exists, readFile, unlink, mkdir, writeFile } from 'fs'; +import { unlink, mkdir, writeFile, readFile, existsSync } from 'fs'; +import * as fetchContentModule from '../../common/filter/fetch-content'; +import { FileLog, setVersion } from '../../common/file-log'; +import { createLog, getDefaultLogPath } from '../../common/log-helpers'; + +setVersion('test-ver'); jest.mock('readline'); jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../common/log-helpers', () => ({ + ...jest.requireActual('../../common/log-helpers'), + getDefaultLogPath: jest.fn() +})); + +jest.mock('../../common/filter/fetch-content'); + describe('content-item unarchive command', () => { afterEach((): void => { jest.restoreAllMocks(); @@ -32,7 +36,8 @@ describe('content-item unarchive command', () => { const config = { clientId: 'client-id', clientSecret: 'client-id', - hubId: 'hub-id' + hubId: 'hub-id', + logFile: new FileLog() }; const mockValues = ( @@ -46,6 +51,7 @@ describe('content-item unarchive command', () => { mockItemGetById: () => void; mockRepoGet: () => void; mockFolderGet: () => void; + mockGetContent: () => void; contentItems: ContentItem[]; } => { const mockGet = jest.fn(); @@ -56,6 +62,7 @@ describe('content-item unarchive command', () => { const mockItemGetById = jest.fn(); const mockRepoGet = jest.fn(); const mockFolderGet = jest.fn(); + const mockGetContent = jest.spyOn(fetchContentModule, 'getContent') as jest.Mock; const item = new ContentItem({ id: '1', @@ -131,8 +138,7 @@ describe('content-item unarchive command', () => { }, _links: { 'content-items': { - href: - 'https://api.amplience.net/v2/content/content-repositories/repo1/content-items{?folderId,page,projection,size,sort,status}', + href: 'https://api.amplience.net/v2/content/content-repositories/repo1/content-items{?folderId,page,projection,size,sort,status}', templated: true } }, @@ -162,8 +168,7 @@ describe('content-item unarchive command', () => { }, _links: { 'content-items': { - href: - 'https://api.amplience.net/v2/content/content-repositories/repo1/content-items{?folderId,page,projection,size,sort,status}', + href: 'https://api.amplience.net/v2/content/content-repositories/repo1/content-items{?folderId,page,projection,size,sort,status}', templated: true } }, @@ -184,8 +189,7 @@ describe('content-item unarchive command', () => { }, _links: { 'content-items': { - href: - 'https://api.amplience.net/v2/content/content-repositories/repo1/content-items{?folderId,page,projection,size,sort,status}', + href: 'https://api.amplience.net/v2/content/content-repositories/repo1/content-items{?folderId,page,projection,size,sort,status}', templated: true } }, @@ -202,6 +206,7 @@ describe('content-item unarchive command', () => { mockItemUpdate.mockResolvedValue(item); mockItemsList.mockResolvedValue(new MockPage(ContentItem, contentItems)); + mockGetContent.mockResolvedValue(contentItems); if (unarchiveError) { mockUnarchive.mockRejectedValue(new Error('Error')); @@ -218,16 +223,17 @@ describe('content-item unarchive command', () => { mockItemGetById, mockRepoGet, mockFolderGet, + mockGetContent, contentItems }; }; - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('unarchive [id]'); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); @@ -286,7 +292,8 @@ describe('content-item unarchive command', () => { expect(spyOption).toHaveBeenCalledWith('logFile', { type: 'string', default: LOG_FILENAME, - describe: 'Path to a log file to write to.' + describe: 'Path to a log file to write to.', + coerce: coerceLog }); expect(spyOption).toHaveBeenCalledWith('name', { @@ -298,15 +305,38 @@ describe('content-item unarchive command', () => { type: 'string', hidden: true }); + + expect(spyOption).toHaveBeenCalledWith('ignoreSchemaValidation', { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during unarchive' + }); }); }); - describe('handler tests', function() { + describe('handler tests', function () { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { + LOG_FILENAME(); + + expect(getDefaultLogPath).toHaveBeenCalledWith('content-item', 'unarchive', process.platform); + }); + + it('should generate a log with coerceLog with the appropriate title', function () { + const logFile = coerceLog('filename.log'); + + expect(logFile).toEqual(expect.any(FileLog)); + expect(logFile.title).toMatch(/^dc\-cli test\-ver \- Content Items Unarchive Log \- ./); + }); + it('should unarchive all content', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockGet, mockGetList, mockItemsList, mockUnarchive } = mockValues(); + const { mockGet, mockGetContent, mockUnarchive } = mockValues(); const argv = { ...yargArgs, @@ -315,9 +345,10 @@ describe('content-item unarchive command', () => { await handler(argv); expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockUnarchive).toBeCalledTimes(2); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + status: Status.ARCHIVED + }); + expect(mockUnarchive).toHaveBeenCalledTimes(2); }); it('should unarchive content by id', async () => { @@ -335,7 +366,7 @@ describe('content-item unarchive command', () => { await handler(argv); expect(mockItemGetById).toHaveBeenCalled(); - expect(mockUnarchive).toBeCalledTimes(1); + expect(mockUnarchive).toHaveBeenCalledTimes(1); }); it("shouldn't unarchive content by id", async () => { @@ -352,14 +383,14 @@ describe('content-item unarchive command', () => { await handler(argv); expect(mockItemGetById).toHaveBeenCalled(); - expect(mockUnarchive).not.toBeCalled(); + expect(mockUnarchive).not.toHaveBeenCalled(); }); it('should unarchive content by repo id', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockUnarchive, mockRepoGet } = mockValues(); + const { mockUnarchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -368,15 +399,18 @@ describe('content-item unarchive command', () => { }; await handler(argv); - expect(mockRepoGet).toBeCalledTimes(1); - expect(mockUnarchive).toBeCalledTimes(2); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + repoId: 'repo1', + status: Status.ARCHIVED + }); + expect(mockUnarchive).toHaveBeenCalledTimes(2); }); it('should unarchive content by repo ids', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockUnarchive, mockRepoGet } = mockValues(); + const { mockUnarchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -385,15 +419,18 @@ describe('content-item unarchive command', () => { }; await handler(argv); - expect(mockRepoGet).toBeCalledTimes(2); - expect(mockUnarchive).toBeCalledTimes(4); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + repoId: ['repo1', 'repo2'], + status: Status.ARCHIVED + }); + expect(mockUnarchive).toHaveBeenCalledTimes(2); }); it('should unarchive content by folder id', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockUnarchive, mockFolderGet, mockItemsList } = mockValues(); + const { mockUnarchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -403,16 +440,19 @@ describe('content-item unarchive command', () => { }; await handler(argv); - expect(mockFolderGet).toBeCalledTimes(1); - expect(mockItemsList).toBeCalledTimes(1); - expect(mockUnarchive).toBeCalledTimes(2); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + repoId: 'repo123', + folderId: 'folder1', + status: Status.ARCHIVED + }); + expect(mockUnarchive).toHaveBeenCalledTimes(2); }); it('should unarchive content by folder ids', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockUnarchive, mockFolderGet, mockItemsList } = mockValues(); + const { mockUnarchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -421,16 +461,18 @@ describe('content-item unarchive command', () => { }; await handler(argv); - expect(mockFolderGet).toBeCalledTimes(2); - expect(mockItemsList).toBeCalledTimes(2); - expect(mockUnarchive).toBeCalledTimes(4); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + folderId: ['folder1', 'folder1'], + status: Status.ARCHIVED + }); + expect(mockUnarchive).toHaveBeenCalledTimes(2); }); it('should unarchive content by name', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockUnarchive, mockFolderGet, mockItemsList } = mockValues(); + const { mockUnarchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -440,16 +482,18 @@ describe('content-item unarchive command', () => { }; await handler(argv); - expect(mockFolderGet).toBeCalledTimes(1); - expect(mockItemsList).toBeCalledTimes(1); - expect(mockUnarchive).toBeCalledTimes(1); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), 'name:item1', { + folderId: 'folder1', + status: Status.ARCHIVED + }); + expect(mockUnarchive).toHaveBeenCalledTimes(2); }); it('should exit if a facet AND id are provided', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockUnarchive, mockFolderGet, mockItemsList } = mockValues(); + const { mockUnarchive, mockFolderGet, mockItemsList, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -459,16 +503,20 @@ describe('content-item unarchive command', () => { }; await handler(argv); - expect(mockFolderGet).not.toBeCalled(); - expect(mockItemsList).not.toBeCalled(); - expect(mockUnarchive).not.toBeCalled(); + expect(mockGetContent).not.toHaveBeenCalled(); + expect(mockFolderGet).not.toHaveBeenCalled(); + expect(mockItemsList).not.toHaveBeenCalled(); + expect(mockUnarchive).not.toHaveBeenCalled(); }); - it("shouldn't unarchive content by name", async () => { + it("shouldn't unarchive content when facet returns none", async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockUnarchive, mockFolderGet, mockItemsList } = mockValues(); + const { mockUnarchive, mockGetContent } = mockValues(); + + (mockGetContent as jest.Mock).mockReset(); + (mockGetContent as jest.Mock).mockResolvedValue([]); const argv = { ...yargArgs, @@ -478,16 +526,18 @@ describe('content-item unarchive command', () => { }; await handler(argv); - expect(mockFolderGet).toBeCalledTimes(1); - expect(mockItemsList).toBeCalledTimes(1); - expect(mockUnarchive).not.toBeCalled(); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), 'name:item3', { + folderId: 'folder1', + status: Status.ARCHIVED + }); + expect(mockUnarchive).not.toHaveBeenCalled(); }); it("shouldn't unarchive content, answer no", async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['n']); - const { mockUnarchive, mockFolderGet, mockItemsList } = mockValues(); + const { mockUnarchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, @@ -497,201 +547,245 @@ describe('content-item unarchive command', () => { }; await handler(argv); - expect(mockFolderGet).toBeCalledTimes(1); - expect(mockItemsList).toBeCalledTimes(1); - expect(mockUnarchive).not.toBeCalled(); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), 'name:item1', { + folderId: 'folder1', + status: Status.ARCHIVED + }); + expect(mockUnarchive).not.toHaveBeenCalled(); }); - it('should unarchive content by name regexp', async () => { + it('should unarchive content by content type name', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockGet, mockGetList, mockUnarchive, mockItemsList } = mockValues(); + const { mockUnarchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, ...config, - facet: 'name:/item/' + facet: 'schema:http://test.com' }; await handler(argv); - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockUnarchive).toBeCalledTimes(2); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), 'schema:http://test.com', { + status: Status.ARCHIVED + }); + expect(mockUnarchive).toHaveBeenCalledTimes(2); }); - it('should unarchive content by content type name', async () => { + it('should unarchive content with ignoreError', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockGet, mockGetList, mockUnarchive, mockItemsList } = mockValues(); + const { mockUnarchive, mockGetContent } = mockValues(true); const argv = { ...yargArgs, ...config, - facet: 'schema:http://test.com' + ignoreError: true }; await handler(argv); - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockUnarchive).toBeCalledTimes(1); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + status: Status.ARCHIVED + }); + expect(mockUnarchive).toHaveBeenCalledTimes(2); }); - it('should unarchive content by content type regexp', async () => { + it("shouldn't unarchive content with ignoreError", async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockGet, mockGetList, mockUnarchive, mockItemsList } = mockValues(); + const { mockUnarchive, mockGetContent } = mockValues(true); const argv = { ...yargArgs, ...config, - facet: 'schema:/test/' + ignoreError: false }; await handler(argv); - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockUnarchive).toBeCalledTimes(2); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + status: Status.ARCHIVED + }); + expect(mockUnarchive).toHaveBeenCalledTimes(1); }); - it("shouldn't unarchive content by content type regexp", async () => { + it('should unarchive content items without asking if --force is provided', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any - (readline as any).setResponses(['y']); + (readline as any).setResponses(['input', 'ignored']); - const { mockGet, mockGetList, mockUnarchive, mockItemsList } = mockValues(); + const { mockUnarchive, mockGetContent } = mockValues(); const argv = { ...yargArgs, ...config, - facet: 'schema:/test123/' + force: true }; await handler(argv); - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockUnarchive).toBeCalledTimes(0); + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + status: Status.ARCHIVED + }); + expect(mockUnarchive).toHaveBeenCalledTimes(2); }); - it('should unarchive content with ignoreError', async () => { + it('should unarchive content items specified in the provided --revertLog maintaining deliveryKey', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockGet, mockGetList, mockUnarchive, mockItemsList } = mockValues(true); + const logFileName = `temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`; + const log = '// Type log test file\n' + 'ARCHIVE 1\n' + 'ARCHIVE 2 delivery-key\n' + 'ARCHIVE idMissing\n'; + + const dir = dirname(logFileName); + if (!existsSync(dir)) { + await promisify(mkdir)(dir); + } + await promisify(writeFile)(logFileName, log); + + const { mockUnarchive, mockItemUpdate, mockItemGetById, contentItems } = mockValues(); + + (mockItemGetById as jest.Mock).mockReset(); + (mockItemGetById as jest.Mock).mockResolvedValueOnce(contentItems[0]); + (mockItemGetById as jest.Mock).mockResolvedValueOnce(contentItems[1]); + (mockItemGetById as jest.Mock).mockRejectedValue(new Error("Couldn't locate item")); const argv = { ...yargArgs, ...config, - ignoreError: true + silent: true, + force: true, + revertLog: logFileName }; await handler(argv); - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockUnarchive).toBeCalledTimes(2); + expect(mockItemGetById).toHaveBeenNthCalledWith(1, '1'); + expect(mockItemGetById).toHaveBeenNthCalledWith(2, '2'); + expect(mockItemGetById).toHaveBeenNthCalledWith(3, 'idMissing'); + expect(mockItemUpdate).toHaveBeenCalled(); + const updateItem: ContentItem = (mockItemUpdate as jest.Mock).mock.calls[0][0]; + expect(updateItem.body._meta.deliveryKey).toEqual('delivery-key'); + expect(mockUnarchive).toHaveBeenCalledTimes(2); }); - it("shouldn't unarchive content with ignoreError", async () => { + it('should unarchive content items specified in the provided --revertLog maintaining deliveryKeys', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - const { mockGet, mockGetList, mockUnarchive, mockItemsList } = mockValues(true); - - const argv = { - ...yargArgs, - ...config, - ignoreError: false - }; - await handler(argv); + const logFileName = `temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`; + const log = + '// Type log test file\n' + + 'ARCHIVE 1\n' + + 'ARCHIVE 2 delivery-key-1,delivery-key-2\n' + + 'ARCHIVE idMissing\n'; - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockUnarchive).toBeCalledTimes(1); - }); + const dir = dirname(logFileName); + if (!existsSync(dir)) { + await promisify(mkdir)(dir); + } + await promisify(writeFile)(logFileName, log); - it('should unarchive content items without asking if --force is provided', async () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (readline as any).setResponses(['input', 'ignored']); + const { mockUnarchive, mockItemUpdate, mockItemGetById, contentItems } = mockValues(); - const { mockGet, mockGetList, mockUnarchive, mockItemsList } = mockValues(); + (mockItemGetById as jest.Mock).mockReset(); + (mockItemGetById as jest.Mock).mockResolvedValueOnce(contentItems[0]); + (mockItemGetById as jest.Mock).mockResolvedValueOnce(contentItems[1]); + (mockItemGetById as jest.Mock).mockRejectedValue(new Error("Couldn't locate item")); const argv = { ...yargArgs, ...config, - force: true + silent: true, + force: true, + revertLog: logFileName }; await handler(argv); - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockUnarchive).toBeCalledTimes(2); + expect(mockItemGetById).toHaveBeenNthCalledWith(1, '1'); + expect(mockItemGetById).toHaveBeenNthCalledWith(2, '2'); + expect(mockItemGetById).toHaveBeenNthCalledWith(3, 'idMissing'); + expect(mockItemUpdate).toHaveBeenCalled(); + const updateItem: ContentItem = (mockItemUpdate as jest.Mock).mock.calls[0][0]; + expect(updateItem.body._meta.deliveryKeys).toEqual({ + values: [{ value: 'delivery-key-1' }, { value: 'delivery-key-2' }] + }); + expect(mockUnarchive).toHaveBeenCalledTimes(2); }); - it('should unarchive content items specified in the provided --revertLog', async () => { + it('should unarchive content items specified in the provided --revertLog maintaining deliveryKey and deliveryKeys', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); const logFileName = `temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`; - const log = '// Type log test file\n' + 'ARCHIVE 1\n' + 'ARCHIVE 2 delivery-key\n' + 'ARCHIVE idMissing'; + const log = + '// Type log test file\n' + + 'ARCHIVE 1\n' + + 'ARCHIVE 2 delivery-key delivery-key-1,delivery-key-2\n' + + 'ARCHIVE idMissing\n'; const dir = dirname(logFileName); - if (!(await promisify(exists)(dir))) { + if (!existsSync(dir)) { await promisify(mkdir)(dir); } await promisify(writeFile)(logFileName, log); - const { mockGet, mockGetList, mockUnarchive, mockItemsList, mockItemUpdate } = mockValues(); + const { mockUnarchive, mockItemUpdate, mockItemGetById, contentItems } = mockValues(); + + (mockItemGetById as jest.Mock).mockReset(); + (mockItemGetById as jest.Mock).mockResolvedValueOnce(contentItems[0]); + (mockItemGetById as jest.Mock).mockResolvedValueOnce(contentItems[1]); + (mockItemGetById as jest.Mock).mockRejectedValue(new Error("Couldn't locate item")); const argv = { ...yargArgs, ...config, - logFile: LOG_FILENAME(), silent: true, force: true, revertLog: logFileName }; await handler(argv); - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); + expect(mockItemGetById).toHaveBeenNthCalledWith(1, '1'); + expect(mockItemGetById).toHaveBeenNthCalledWith(2, '2'); + expect(mockItemGetById).toHaveBeenNthCalledWith(3, 'idMissing'); expect(mockItemUpdate).toHaveBeenCalled(); const updateItem: ContentItem = (mockItemUpdate as jest.Mock).mock.calls[0][0]; expect(updateItem.body._meta.deliveryKey).toEqual('delivery-key'); - expect(mockUnarchive).toBeCalledTimes(2); + expect(updateItem.body._meta.deliveryKeys).toEqual({ + values: [{ value: 'delivery-key-1' }, { value: 'delivery-key-2' }] + }); + expect(mockUnarchive).toHaveBeenCalledTimes(2); }); - it("shouldn't unarchive content items, getFolder error", async () => { + it("shouldn't unarchive content items, getFacet error", async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['input', 'ignored']); - const { mockFolderGet, mockUnarchive, mockItemsList } = mockValues(true); + const { mockGetContent, mockUnarchive } = mockValues(true); + + (mockGetContent as jest.Mock).mockReset(); + (mockGetContent as jest.Mock).mockRejectedValue(new Error('Simulated error')); const argv = { ...yargArgs, ...config, folderId: 'folder1' }; - await handler(argv); - expect(mockFolderGet).toBeCalledTimes(1); - expect(mockItemsList).not.toBeCalled(); - expect(mockUnarchive).not.toBeCalled(); + await expect(handler(argv)).rejects.toThrowErrorMatchingInlineSnapshot(`"Simulated error"`); + + expect(mockGetContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Object), undefined, { + folderId: 'folder1', + status: Status.ARCHIVED + }); + expect(mockUnarchive).not.toHaveBeenCalled(); }); it("shouldn't unarchive content items, revertLog error", async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - if (await promisify(exists)(`temp_${process.env.JEST_WORKER_ID}/content-item-archive.log`)) { + if (existsSync(`temp_${process.env.JEST_WORKER_ID}/content-item-archive.log`)) { await promisify(unlink)(`temp_${process.env.JEST_WORKER_ID}/content-item-archive.log`); } @@ -699,34 +793,34 @@ describe('content-item unarchive command', () => { const log = '// Type log test file\n' + 'ARCHIVE 1\n' + 'ARCHIVE 2\n' + 'ARCHIVE idMissing'; const dir = dirname(logFileName); - if (!(await promisify(exists)(dir))) { + if (!existsSync(dir)) { await promisify(mkdir)(dir); } await promisify(writeFile)(logFileName, log); - const { mockGet, mockGetList, mockUnarchive, mockItemsList } = mockValues(true); + const { mockUnarchive, mockItemGetById, mockGetContent } = mockValues(true); const argv = { ...yargArgs, ...config, - logFile: LOG_FILENAME(), silent: true, force: true, revertLog: 'wrongFileName.log' }; - await handler(argv); + await expect(handler(argv)).rejects.toThrowErrorMatchingInlineSnapshot( + `"ENOENT: no such file or directory, open 'wrongFileName.log'"` + ); - expect(mockGet).toHaveBeenCalled(); - expect(mockGetList).toHaveBeenCalled(); - expect(mockItemsList).toHaveBeenCalled(); - expect(mockUnarchive).not.toBeCalled(); + expect(mockItemGetById).not.toHaveBeenCalled(); + expect(mockGetContent).not.toHaveBeenCalled(); + expect(mockUnarchive).not.toHaveBeenCalled(); }); it('should unarchive content items, write log file', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); - if (await promisify(exists)(`temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`)) { + if (existsSync(`temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`)) { await promisify(unlink)(`temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`); } @@ -735,16 +829,16 @@ describe('content-item unarchive command', () => { const argv = { ...yargArgs, ...config, - logFile: `temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`, + logFile: createLog(`temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`), id: '1' }; await handler(argv); expect(mockItemGetById).toHaveBeenCalled(); - expect(mockUnarchive).toBeCalled(); + expect(mockUnarchive).toHaveBeenCalled(); - const logExists = await promisify(exists)(`temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`); + const logExists = existsSync(`temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`); expect(logExists).toBeTruthy(); @@ -762,161 +856,87 @@ describe('content-item unarchive command', () => { await promisify(unlink)(`temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`); }); - }); - - describe('getContentItems tests', () => { - it('should get content items by id', async () => { - const result = await getContentItems({ - client: dynamicContentClientFactory({ - ...config, - ...yargArgs - }), - id: '1', - hubId: 'hub1' - }); - - if (result) { - expect(result.contentItems.length).toBeGreaterThanOrEqual(1); - - expect(result.contentItems[0].id).toMatch('1'); - } - }); - - it('should get content items all', async () => { - const result = await getContentItems({ - client: dynamicContentClientFactory({ - ...config, - ...yargArgs - }), - hubId: 'hub1' - }); - - if (result) { - expect(result.contentItems.length).toBe(2); - } - }); - - it('should get content items by repo', async () => { - const result = await getContentItems({ - client: dynamicContentClientFactory({ - ...config, - ...yargArgs - }), - hubId: 'hub1', - repoId: 'repo1' - }); - if (result) { - expect(result.contentItems.length).toBe(2); - } - }); + it('should unarchive content items and ignore schema validation on content item update', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['y']); - it('should get content items by folder', async () => { - const result = await getContentItems({ - client: dynamicContentClientFactory({ - ...config, - ...yargArgs - }), - hubId: 'hub1', - folderId: 'folder1' - }); + const logFileName = `temp_${process.env.JEST_WORKER_ID}/content-item-unarchive.log`; + const log = '// Type log test file\n' + 'ARCHIVE 1 delivery-key\n'; - if (result) { - expect(result.contentItems.length).toBe(2); + const dir = dirname(logFileName); + if (!existsSync(dir)) { + await promisify(mkdir)(dir); } - }); - }); - - describe('filterContentItems tests', () => { - it('should filter content items', async () => { - const { contentItems } = mockValues(); - - const result = await filterContentItems({ - contentItems - }); - - expect(result).toMatchObject({ - contentItems, - missingContent: false - }); - }); - - it('should filter content items by content type', async () => { - const { contentItems } = mockValues(); - - const result = await filterContentItems({ - contentItems, - facet: 'schema:/test.com/' - }); - - expect(result).toMatchObject({ - contentItems: [contentItems[0]], - missingContent: false - }); - }); - - it('should filter content items by content types', async () => { - const { contentItems } = mockValues(); - - const result = await filterContentItems({ - contentItems, - facet: 'schema:/test.?\\.com/' - }); - - expect(result).toMatchObject({ - contentItems, - missingContent: false - }); - }); + await promisify(writeFile)(logFileName, log); - it('should filter content items by name', async () => { - const { contentItems } = mockValues(); + const { mockUnarchive, mockItemUpdate, mockItemGetById, contentItems } = mockValues(); - const result = await filterContentItems({ - contentItems, - facet: 'name:/item1/' + (mockItemGetById as jest.Mock).mockReset(); + (mockItemGetById as jest.Mock).mockResolvedValueOnce(contentItems[0]); + const unarchivedContentItem = new ContentItem({ + id: '1', + label: 'item1', + repoId: 'repo1', + folderId: 'folder1', + status: 'ARCHIVED', + body: { + _meta: { + schema: 'http://test.com' + } + }, + client: { + updateLinkedResource: mockItemUpdate + }, + _links: { + archive: { + href: 'https://api.amplience.net/v2/content/content-items/1/unarchive' + }, + update: { + href: 'https://api.amplience.net/v2/content/content-items/1' + } + } }); + (mockUnarchive as jest.Mock).mockResolvedValueOnce(unarchivedContentItem); - if (result) { - expect(result.contentItems.length).toBeGreaterThanOrEqual(1); + const argv = { + ...yargArgs, + ...config, + silent: true, + force: true, + revertLog: logFileName, + ignoreSchemaValidation: true + }; + await handler(argv); - expect(result.contentItems[0].id).toMatch('1'); - } + expect(mockItemGetById).toHaveBeenNthCalledWith(1, '1'); + expect(mockItemUpdate).toHaveBeenCalledTimes(1); + expect((mockItemUpdate as jest.Mock).mock.calls[0][1].ignoreSchemaValidation).toBe(true); }); - }); - - describe('processItems tests', () => { - it('should unarchive content items', async () => { - const { contentItems, mockUnarchive } = mockValues(); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (readline as any).setResponses(['y']); - await processItems({ - contentItems, - allContent: true, - missingContent: false, - logFile: './logFile.log' + it('should not archive content items', async () => { + const { mockItemGetById, mockUnarchive } = mockValues(); + const logFile = new FileLog(); + const mockAppendFile = jest.fn(); + logFile.open = jest.fn().mockImplementation(() => { + return { + appendLine: mockAppendFile + }; }); + const argv = { + ...yargArgs, + ...config, + id: 'repo123', + logFile + }; - expect(mockUnarchive).toBeCalledTimes(2); - - if (await promisify(exists)('./logFile.log')) { - await promisify(unlink)('./logFile.log'); - } - }); - - it('should not unarchive content items', async () => { - jest.spyOn(global.console, 'log'); + (mockItemGetById as jest.Mock).mockResolvedValue([]); - await processItems({ - contentItems: [], - allContent: true, - missingContent: false - }); + await handler(argv); - expect(console.log).toBeCalled(); - expect(console.log).toHaveBeenLastCalledWith('Nothing found to unarchive, aborting.'); + expect(mockUnarchive).not.toHaveBeenCalled(); + expect(mockAppendFile).toHaveBeenCalled(); + expect(mockAppendFile).toHaveBeenLastCalledWith('Nothing found to unarchive, aborting'); }); }); }); diff --git a/src/commands/content-item/unarchive.ts b/src/commands/content-item/unarchive.ts index 697b038d..0df72017 100644 --- a/src/commands/content-item/unarchive.ts +++ b/src/commands/content-item/unarchive.ts @@ -2,12 +2,16 @@ import { Arguments, Argv } from 'yargs'; import { ConfigurationParameters } from '../configure'; import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; import { ArchiveLog } from '../../common/archive/archive-log'; -import paginator from '../../common/dc-management-sdk-js/paginator'; -import { confirmArchive } from '../../common/archive/archive-helpers'; -import UnarchiveOptions from '../../common/archive/unarchive-options'; -import { ContentItem, DynamicContent, Status } from 'dc-management-sdk-js'; -import { getDefaultLogPath } from '../../common/log-helpers'; -import { applyFacet, withOldFilters } from '../../common/filter/facet'; +import { confirmAllContent } from '../../common/content-item/confirm-all-content'; +import { ContentItem, DynamicContent, FacetedContentItem, Status } from 'dc-management-sdk-js'; +import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { Facet, withOldFilters } from '../../common/filter/facet'; +import { getContent } from '../../common/filter/fetch-content'; +import { isEqual } from 'lodash'; +import { getContentByIds } from '../../common/content-item/get-content-items-by-ids'; +import { FileLog } from '../../common/file-log'; +import { progressBar } from '../../common/progress-bar/progress-bar'; +import ContentItemUnarchiveOptions from '../../common/archive/content-item-unarchive-options'; export const command = 'unarchive [id]'; @@ -16,6 +20,8 @@ export const desc = 'Unarchive Content Items'; export const LOG_FILENAME = (platform: string = process.platform): string => getDefaultLogPath('content-item', 'unarchive', platform); +export const coerceLog = (logFile: string): FileLog => createLog(logFile, 'Content Items Unarchive Log'); + export const builder = (yargs: Argv): void => { yargs .positional('id', { @@ -64,7 +70,8 @@ export const builder = (yargs: Argv): void => { .option('logFile', { type: 'string', default: LOG_FILENAME, - describe: 'Path to a log file to write to.' + describe: 'Path to a log file to write to.', + coerce: coerceLog }) .option('name', { type: 'string', @@ -73,261 +80,209 @@ export const builder = (yargs: Argv): void => { .option('schemaId', { type: 'string', hidden: true + }) + .option('ignoreSchemaValidation', { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during unarchive' }); }; -export const filterContentItems = async ({ - revertLog, - facet, - contentItems +const getContentToUnarchiveWithIds = async ({ + client, + ids, + revertItems }: { - revertLog?: string; - facet?: string; - contentItems: ContentItem[]; -}): Promise<{ contentItems: ContentItem[]; missingContent: boolean } | undefined> => { - try { - let missingContent = false; - - if (revertLog != null) { - const log = await new ArchiveLog().loadFromFile(revertLog); - const archived = log.getData('ARCHIVE'); - const items = archived.map(args => args.split(' ')); - - // The archive actions may include delivery keys that were removed. - // Add these back to the content item, which will cause the unarchive to assign them later. - const contentItemsFiltered = contentItems - .map(contentItem => { - const entry = items.find(item => item[0] === contentItem.id || ''); - if (entry) { - contentItem.body._meta.deliveryKey = entry[1]; - return contentItem; - } else { - return null; - } - }) - .filter(contentItem => !!contentItem); - - missingContent = contentItems.length !== archived.length; - - return { - contentItems: contentItemsFiltered as ContentItem[], - missingContent - }; - } - - // Delete the delivery keys, as the unarchive will attempt to reassign them if present. - contentItems.forEach(item => delete item.body._meta.deliveryKey); + client: DynamicContent; + ids: string[]; + revertItems?: string[][]; +}) => { + let contentItemIds = ids; - if (facet != null) { - const contentItemsFiltered = applyFacet(contentItems, facet); + if (revertItems?.length) { + contentItemIds = revertItems.map(item => item[0]); + } - return { - contentItems: contentItemsFiltered, - missingContent - }; + const contentItems = await getContentByIds(client, contentItemIds); + const contentItemsWithRevert = contentItems.map(item => { + const revertItem = revertItems?.find(revertItem => item.id === revertItem[0]); + if (revertItem) { + const [, key, keys] = revertItem; + const deliveryKeys = keys?.split(',') || []; + item.body._meta.deliveryKey = key || null; + if (keys?.length) { + item.body._meta.deliveryKeys = { + values: deliveryKeys.map(k => ({ value: k })) + }; + } } + return item; + }); - return { - contentItems, - missingContent - }; - } catch (err) { - console.log(err); - return { - contentItems: [], - missingContent: false - }; - } + return contentItemsWithRevert.filter(item => item.status === Status.ARCHIVED); }; -export const getContentItems = async ({ +const getContentToUnarchiveWithFacet = async ({ client, - id, hubId, + facet, repoId, - folderId, - revertLog, - facet + folderId }: { client: DynamicContent; - id?: string; hubId: string; + facet?: Facet | string | undefined; repoId?: string | string[]; folderId?: string | string[]; - revertLog?: string; - facet?: string; -}): Promise<{ contentItems: ContentItem[]; missingContent: boolean }> => { - try { - const contentItems: ContentItem[] = []; - - if (id != null) { - contentItems.push(await client.contentItems.get(id)); - - return { - contentItems, - missingContent: false - }; +}) => { + const hub = await client.hubs.get(hubId); + const contentItems = await getContent(client, hub, facet, { repoId, folderId, status: Status.ARCHIVED }); + + // Delete the delivery keys, as the unarchive will attempt to reassign them if present. + contentItems.forEach(item => { + if (item instanceof ContentItem) { + delete item.body._meta.deliveryKey; + delete item.body._meta.deliveryKeys; } - - const hub = await client.hubs.get(hubId); - const repoIds = typeof repoId === 'string' ? [repoId] : repoId || []; - const folderIds = typeof folderId === 'string' ? [folderId] : folderId || []; - const contentRepositories = await (repoId != null - ? Promise.all(repoIds.map(id => client.contentRepositories.get(id))) - : paginator(hub.related.contentRepositories.list)); - - const folders = folderId != null ? await Promise.all(folderIds.map(id => client.folders.get(id))) : []; - - folderId != null - ? await Promise.all( - folders.map(async source => { - const items = await paginator(source.related.contentItems.list, { status: Status.ARCHIVED }); - contentItems.push(...items); - }) - ) - : await Promise.all( - contentRepositories.map(async source => { - const items = await paginator(source.related.contentItems.list, { status: Status.ARCHIVED }); - contentItems.push(...items); - }) - ); - - return ( - (await filterContentItems({ - revertLog, - facet, - contentItems - })) || { - contentItems: [], - missingContent: false + if (item instanceof FacetedContentItem) { + if ('deliveryKey' in item) { + delete item.deliveryKey; } - ); - } catch (err) { - console.log(err); - - return { - contentItems: [], - missingContent: false - }; - } + if ('deliveryKeys' in item) { + delete item.deliveryKeys; + } + } + }); + + return contentItems; }; -export const processItems = async ({ +const processItems = async ({ contentItems, - force, - silent, - logFile, - allContent, - missingContent, - ignoreError + log, + ignoreError, + ignoreSchemaValidation }: { contentItems: ContentItem[]; - force?: boolean; - silent?: boolean; - logFile?: string; - allContent: boolean; - missingContent: boolean; + log: FileLog; ignoreError?: boolean; -}): Promise => { - if (contentItems.length == 0) { - console.log('Nothing found to unarchive, aborting.'); - return; - } - - console.log('The following content items will be unarchived:'); - contentItems.forEach((contentItem: ContentItem) => { - console.log(` ${contentItem.label} (${contentItem.id})`); - }); - console.log(`Total: ${contentItems.length}`); - - if (!force) { - const yes = await confirmArchive('unarchive', 'content item', allContent, missingContent); - if (!yes) { - return; - } - } - - const timestamp = Date.now().toString(); - const log = new ArchiveLog(`Content Items Unarchive Log - ${timestamp}\n`); - - let successCount = 0; + ignoreSchemaValidation?: boolean; +}): Promise<{ failedUnarchives: ContentItem[] }> => { + const progress = progressBar(contentItems.length, 0, { title: 'Unarchiving content items' }); + const failedUnarchives: ContentItem[] = []; for (let i = 0; i < contentItems.length; i++) { try { - const deliveryKey = contentItems[i].body._meta.deliveryKey; + const deliveryKey = contentItems[i].body?._meta?.deliveryKey; + const deliveryKeys = contentItems[i].body?._meta?.deliveryKeys; contentItems[i] = await contentItems[i].related.unarchive(); - if (contentItems[i].body._meta.deliveryKey != deliveryKey) { + if ( + contentItems[i].body?._meta?.deliveryKey !== deliveryKey || + !isEqual(contentItems[i].body?._meta?.deliveryKeys, deliveryKeys) + ) { // Restore the delivery key if present. (only on ARCHIVE revert) - contentItems[i].body._meta.deliveryKey = deliveryKey; - await contentItems[i].related.update(contentItems[i]); + contentItems[i].body._meta.deliveryKey = deliveryKey || null; + contentItems[i].body._meta.deliveryKeys = deliveryKeys; + const updateParams = { ...(ignoreSchemaValidation ? { ignoreSchemaValidation: true } : {}) }; + await contentItems[i].related.update(contentItems[i], updateParams); } log.addAction('UNARCHIVE', `${contentItems[i].id}\n`); - successCount++; + progress.increment(); } catch (e) { + failedUnarchives.push(contentItems[i]); + progress.increment(); log.addComment(`UNARCHIVE FAILED: ${contentItems[i].id}`); log.addComment(e.toString()); if (ignoreError) { log.warn(`Failed to unarchive ${contentItems[i].label} (${contentItems[i].id}), continuing.`, e); } else { + progress.stop(); log.error(`Failed to unarchive ${contentItems[i].label} (${contentItems[i].id}), aborting.`, e); break; } } } - if (!silent && logFile) { - await log.writeToFile(logFile.replace('', timestamp)); - } + progress.stop(); - console.log(`Unarchived ${successCount} content items.`); + return { failedUnarchives }; }; -export const handler = async (argv: Arguments): Promise => { - const { id, logFile, force, silent, ignoreError, hubId, revertLog, repoId, folderId } = argv; +export const handler = async ( + argv: Arguments +): Promise => { + const { id, logFile, force, silent, ignoreError, hubId, revertLog, repoId, folderId, ignoreSchemaValidation } = argv; + const log = logFile.open(); const facet = withOldFilters(argv.facet, argv); const client = dynamicContentClientFactory(argv); - const allContent = !id && !facet && !revertLog && !folderId && !repoId; if (repoId && id) { - console.log('ID of content item is specified, ignoring repository ID'); + log.appendLine('ID of content item is specified, ignoring repository ID'); } if (id && facet) { - console.log('Please specify either a facet or an ID - not both.'); + log.appendLine('Please specify either a facet or an ID - not both.'); return; } if (repoId && folderId) { - console.log('Folder is specified, ignoring repository ID'); + log.appendLine('Folder is specified, ignoring repository ID'); } if (allContent) { - console.log('No filter was given, archiving all content'); + log.appendLine('No filter was given, archiving all content'); } - const { contentItems, missingContent } = await getContentItems({ - client, - id, - hubId, - repoId, - folderId, - revertLog, - facet - }); + let ids: string[] = []; + let revertItems: string[][] = []; + + if (id) { + ids = Array.isArray(id) ? id : [id]; + } + + if (revertLog) { + const log = await new ArchiveLog().loadFromFile(revertLog); + revertItems = log.getData('ARCHIVE').map(args => args.split(' ')); + ids = revertItems.map(item => item[0]); + } + + const contentItems = ids.length + ? await getContentToUnarchiveWithIds({ client, ids, revertItems }) + : await getContentToUnarchiveWithFacet({ client, hubId, facet, repoId, folderId }); - await processItems({ + if (!contentItems.length) { + log.appendLine('Nothing found to unarchive, aborting'); + return; + } + + const missingContentItems = ids.length > 0 ? Boolean(ids.length !== contentItems.length) : false; + logFile.appendLine(`Found ${contentItems.length} content items to unarchive`); + + if (!force) { + const yes = await confirmAllContent('unarchive', 'content item', allContent, missingContentItems); + if (!yes) { + return; + } + } + + const { failedUnarchives } = await processItems({ contentItems, - force, - silent, - logFile, - allContent, - missingContent, - ignoreError + log, + ignoreError, + ignoreSchemaValidation }); + + const failedUnarchiveMsg = failedUnarchives.length + ? `with ${failedUnarchives.length} failed archives - check logs for details` + : ``; + + log.appendLine(`Unarchived content items ${failedUnarchiveMsg}`); + + await log.close(!silent); }; // log format: diff --git a/src/commands/content-item/unpublish.spec.ts b/src/commands/content-item/unpublish.spec.ts new file mode 100644 index 00000000..dfcc4fd0 --- /dev/null +++ b/src/commands/content-item/unpublish.spec.ts @@ -0,0 +1,285 @@ +import { builder, handler, LOG_FILENAME, coerceLog } from './unpublish'; +import { ContentItem, Hub, PublishingJob, Job, ContentItemPublishingStatus } from 'dc-management-sdk-js'; +import { FileLog } from '../../common/file-log'; +import Yargs from 'yargs/yargs'; +import { PublishingJobStatus } from 'dc-management-sdk-js/build/main/lib/model/PublishingJobStatus'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { getContentByIds } from '../../common/content-item/get-content-items-by-ids'; +import { getContent } from '../../common/filter/fetch-content'; +import * as confirmAllContentModule from '../../common/content-item/confirm-all-content'; +import * as questionHelpers from '../../common/question-helpers'; + +const mockUnpublish = jest.fn().mockImplementation((contentItems, fn) => { + fn(contentItems, new PublishingJob({ state: PublishingJobStatus.CREATED })); +}); +const mockUnpublishOnIdle = jest.fn().mockImplementation(() => Promise.resolve()); + +const confirmAllContentSpy = jest.spyOn(confirmAllContentModule, 'confirmAllContent'); +const asyncQuestionSpy = jest.spyOn(questionHelpers, 'asyncQuestion'); + +jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../common/log-helpers'); +jest.mock('../../common/filter/fetch-content'); +jest.mock('../../common/content-item/get-content-items-by-ids', () => { + return { + getContentByIds: jest.fn() + }; +}); +jest.mock('../../common/publishing/content-item-unpublishing-service', () => { + return { + ContentItemUnpublishingService: jest.fn().mockImplementation(() => { + return { + unpublish: mockUnpublish, + onIdle: mockUnpublishOnIdle + }; + }) + }; +}); + +describe('unpublish tests', () => { + describe('builder tests', () => { + it('should configure yargs', function () { + const argv = Yargs(process.argv.slice(2)); + const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); + const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); + + builder(argv); + + expect(spyPositional).toHaveBeenCalledWith('id', { + type: 'string', + describe: + 'The ID of a content item to be unpublished. If id is not provided, this command will unpublish ALL content items through all content repositories in the hub.' + }); + + expect(spyOption).toHaveBeenCalledWith('repoId', { + type: 'string', + describe: 'The ID of a content repository to search items in to be unpublished.', + requiresArg: false + }); + + expect(spyOption).toHaveBeenCalledWith('folderId', { + type: 'string', + describe: 'The ID of a folder to search items in to be unpublished.', + requiresArg: false + }); + + expect(spyOption).toHaveBeenCalledWith('facet', { + type: 'string', + describe: + "Unpublish content matching the given facets. Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values. A regex can be provided for text filters, surrounded with forward slashes. For more examples, see the readme." + }); + + expect(spyOption).toHaveBeenCalledWith('f', { + type: 'boolean', + boolean: true, + describe: 'If present, there will be no confirmation prompt before unpublishing the found content.' + }); + + expect(spyOption).toHaveBeenCalledWith('s', { + type: 'boolean', + boolean: true, + describe: 'If present, no log file will be produced.' + }); + + expect(spyOption).toHaveBeenCalledWith('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: coerceLog + }); + }); + }); + + describe('handler', () => { + const HUB_ID = '67d1c1c7642fa239dbe15164'; + const CONTENT_ITEM_ID = 'c5b659df-680e-4711-bfbe-84eaa10d76cc'; + const globalArgs = { + $0: 'test', + _: ['test'], + json: true, + clientId: 'client-id', + clientSecret: 'client-secret', + hubId: HUB_ID + }; + const mockAppendLine = jest.fn(); + const mockLog = { + open: jest.fn().mockReturnValue({ + appendLine: mockAppendLine, + addComment: jest.fn(), + close: jest.fn() + }) + } as unknown as FileLog; + + beforeEach(() => { + jest.clearAllMocks(); + confirmAllContentSpy.mockResolvedValue(true); + asyncQuestionSpy.mockResolvedValue(true); + }); + + it('should publish content item by id', async () => { + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContentByIds as unknown as jest.Mock).mockResolvedValue([ + new ContentItem({ id: CONTENT_ITEM_ID, body: { _meta: {} } }) + ]); + + mockUnpublish.mockImplementation((contentItem, fn) => { + fn(new Job({ id: '68e5289f0aba3024bde050f9', status: 'COMPLETE' })); + }); + + await handler({ + ...globalArgs, + id: CONTENT_ITEM_ID, + logFile: mockLog + }); + + expect(getContentByIds).toHaveBeenCalledWith(expect.any(Object), [CONTENT_ITEM_ID]); + expect(mockUnpublish).toHaveBeenCalledTimes(1); + expect(mockUnpublish).toHaveBeenCalledWith(expect.any(ContentItem), expect.any(Function)); + expect(mockUnpublishOnIdle).toHaveBeenCalledTimes(1); + }); + it('should publish content items by query', async () => { + const REPOSITORY_ID = '67d1c1cf642fa239dbe15165'; + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContent as unknown as jest.Mock).mockResolvedValue([ + new ContentItem({ id: CONTENT_ITEM_ID, body: { _meta: {} } }) + ]); + + mockUnpublish.mockImplementation((contentItem, fn) => { + fn(new Job({ id: '68e5289f0aba3024bde050f9', status: 'COMPLETE' })); + }); + + await handler({ + ...globalArgs, + repoId: REPOSITORY_ID, + logFile: mockLog + }); + + expect(getContent).toHaveBeenCalledWith(expect.any(Object), expect.any(Hub), undefined, { + enrichItems: true, + folderId: undefined, + repoId: REPOSITORY_ID, + status: 'ACTIVE' + }); + expect(mockUnpublish).toHaveBeenCalledTimes(1); + expect(mockUnpublish).toHaveBeenCalledWith(expect.any(ContentItem), expect.any(Function)); + expect(mockUnpublishOnIdle).toHaveBeenCalledTimes(1); + }); + + it('should process only process content items with an unpublishable status', async () => { + const publishedContentItem = new ContentItem({ + id: 'da2ee918-34c3-4fc1-ae05-111111111111', + label: 'Published - unpublish me', + publishingStatus: ContentItemPublishingStatus.LATEST, + body: { + _meta: {}, + text: 'text 1' + } + }); + const unpublishedContentItemDependency = new ContentItem({ + id: 'da2ee918-34c3-4fc1-ae05-222222222222', + label: 'Already unpublished - ignore me', + publishingStatus: ContentItemPublishingStatus.UNPUBLISHED, + body: { + _meta: {}, + text: 'text 1' + } + }); + const notPublishedContentItemDependency = new ContentItem({ + id: 'da2ee918-34c3-4fc1-ae05-333333333333', + label: 'Never been published - ignore me', + publishingStatus: ContentItemPublishingStatus.NONE, + body: { + _meta: {}, + text: 'text 1' + } + }); + + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContentByIds as unknown as jest.Mock).mockResolvedValue([ + publishedContentItem, + unpublishedContentItemDependency, + notPublishedContentItemDependency + ]); + + mockUnpublish.mockImplementation((contentItem, fn) => { + fn(new ContentItem({ id: '68e5289f0aba3024bde050f9' })); + }); + + await handler({ + ...globalArgs, + id: [publishedContentItem.id, unpublishedContentItemDependency.id, notPublishedContentItemDependency.id], + logFile: mockLog + }); + + expect(mockUnpublish).toHaveBeenCalledTimes(1); + expect(mockUnpublish).toHaveBeenCalledWith(publishedContentItem, expect.any(Function)); + expect(mockUnpublishOnIdle).toHaveBeenCalledTimes(1); + }); + + it('should exit before processing content items if confirmation to proceed is rejected', async () => { + confirmAllContentSpy.mockResolvedValue(false); + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContentByIds as unknown as jest.Mock).mockResolvedValue([ + new ContentItem({ id: CONTENT_ITEM_ID, body: { _meta: {} } }) + ]); + + await handler({ + ...globalArgs, + id: CONTENT_ITEM_ID, + logFile: mockLog + }); + expect(mockUnpublish).toHaveBeenCalledTimes(0); + expect(mockUnpublishOnIdle).toHaveBeenCalledTimes(0); + }); + + it('should exit early if ID or query args are not passed', async () => { + await handler({ + ...globalArgs, + id: CONTENT_ITEM_ID, + facet: 'mock-facet', + logFile: mockLog + }); + expect(mockAppendLine).toHaveBeenCalledWith('Please specify either a facet or an ID - not both'); + expect(mockUnpublish).toHaveBeenCalledTimes(0); + expect(mockUnpublishOnIdle).toHaveBeenCalledTimes(0); + }); + + it('should exit early if no content items', async () => { + const mockGetHub = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue(new Hub({ id: HUB_ID })) + } + }); + (getContentByIds as unknown as jest.Mock).mockResolvedValue([]); + await handler({ + ...globalArgs, + id: CONTENT_ITEM_ID, + logFile: mockLog + }); + expect(mockAppendLine).toHaveBeenCalledWith('Nothing found to unpublish, aborting'); + expect(mockUnpublish).toHaveBeenCalledTimes(0); + expect(mockUnpublishOnIdle).toHaveBeenCalledTimes(0); + }); + }); +}); diff --git a/src/commands/content-item/unpublish.ts b/src/commands/content-item/unpublish.ts new file mode 100644 index 00000000..e02cf89a --- /dev/null +++ b/src/commands/content-item/unpublish.ts @@ -0,0 +1,167 @@ +import { Arguments, Argv } from 'yargs'; +import { ConfigurationParameters } from '../configure'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { confirmAllContent } from '../../common/content-item/confirm-all-content'; +import PublishOptions from '../../common/publish/publish-options'; +import { ContentItem, ContentItemPublishingStatus, Status } from 'dc-management-sdk-js'; +import { getDefaultLogPath, createLog } from '../../common/log-helpers'; +import { FileLog } from '../../common/file-log'; +import { withOldFilters } from '../../common/filter/facet'; +import { getContent } from '../../common/filter/fetch-content'; +import { progressBar } from '../../common/progress-bar/progress-bar'; +import { ContentItemUnpublishingService } from '../../common/publishing/content-item-unpublishing-service'; +import { getContentByIds } from '../../common/content-item/get-content-items-by-ids'; + +export const command = 'unpublish [id]'; + +export const desc = 'Unublish Content Items'; + +export const LOG_FILENAME = (platform: string = process.platform): string => + getDefaultLogPath('content-item', 'unpublish', platform); + +export const coerceLog = (logFile: string): FileLog => createLog(logFile, 'Content Items Unpublish Log'); + +export const builder = (yargs: Argv): void => { + yargs + .positional('id', { + type: 'string', + describe: + 'The ID of a content item to be unpublished. If id is not provided, this command will unpublish ALL content items through all content repositories in the hub.' + }) + .option('repoId', { + type: 'string', + describe: 'The ID of a content repository to search items in to be unpublished.', + requiresArg: false + }) + .option('folderId', { + type: 'string', + describe: 'The ID of a folder to search items in to be unpublished.', + requiresArg: false + }) + .option('facet', { + type: 'string', + describe: + "Unpublish content matching the given facets. Provide facets in the format 'label:example name,locale:en-GB', spaces are allowed between values. A regex can be provided for text filters, surrounded with forward slashes. For more examples, see the readme." + }) + .alias('f', 'force') + .option('f', { + type: 'boolean', + boolean: true, + describe: 'If present, there will be no confirmation prompt before unpublishing the found content.' + }) + .alias('s', 'silent') + .option('s', { + type: 'boolean', + boolean: true, + describe: 'If present, no log file will be produced.' + }) + .option('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: coerceLog + }) + .option('name', { + type: 'string', + hidden: true + }); +}; + +export const processItems = async ({ + contentItems, + log +}: { + contentItems: ContentItem[]; + log: FileLog; +}): Promise => { + log.appendLine(`Unpublishing ${contentItems.length} items.`); + + const unpublishingService = new ContentItemUnpublishingService(); + const contentItemUnpublishJobs: ContentItem[] = []; + const unpublishProgress = progressBar(contentItems.length, 0, { title: 'Unpublishing content items' }); + + for (const item of contentItems) { + try { + await unpublishingService.unpublish(item, contentItem => { + contentItemUnpublishJobs.push(contentItem); + + log.addComment(`Initiated unpublish for "${item.label}"`); + unpublishProgress.increment(); + }); + } catch (e) { + log.appendLine(`\nFailed to initiate unpublish for ${item.label}: ${e.toString()}`); + unpublishProgress.increment(); + } + } + + await unpublishingService.onIdle(); + unpublishProgress.stop(); +}; + +export const handler = async (argv: Arguments): Promise => { + const { id, logFile, force, silent, hubId, repoId, folderId } = argv; + const log = logFile.open(); + const client = dynamicContentClientFactory(argv); + const facet = withOldFilters(argv.facet, argv); + const allContent = !id && !facet && !folderId && !repoId; + + if (repoId && id) { + log.appendLine('ID of content item is specified, ignoring repository ID'); + } + + if (id && facet) { + log.appendLine('Please specify either a facet or an ID - not both'); + return; + } + + if (repoId && folderId) { + log.appendLine('Folder is specified, ignoring repository ID'); + } + + if (allContent) { + log.appendLine('No filter was given, unpublishing all content'); + } + + let ids: string[] = []; + + if (id) { + ids = Array.isArray(id) ? id : [id]; + } + + const hub = await client.hubs.get(hubId); + const contentItems = + ids.length > 0 + ? await getContentByIds(client, ids) + : await getContent(client, hub, facet, { repoId, folderId, status: Status.ACTIVE, enrichItems: true }); + + const unpublishableContentItems = contentItems.filter( + item => + item.publishingStatus !== ContentItemPublishingStatus.UNPUBLISHED && + item.publishingStatus !== ContentItemPublishingStatus.NONE + ); + + if (!unpublishableContentItems.length) { + log.appendLine('Nothing found to unpublish, aborting'); + return; + } + + const missingContentItems = ids.length > 0 ? Boolean(ids.length !== unpublishableContentItems.length) : false; + + log.appendLine(`Found ${unpublishableContentItems.length} content items to unpublish\n`); + + if (!force) { + const yes = await confirmAllContent('unpublish', 'content items', allContent, missingContentItems); + if (!yes) { + return; + } + } + + await processItems({ + contentItems: unpublishableContentItems, + log + }); + + log.appendLine(`Unpublish complete - please manually verify unpublish status`); + + await log.close(!silent); +}; diff --git a/src/commands/content-repository.spec.ts b/src/commands/content-repository.spec.ts index 9a96df81..dc3c1e2a 100644 --- a/src/commands/content-repository.spec.ts +++ b/src/commands/content-repository.spec.ts @@ -1,12 +1,17 @@ import { builder } from './content-repository'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; import Yargs from 'yargs/yargs'; +import { configureCommandOptions } from './configure'; -describe('content-repository command', function() { +describe('content-repository command', function () { it('should include the commands in the content-repository dir', () => { const argv = Yargs(process.argv.slice(2)); const spyCommandDir = jest.spyOn(argv, 'commandDir').mockReturnValue(argv); + const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); + const spyConfig = jest.spyOn(argv, 'config').mockReturnThis(); builder(argv); expect(spyCommandDir).toHaveBeenCalledWith('content-repository', YargsCommandBuilderOptions); + expect(spyOptions).toHaveBeenCalledWith(configureCommandOptions); + expect(spyConfig).toHaveBeenCalledWith('config', expect.any(Function)); }); }); diff --git a/src/commands/content-repository.ts b/src/commands/content-repository.ts index 0333eb02..cd7f7080 100644 --- a/src/commands/content-repository.ts +++ b/src/commands/content-repository.ts @@ -1,5 +1,7 @@ import { Argv } from 'yargs'; +import { readConfig } from '../cli'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import { configureCommandOptions } from './configure'; export const command = 'content-repository'; @@ -8,6 +10,8 @@ export const desc = 'Content Repository'; export const builder = (yargs: Argv): Argv => yargs .commandDir('content-repository', YargsCommandBuilderOptions) + .options(configureCommandOptions) + .config('config', readConfig) .demandCommand() .help(); diff --git a/src/commands/content-repository/assign-content-type.spec.ts b/src/commands/content-repository/assign-content-type.spec.ts index b0335afe..cb4d6136 100644 --- a/src/commands/content-repository/assign-content-type.spec.ts +++ b/src/commands/content-repository/assign-content-type.spec.ts @@ -15,12 +15,12 @@ describe('content-repository assign-content-type command', () => { jest.restoreAllMocks(); }); - it('should have a command defined', function() { + it('should have a command defined', function () { expect(command).toEqual('assign-content-type '); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); @@ -45,7 +45,7 @@ describe('content-repository assign-content-type command', () => { }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], diff --git a/src/commands/content-repository/list.spec.ts b/src/commands/content-repository/list.spec.ts index 222ab5ef..da49a194 100644 --- a/src/commands/content-repository/list.spec.ts +++ b/src/commands/content-repository/list.spec.ts @@ -16,12 +16,12 @@ describe('content-type-schema list command', (): void => { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('list'); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { expect(builder).toEqual({ ...SortingOptions, ...RenderingOptions @@ -29,7 +29,7 @@ describe('content-type-schema list command', (): void => { }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -99,8 +99,8 @@ describe('content-type-schema list command', (): void => { const argv = { ...yargArgs, ...config, ...pagingOptions }; await handler(argv); - expect(mockGetHub).toBeCalledWith('hub-id'); - expect(mockList).toBeCalledWith({ size: DEFAULT_SIZE, ...pagingOptions }); + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(mockList).toHaveBeenCalledWith({ size: DEFAULT_SIZE, ...pagingOptions }); expect(mockDataPresenter).toHaveBeenCalledWith(plainListContentRepository); expect(mockDataPresenter.mock.instances[0].render).toHaveBeenCalledWith({ itemMapFn, json: argv.json }); diff --git a/src/commands/content-repository/unassign-content-type.spec.ts b/src/commands/content-repository/unassign-content-type.spec.ts index 4a664942..ccf41603 100644 --- a/src/commands/content-repository/unassign-content-type.spec.ts +++ b/src/commands/content-repository/unassign-content-type.spec.ts @@ -15,12 +15,12 @@ describe('content-repository assign-content-type command', () => { jest.restoreAllMocks(); }); - it('should have a command defined', function() { + it('should have a command defined', function () { expect(command).toEqual('unassign-content-type '); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); @@ -45,7 +45,7 @@ describe('content-repository assign-content-type command', () => { }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], diff --git a/src/commands/content-type-schema.spec.ts b/src/commands/content-type-schema.spec.ts index 64dce838..e8a171a6 100644 --- a/src/commands/content-type-schema.spec.ts +++ b/src/commands/content-type-schema.spec.ts @@ -1,12 +1,17 @@ import { builder } from './content-type-schema'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; import Yargs from 'yargs/yargs'; +import { configureCommandOptions } from './configure'; -describe('content-type-schema command', function() { +describe('content-type-schema command', function () { it('should include the commands in the content-type-schema dir', () => { const argv = Yargs(process.argv.slice(2)); const spyCommandDir = jest.spyOn(argv, 'commandDir').mockReturnValue(argv); + const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); + const spyConfig = jest.spyOn(argv, 'config').mockReturnThis(); builder(argv); expect(spyCommandDir).toHaveBeenCalledWith('content-type-schema', YargsCommandBuilderOptions); + expect(spyOptions).toHaveBeenCalledWith(configureCommandOptions); + expect(spyConfig).toHaveBeenCalledWith('config', expect.any(Function)); }); }); diff --git a/src/commands/content-type-schema.ts b/src/commands/content-type-schema.ts index 018d67ff..66df093b 100644 --- a/src/commands/content-type-schema.ts +++ b/src/commands/content-type-schema.ts @@ -1,5 +1,7 @@ import { Argv } from 'yargs'; +import { readConfig } from '../cli'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import { configureCommandOptions } from './configure'; export const command = 'content-type-schema'; @@ -8,6 +10,8 @@ export const desc = 'Content Type Schema'; export const builder = (yargs: Argv): Argv => yargs .commandDir('content-type-schema', YargsCommandBuilderOptions) + .options(configureCommandOptions) + .config('config', readConfig) .demandCommand() .help(); diff --git a/src/commands/content-type-schema/__snapshots__/export.spec.ts.snap b/src/commands/content-type-schema/__snapshots__/export.spec.ts.snap index f55265ae..6a14970c 100644 --- a/src/commands/content-type-schema/__snapshots__/export.spec.ts.snap +++ b/src/commands/content-type-schema/__snapshots__/export.spec.ts.snap @@ -148,6 +148,57 @@ Array [ ] `; +exports[`content-type-schema export command filterContentTypeSchemasBySchemaId should return the content types matching the given regex 1`] = ` +Array [ + Object { + "body": "{ + \\"$schema\\": \\"http://json-schema.org/draft-07/schema#\\", + \\"$id\\": \\"https://schema.localhost.com/remote-test-2.json\\", + + \\"title\\": \\"Test Schema 2\\", + \\"description\\": \\"Test Schema 2\\", + + \\"allOf\\": [ + { + \\"$ref\\": \\"http://bigcontent.io/cms/schema/v1/core#/definitions/content\\" + } + ], + + \\"type\\": \\"object\\", + \\"properties\\": { + + }, + \\"propertyOrder\\": [] +}", + "schemaId": "content-type-schema-id-2", + "validationLevel": "CONTENT_TYPE", + }, + Object { + "body": "{ + \\"$schema\\": \\"http://json-schema.org/draft-07/schema#\\", + \\"$id\\": \\"https://schema.localhost.com/remote-test-3.json\\", + + \\"title\\": \\"Test Schema 3\\", + \\"description\\": \\"Test Schema 3\\", + + \\"allOf\\": [ + { + \\"$ref\\": \\"http://bigcontent.io/cms/schema/v1/core#/definitions/content\\" + } + ], + + \\"type\\": \\"object\\", + \\"properties\\": { + + }, + \\"propertyOrder\\": [] +}", + "schemaId": "content-type-schema-id-3", + "validationLevel": "CONTENT_TYPE", + }, +] +`; + exports[`content-type-schema export command filterContentTypeSchemasBySchemaId should return the content types matching the given schemaIds 1`] = ` Array [ Object { diff --git a/src/commands/content-type-schema/archive.spec.ts b/src/commands/content-type-schema/archive.spec.ts index fbac2b75..86067634 100644 --- a/src/commands/content-type-schema/archive.spec.ts +++ b/src/commands/content-type-schema/archive.spec.ts @@ -1,6 +1,6 @@ import { builder, coerceLog, command, handler, LOG_FILENAME } from './archive'; import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; -import { ContentTypeSchema, Hub } from 'dc-management-sdk-js'; +import { ContentTypeSchema, HttpError, Hub } from 'dc-management-sdk-js'; import Yargs from 'yargs/yargs'; import MockPage from '../../common/dc-management-sdk-js/mock-page'; import { exists, readFile, unlink, mkdir, writeFile } from 'fs'; @@ -26,12 +26,12 @@ describe('content-item-schema archive command', () => { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('archive [id]'); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); @@ -83,13 +83,13 @@ describe('content-item-schema archive command', () => { }); }); - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('schema', 'archive', process.platform); }); - it('should generate a log with coerceLog with the appropriate title', function() { + it('should generate a log with coerceLog with the appropriate title', function () { const logFile = coerceLog('filename.log'); expect(logFile).toEqual(expect.any(FileLog)); @@ -97,7 +97,7 @@ describe('content-item-schema archive command', () => { }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -608,64 +608,105 @@ describe('content-item-schema archive command', () => { await handler(argv); }); - it('should exit cleanly when revert log is missing', async () => { + it('should throw an error when revert log is missing', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockHubGet = jest.fn(); + const mockHubList = jest.fn(); + + const mockHub = new Hub(); + mockHubList.mockResolvedValue(generateMockSchemaList(['http://schemas.com/schema1'], () => {}, false)); + mockHub.related.contentTypeSchema.list = mockHubList; + mockHubGet.mockResolvedValue(mockHub); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockHubGet + } + }); + const argv = { ...yargArgs, ...config, - - force: true, + schemaId: 'http://schemas.com/schema1', silent: true, revertLog: 'doesntExist.txt' }; - await handler(argv); + + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error - could not read unarchive log']); }); - it('should exit cleanly when hub is not configured, or on invalid input.', async () => { - // Content list/get is not init, so it will throw. + it('should throw an error when fails to get content type schema by id', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockGet = jest.fn(); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + contentTypeSchemas: { + get: mockGet + } + }); + + mockGet.mockRejectedValue(new HttpError('Failed to get content type schema')); + + const argv = { + ...yargArgs, + ...config, + silent: true, + id: 'test-schema-id' + }; + + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error: could not find schema with ID test-schema-id']); + }); + it('should throw an error when fails to get hub by id', async () => { + const logSpy = jest.spyOn(console, 'log'); const mockHubGet = jest.fn(); + mockHubGet.mockRejectedValue(new HttpError('Failed to get hub by id')); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ hubs: { get: mockHubGet } }); - const mockHub = new Hub(); - mockHubGet.mockResolvedValue(mockHub); - - // All const argv = { ...yargArgs, ...config, - - force: true, + schemaId: 'http://schemas.com/schema1', silent: true }; - await handler(argv); - // Id - const argv2 = { - ...yargArgs, - ...config, + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error: could not retrieve content type schemas to archive']); + }); - force: true, - silent: true, - id: 'test' - }; - await handler(argv2); + it('should throw an error when fails to list hub content type schemas', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockHubGet = jest.fn(); + const mockHubList = jest.fn(); - // Id and Schema id - const argv3 = { + const mockHub = new Hub(); + mockHubList.mockRejectedValue(new HttpError('Failed to list content type schemas')); + mockHub.related.contentTypeSchema.list = mockHubList; + mockHubGet.mockResolvedValue(mockHub); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockHubGet + } + }); + + const argv = { ...yargArgs, ...config, - - force: true, - silent: true, - id: 'test', - schemaId: 'conflict' + schemaId: 'http://schemas.com/schema1', + silent: true }; - await handler(argv3); + + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error: could not retrieve content type schemas to archive']); }); }); }); diff --git a/src/commands/content-type-schema/archive.ts b/src/commands/content-type-schema/archive.ts index fc4ba6c2..abb90a21 100644 --- a/src/commands/content-type-schema/archive.ts +++ b/src/commands/content-type-schema/archive.ts @@ -3,12 +3,13 @@ import { ConfigurationParameters } from '../configure'; import { ContentTypeSchema, Status } from 'dc-management-sdk-js'; import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; import { ArchiveLog } from '../../common/archive/archive-log'; -import paginator from '../../common/dc-management-sdk-js/paginator'; import { equalsOrRegex } from '../../common/filter/filter'; -import { confirmArchive } from '../../common/archive/archive-helpers'; +import { confirmAllContent } from '../../common/content-item/confirm-all-content'; import ArchiveOptions from '../../common/archive/archive-options'; import { createLog, getDefaultLogPath } from '../../common/log-helpers'; import { FileLog } from '../../common/file-log'; +import { paginateWithProgress } from '../../common/dc-management-sdk-js/paginate-with-progress'; +import { progressBar } from '../../common/progress-bar/progress-bar'; export const command = 'archive [id]'; @@ -81,17 +82,19 @@ export const handler = async (argv: Arguments client.contentTypeSchemas.get(id))); } catch (e) { - console.log(`Fatal error: could not find schema with ID ${id}. Error: \n${e.toString()}`); + console.log(`Fatal error: could not find schema with ID ${id}`); return; } } else { try { const hub = await client.hubs.get(hubId); - schemas = await paginator(hub.related.contentTypeSchema.list, { status: Status.ACTIVE }); - } catch (e) { - console.log( - `Fatal error: could not retrieve content type schemas to archive. Is your hub correct? Error: \n${e.toString()}` + schemas = await paginateWithProgress( + hub.related.contentTypeSchema.list, + { status: Status.ACTIVE }, + { title: 'Retrieving active content type schemas' } ); + } catch (e) { + console.log(`Fatal error: could not retrieve content type schemas to archive`); return; } @@ -104,7 +107,7 @@ export const handler = async (argv: Arguments; -describe('content type schema create command', function() { +describe('content type schema create command', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -34,15 +34,15 @@ describe('content type schema create command', function() { const aHub = new Hub(); mockGetHub.mockResolvedValue(aHub); - it('should have a command', function() { + it('should have a command', function () { expect(command).toEqual('create'); }); - it('should have a description', function() { + it('should have a description', function () { expect(desc).toEqual('Create Content Type Schema'); }); - it('should have a builder that has a schema option', function() { + it('should have a builder that has a schema option', function () { expect(builder.schema).toEqual({ type: 'string', demandOption: true, @@ -51,7 +51,7 @@ describe('content type schema create command', function() { }); }); - it('should have a builder that has a validation level option', function() { + it('should have a builder that has a validation level option', function () { expect(builder.validationLevel).toEqual({ type: 'string', choices: ['SLOT', 'CONTENT_TYPE', 'PARTIAL'], @@ -61,7 +61,7 @@ describe('content type schema create command', function() { }); }); - it('should create a schema', async function() { + it('should create a schema', async function () { const input = { schema: __dirname + '/__fixtures/schema.json', validationLevel: ValidationLevel.CONTENT_TYPE diff --git a/src/commands/content-type-schema/export.spec.ts b/src/commands/content-type-schema/export.spec.ts index 90f8a736..8a13655f 100644 --- a/src/commands/content-type-schema/export.spec.ts +++ b/src/commands/content-type-schema/export.spec.ts @@ -61,7 +61,7 @@ describe('content-type-schema export command', (): void => { expect(spyOption).toHaveBeenCalledWith('schemaId', { type: 'string', describe: - 'The Schema ID of a Content Type Schema to be exported.\nIf no --schemaId option is given, all content type schemas for the hub are exported.\nA single --schemaId option may be given to export a single content type schema.\nMultiple --schemaId options may be given to export multiple content type schemas at the same time.', + 'The Schema ID of a Content Type Schema to be exported.\nIf no --schemaId option is given, all content type schemas for the hub are exported.\nA regex can be provided to select multiple type schemas with similar or matching schema ids (eg /schema(0-9)\\.json/).\nA single --schemaId option may be given to export a single content type schema.\nMultiple --schemaId options may be given to export multiple content type schemas at the same time.', requiresArg: true }); expect(spyOption).toHaveBeenCalledWith('f', { @@ -592,6 +592,11 @@ describe('content-type-schema export command', (): void => { expect(result).toMatchSnapshot(); }); + it('should return the content types matching the given regex', async () => { + const result = filterContentTypeSchemasBySchemaId(listToFilter, ['/2|3/']); + expect(result).toMatchSnapshot(); + }); + it('should return all the content type schemas if a filter list is not provided', async () => { const result = filterContentTypeSchemasBySchemaId(listToFilter, []); expect(result).toMatchSnapshot(); @@ -698,9 +703,7 @@ describe('content-type-schema export command', (): void => { expectProcessArguments(argv.dir, contentTypeSchemasToExport); }); - it('should export all content type schemas for the current hub if schemaId is not supplied', async (): Promise< - void - > => { + it('should export all content type schemas for the current hub if schemaId is not supplied', async (): Promise => { filterContentTypeSchemasBySchemaIdSpy.mockReturnValue(contentTypeSchemasToExport); const argv = { ...yargArgs, ...config, dir: 'my-dir' }; diff --git a/src/commands/content-type-schema/export.ts b/src/commands/content-type-schema/export.ts index ec1d470e..a7803bcf 100644 --- a/src/commands/content-type-schema/export.ts +++ b/src/commands/content-type-schema/export.ts @@ -1,7 +1,6 @@ import { Arguments, Argv } from 'yargs'; import { ConfigurationParameters } from '../configure'; import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; -import paginator from '../../common/dc-management-sdk-js/paginator'; import { ContentTypeSchema, Status } from 'dc-management-sdk-js'; import { table } from 'table'; import { baseTableConfig } from '../../common/table/table.consts'; @@ -21,6 +20,9 @@ import { resolveSchemaBody } from '../../services/resolve-schema-body'; import { ensureDirectoryExists } from '../../common/import/directory-utils'; import { FileLog } from '../../common/file-log'; import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { equalsOrRegex } from '../../common/filter/filter'; +import { paginateWithProgress } from '../../common/dc-management-sdk-js/paginate-with-progress'; +import { progressBar } from '../../common/progress-bar/progress-bar'; export const streamTableOptions = { ...baseTableConfig, @@ -60,7 +62,7 @@ export const builder = (yargs: Argv): void => { .option('schemaId', { type: 'string', describe: - 'The Schema ID of a Content Type Schema to be exported.\nIf no --schemaId option is given, all content type schemas for the hub are exported.\nA single --schemaId option may be given to export a single content type schema.\nMultiple --schemaId options may be given to export multiple content type schemas at the same time.', + 'The Schema ID of a Content Type Schema to be exported.\nIf no --schemaId option is given, all content type schemas for the hub are exported.\nA regex can be provided to select multiple type schemas with similar or matching schema ids (eg /schema(0-9)\\.json/).\nA single --schemaId option may be given to export a single content type schema.\nMultiple --schemaId options may be given to export multiple content type schemas at the same time.', requiresArg: true }) .alias('f', 'force') @@ -175,7 +177,9 @@ export const filterContentTypeSchemasBySchemaId = ( return listToFilter; } - const unmatchedIdList: string[] = listToMatch.filter(id => !listToFilter.some(schema => schema.schemaId === id)); + const unmatchedIdList: string[] = listToMatch.filter( + match => !listToFilter.some(schema => equalsOrRegex(schema.schemaId as string, match)) + ); if (unmatchedIdList.length > 0) { throw new Error( `The following schema ID(s) could not be found: [${unmatchedIdList @@ -184,7 +188,7 @@ export const filterContentTypeSchemasBySchemaId = ( ); } - return listToFilter.filter(schema => listToMatch.some(id => schema.schemaId === id)); + return listToFilter.filter(schema => listToMatch.some(match => equalsOrRegex(schema.schemaId as string, match))); }; export const getContentTypeSchemaExports = ( @@ -239,8 +243,11 @@ export const processContentTypeSchemas = async ( await ensureDirectoryExists(outputDir); - const data: string[][] = []; - data.push([chalk.bold('File'), chalk.bold('Schema file'), chalk.bold('Schema ID'), chalk.bold('Result')]); + const progress = progressBar(allExports.length, 0, { title: 'Exporting content types' }); + + const data: [string, string, string, string][] = [ + [chalk.bold('File'), chalk.bold('Schema file'), chalk.bold('Schema ID'), chalk.bold('Result')] + ]; for (const { filename, status, contentTypeSchema } of allExports) { let schemaFilename = ''; if (status !== 'UP-TO-DATE') { @@ -260,9 +267,10 @@ export const processContentTypeSchemas = async ( }) ); } + progress.increment(); data.push([filename, schemaFilename, contentTypeSchema.schemaId || '', status]); } - + progress.stop(); log.appendLine(table(data, streamTableOptions)); }; @@ -275,9 +283,10 @@ export const handler = async (argv: Arguments { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('get '); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); @@ -35,7 +35,7 @@ describe('content-item-schema get command', () => { }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], diff --git a/src/commands/content-type-schema/import.ts b/src/commands/content-type-schema/import.ts index 2db7d8e3..db27becc 100644 --- a/src/commands/content-type-schema/import.ts +++ b/src/commands/content-type-schema/import.ts @@ -13,6 +13,7 @@ import { ImportResult, loadJsonFromDirectory, UpdateStatus } from '../../service import { resolveSchemaBody } from '../../services/resolve-schema-body'; import { FileLog } from '../../common/file-log'; import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { progressBar } from '../../common/progress-bar/progress-bar'; export const command = 'import '; @@ -108,9 +109,11 @@ export const processSchemas = async ( hub: Hub, log: FileLog ): Promise => { - const data: string[][] = []; + const progress = progressBar(schemasToProcess.length, 0, { title: 'Importing content type schemas' }); + progress.start(schemasToProcess.length, 0); + + const data: string[][] = [[chalk.bold('ID'), chalk.bold('Schema ID'), chalk.bold('Result')]]; - data.push([chalk.bold('ID'), chalk.bold('Schema ID'), chalk.bold('Result')]); for (const schema of schemasToProcess) { let status: ImportResult; let contentTypeSchema: ContentTypeSchema; @@ -122,9 +125,11 @@ export const processSchemas = async ( contentTypeSchema = await doCreate(hub, schema, log); status = 'CREATED'; } + progress.increment(); data.push([contentTypeSchema.id || '', contentTypeSchema.schemaId || '', status]); } + progress.stop(); log.appendLine(table(data, streamTableOptions)); }; diff --git a/src/commands/content-type-schema/list.spec.ts b/src/commands/content-type-schema/list.spec.ts index a15a3bca..d43e8e3f 100644 --- a/src/commands/content-type-schema/list.spec.ts +++ b/src/commands/content-type-schema/list.spec.ts @@ -15,7 +15,7 @@ describe('content-type-schema list command', (): void => { jest.restoreAllMocks(); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -64,8 +64,8 @@ describe('content-type-schema list command', (): void => { const argv = { ...yargArgs, ...config }; await handler(argv); - expect(mockGetHub).toBeCalledWith('hub-id'); - expect(mockList).toBeCalledWith({ size: DEFAULT_SIZE }); + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(mockList).toHaveBeenCalledWith({ size: DEFAULT_SIZE }); expect(mockDataPresenter).toHaveBeenCalledWith(plainListContentTypeSchemas); expect(mockDataPresenter.mock.instances[0].render).toHaveBeenCalledWith({ itemMapFn, json: argv.json }); @@ -95,7 +95,7 @@ describe('content-type-schema list command', (): void => { const argv = { ...yargArgs, ...config }; await handler(argv); - expect(mockGetHub).toBeCalledWith('hub-id'); + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); expect(mockList).toHaveBeenCalled(); expect(mockDataPresenter).toHaveBeenCalledTimes(0); }); diff --git a/src/commands/content-type-schema/unarchive.spec.ts b/src/commands/content-type-schema/unarchive.spec.ts index c7d29a6e..34858b12 100644 --- a/src/commands/content-type-schema/unarchive.spec.ts +++ b/src/commands/content-type-schema/unarchive.spec.ts @@ -1,6 +1,6 @@ import { builder, command, handler, LOG_FILENAME } from './unarchive'; import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; -import { ContentTypeSchema, Hub } from 'dc-management-sdk-js'; +import { ContentTypeSchema, HttpError, Hub } from 'dc-management-sdk-js'; import Yargs from 'yargs/yargs'; import MockPage from '../../common/dc-management-sdk-js/mock-page'; import { dirname } from 'path'; @@ -17,12 +17,12 @@ describe('content-item-schema unarchive command', () => { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('unarchive [id]'); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); @@ -75,7 +75,7 @@ describe('content-item-schema unarchive command', () => { }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -588,7 +588,22 @@ describe('content-item-schema unarchive command', () => { await handler(argv); }); - it('should exit cleanly when revert log is missing', async () => { + it('should throw an error when revert log is missing', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockHubGet = jest.fn(); + const mockHubList = jest.fn(); + + const mockHub = new Hub(); + mockHubList.mockResolvedValue(generateMockSchemaList(['http://schemas.com/schema1'], () => {}, false)); + mockHub.related.contentTypeSchema.list = mockHubList; + mockHubGet.mockResolvedValue(mockHub); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockHubGet + } + }); + const argv = { ...yargArgs, ...config, @@ -597,55 +612,85 @@ describe('content-item-schema unarchive command', () => { silent: true, revertLog: 'doesntExist.txt' }; - await handler(argv); + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error - could not read archive log']); }); - it('should exit cleanly when hub is not configured, or on invalid input.', async () => { - // Content list/get is not init, so it will throw. - - const mockHubGet = jest.fn(); + it('should throw an error when fails to get content type schema by id', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockGet = jest.fn(); (dynamicContentClientFactory as jest.Mock).mockReturnValue({ - hubs: { - get: mockHubGet + contentTypeSchemas: { + get: mockGet } }); - const mockHub = new Hub(); - mockHubGet.mockResolvedValue(mockHub); + mockGet.mockRejectedValue(new HttpError('Failed to get content type schema')); - // All const argv = { ...yargArgs, ...config, logFile: LOG_FILENAME(), force: true, - silent: true + silent: true, + id: 'test-schema-id' }; - await handler(argv); - // Id - const argv2 = { + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error: could not find content type schema with ID test-schema-id']); + }); + + it('should throw an error when fails to get hub by id', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockHubGet = jest.fn(); + + mockHubGet.mockRejectedValue(new HttpError('Failed to get hub by id')); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockHubGet + } + }); + + const argv = { ...yargArgs, ...config, logFile: LOG_FILENAME(), force: true, - silent: true, - id: 'test' + silent: true }; - await handler(argv2); - // Id and Schema id - const argv3 = { + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error: could not retrieve content type schemas to unarchive']); + }); + + it('should throw an error when fails to list hub content type schemas', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockHubGet = jest.fn(); + const mockHubList = jest.fn(); + + const mockHub = new Hub(); + mockHubList.mockRejectedValue(new HttpError('Failed to list content type schemas')); + mockHub.related.contentTypeSchema.list = mockHubList; + mockHubGet.mockResolvedValue(mockHub); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockHubGet + } + }); + + const argv = { ...yargArgs, ...config, logFile: LOG_FILENAME(), force: true, - silent: true, - id: 'test', - schemaId: 'conflict' + silent: true }; - await handler(argv3); + + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error: could not retrieve content type schemas to unarchive']); }); }); }); diff --git a/src/commands/content-type-schema/unarchive.ts b/src/commands/content-type-schema/unarchive.ts index 2b45e756..114ba595 100644 --- a/src/commands/content-type-schema/unarchive.ts +++ b/src/commands/content-type-schema/unarchive.ts @@ -5,7 +5,7 @@ import dynamicContentClientFactory from '../../services/dynamic-content-client-f import { ArchiveLog } from '../../common/archive/archive-log'; import { equalsOrRegex } from '../../common/filter/filter'; import paginator from '../../common/dc-management-sdk-js/paginator'; -import { confirmArchive } from '../../common/archive/archive-helpers'; +import { confirmAllContent } from '../../common/content-item/confirm-all-content'; import UnarchiveOptions from '../../common/archive/unarchive-options'; import { getDefaultLogPath } from '../../common/log-helpers'; @@ -77,7 +77,7 @@ export const handler = async (argv: Arguments; -describe('content type schema update command', function() { - describe('command tests', function() { - it('should have a command', function() { +describe('content type schema update command', function () { + describe('command tests', function () { + it('should have a command', function () { expect(command).toEqual('update '); }); }); - describe('description tests', function() { - it('should have a description', function() { + describe('description tests', function () { + it('should have a description', function () { expect(desc).toEqual('Update Content Type Schema'); }); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); @@ -58,7 +58,7 @@ describe('content type schema update command', function() { }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -91,7 +91,7 @@ describe('content type schema update command', function() { } }); - it('should update a schema', async function() { + it('should update a schema', async function () { const argv = { ...yargArgs, ...config, diff --git a/src/commands/content-type.spec.ts b/src/commands/content-type.spec.ts index 3ec7ab4f..e68869f1 100644 --- a/src/commands/content-type.spec.ts +++ b/src/commands/content-type.spec.ts @@ -1,12 +1,17 @@ import { builder } from './content-type'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; import Yargs from 'yargs/yargs'; +import { configureCommandOptions } from './configure'; -describe('content-type command', function() { +describe('content-type command', function () { it('should include the commands in the content-type dir', () => { const argv = Yargs(process.argv.slice(2)); const spyCommandDir = jest.spyOn(argv, 'commandDir').mockReturnValue(argv); + const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); + const spyConfig = jest.spyOn(argv, 'config').mockReturnThis(); builder(argv); expect(spyCommandDir).toHaveBeenCalledWith('content-type', YargsCommandBuilderOptions); + expect(spyOptions).toHaveBeenCalledWith(configureCommandOptions); + expect(spyConfig).toHaveBeenCalledWith('config', expect.any(Function)); }); }); diff --git a/src/commands/content-type.ts b/src/commands/content-type.ts index 60ebc4cd..067c602b 100644 --- a/src/commands/content-type.ts +++ b/src/commands/content-type.ts @@ -1,5 +1,7 @@ import { Argv } from 'yargs'; +import { readConfig } from '../cli'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import { configureCommandOptions } from './configure'; export const command = 'content-type'; @@ -8,6 +10,8 @@ export const desc = 'Content Type'; export const builder = (yargs: Argv): Argv => yargs .commandDir('content-type', YargsCommandBuilderOptions) + .options(configureCommandOptions) + .config('config', readConfig) .demandCommand() .help(); diff --git a/src/commands/content-type/__snapshots__/import.spec.ts.snap b/src/commands/content-type/__snapshots__/import.spec.ts.snap index d4dcf80c..8490fe1d 100644 --- a/src/commands/content-type/__snapshots__/import.spec.ts.snap +++ b/src/commands/content-type/__snapshots__/import.spec.ts.snap @@ -12,8 +12,6 @@ exports[`content-type import command doUpdate should throw an error when unable exports[`content-type import command doUpdate should throw an error when unable to update content type during update if a string error is returned by sdk 1`] = `"Error updating content type stored-id: The update action is not available, ensure you have permission to perform this action."`; -exports[`content-type import command handler tests should throw an error when no content found in import directory 1`] = `"No content types found in my-empty-dir"`; - exports[`content-type import command validateNoDuplicateContentTypeUris should throw and error when there are duplicate uris 1`] = ` "Content Types must have unique uri values. Duplicate values found:- uri: 'type-uri-1' in files: ['file-1', 'file-4'] diff --git a/src/commands/content-type/archive.spec.ts b/src/commands/content-type/archive.spec.ts index 1721d852..87b656a8 100644 --- a/src/commands/content-type/archive.spec.ts +++ b/src/commands/content-type/archive.spec.ts @@ -1,6 +1,6 @@ import { builder, coerceLog, command, handler, LOG_FILENAME } from './archive'; import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; -import { ContentType, Hub } from 'dc-management-sdk-js'; +import { ContentType, HttpError, Hub } from 'dc-management-sdk-js'; import Yargs from 'yargs/yargs'; import MockPage from '../../common/dc-management-sdk-js/mock-page'; import { exists, readFile, unlink, mkdir, writeFile } from 'fs'; @@ -26,12 +26,12 @@ describe('content-type archive command', () => { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('archive [id]'); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); @@ -83,13 +83,13 @@ describe('content-type archive command', () => { }); }); - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('type', 'archive', process.platform); }); - it('should generate a log with coerceLog with the appropriate title', function() { + it('should generate a log with coerceLog with the appropriate title', function () { const logFile = coerceLog('filename.log'); expect(logFile).toEqual(expect.any(FileLog)); @@ -97,7 +97,7 @@ describe('content-type archive command', () => { }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -123,7 +123,6 @@ describe('content-type archive command', () => { contentTypeUri: template.schemaId, id: template.id }); - archiveResponse.settings; archiveResponse.related.archive = mockArchive; mockArchive.mockImplementation(() => { @@ -624,60 +623,105 @@ describe('content-type archive command', () => { await handler(argv); }); - it('should exit cleanly when revert log is missing', async () => { + it('should throw an error when revert log is missing', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockHubGet = jest.fn(); + const mockHubList = jest.fn(); + + const mockHub = new Hub(); + mockHubList.mockResolvedValue( + generateMockTypeList([{ name: 'name', schemaId: 'http://schemas.com/schema1' }], () => {}, false) + ); + mockHub.related.contentTypes.list = mockHubList; + mockHubGet.mockResolvedValue(mockHub); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockHubGet + } + }); + const argv = { ...yargArgs, ...config, - force: true, + schemaId: 'http://schemas.com/schema1', silent: true, revertLog: 'doesntExist.txt' }; - await handler(argv); + + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error - could not read unarchive log']); }); - it('should exit cleanly when hub is not configured, or on invalid input.', async () => { - // Content list/get is not init, so it will throw. + it('should throw an error when fails to get content type by id', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockGet = jest.fn(); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + contentTypes: { + get: mockGet + } + }); + + mockGet.mockRejectedValue(new HttpError('Failed to get content type by id')); + + const argv = { + ...yargArgs, + ...config, + silent: true, + id: 'test-content-type-id' + }; + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error: could not find content type with ID test-content-type-id']); + }); + + it('should throw an error when fails to get hub by id', async () => { + const logSpy = jest.spyOn(console, 'log'); const mockHubGet = jest.fn(); + mockHubGet.mockRejectedValue(new HttpError('Failed to get hub by id')); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ hubs: { get: mockHubGet } }); - const mockHub = new Hub(); - mockHubGet.mockResolvedValue(mockHub); - - // All const argv = { ...yargArgs, ...config, - force: true, + schemaId: 'http://schemas.com/schema1', silent: true }; - await handler(argv); + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error: could not retrieve content types to archive']); + }); - // Id - const argv2 = { - ...yargArgs, - ...config, - force: true, - silent: true, - id: 'test' - }; - await handler(argv2); + it('should throw an error when fails to list hub content types', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockHubGet = jest.fn(); + const mockHubList = jest.fn(); + + const mockHub = new Hub(); + mockHubList.mockRejectedValue(new HttpError('Failed to list content types')); + mockHub.related.contentTypes.list = mockHubList; + mockHubGet.mockResolvedValue(mockHub); - // Id and Schema id - const argv3 = { + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockHubGet + } + }); + + const argv = { ...yargArgs, ...config, - force: true, - silent: true, - id: 'test', - schemaId: 'conflict' + schemaId: 'http://schemas.com/schema1', + silent: true }; - await handler(argv3); + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error: could not retrieve content types to archive']); }); }); }); diff --git a/src/commands/content-type/archive.ts b/src/commands/content-type/archive.ts index 53ffc722..59a23106 100644 --- a/src/commands/content-type/archive.ts +++ b/src/commands/content-type/archive.ts @@ -3,13 +3,14 @@ import { ConfigurationParameters } from '../configure'; import { ContentType, Status } from 'dc-management-sdk-js'; import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; import { ArchiveLog } from '../../common/archive/archive-log'; -import paginator from '../../common/dc-management-sdk-js/paginator'; import { equalsOrRegex } from '../../common/filter/filter'; -import { confirmArchive } from '../../common/archive/archive-helpers'; +import { confirmAllContent } from '../../common/content-item/confirm-all-content'; import ArchiveOptions from '../../common/archive/archive-options'; import { createLog, getDefaultLogPath } from '../../common/log-helpers'; import { FileLog } from '../../common/file-log'; +import { paginateWithProgress } from '../../common/dc-management-sdk-js/paginate-with-progress'; +import { progressBar } from '../../common/progress-bar/progress-bar'; export const command = 'archive [id]'; @@ -82,17 +83,19 @@ export const handler = async (argv: Arguments client.contentTypes.get(id))); } catch (e) { - console.log(`Fatal error: could not find content type with ID ${id}. Error: \n${e.toString()}`); + console.log(`Fatal error: could not find content type with ID ${id}`); return; } } else { try { const hub = await client.hubs.get(argv.hubId); - types = await paginator(hub.related.contentTypes.list, { status: Status.ACTIVE }); - } catch (e) { - console.log( - `Fatal error: could not retrieve content types to archive. Is your hub correct? Error: \n${e.toString()}` + types = await paginateWithProgress( + hub.related.contentTypes.list, + { status: Status.ACTIVE }, + { title: 'Retrieving active content types' } ); + } catch (e) { + console.log(`Fatal error: could not retrieve content types to archive`); return; } @@ -105,7 +108,7 @@ export const handler = async (argv: Arguments { expect(spyOption).toHaveBeenCalledWith('schemaId', { type: 'string', describe: - 'The Schema ID of a Content Type to be exported.\nIf no --schemaId option is given, all content types for the hub are exported.\nA single --schemaId option may be given to export a single content type.\nMultiple --schemaId options may be given to export multiple content types at the same time.', + 'The Schema ID of a Content Type to be exported.\nIf no --schemaId option is given, all content types for the hub are exported.\nA regex can be provided to select multiple types with similar or matching schema ids (eg /schema(0-9)\\.json/).\nA single --schemaId option may be given to export a single content type.\nMultiple --schemaId options may be given to export multiple content types at the same time.', requiresArg: true }); expect(spyOption).toHaveBeenCalledWith('f', { @@ -333,6 +333,11 @@ describe('content-type export command', (): void => { expect(result).toEqual(expect.arrayContaining([listToFilter[0], listToFilter[2]])); }); + it('should return the content types matching the given regex', async () => { + const result = filterContentTypesByUri(listToFilter, ['/2|3/']); + expect(result).toEqual(expect.arrayContaining([listToFilter[1], listToFilter[2]])); + }); + it('should return all the content types because there are no URIs to filter', async () => { const result = filterContentTypesByUri(listToFilter, []); expect(result).toEqual(listToFilter); @@ -820,9 +825,7 @@ describe('content-type export command', (): void => { ); }); - it('should export even archived content types for the current hub if --archived is provided', async (): Promise< - void - > => { + it('should export even archived content types for the current hub if --archived is provided', async (): Promise => { const schemaIdsToExport: string[] | undefined = undefined; const argv = { ...yargArgs, diff --git a/src/commands/content-type/export.ts b/src/commands/content-type/export.ts index 17dc90db..8045cb29 100644 --- a/src/commands/content-type/export.ts +++ b/src/commands/content-type/export.ts @@ -20,6 +20,9 @@ import { ExportBuilderOptions } from '../../interfaces/export-builder-options.in import { ensureDirectoryExists } from '../../common/import/directory-utils'; import { FileLog } from '../../common/file-log'; import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { equalsOrRegex } from '../../common/filter/filter'; +import { paginateWithProgress } from '../../common/dc-management-sdk-js/paginate-with-progress'; +import { progressBar } from '../../common/progress-bar/progress-bar'; export const command = 'export '; @@ -37,7 +40,7 @@ export const builder = (yargs: Argv): void => { .option('schemaId', { type: 'string', describe: - 'The Schema ID of a Content Type to be exported.\nIf no --schemaId option is given, all content types for the hub are exported.\nA single --schemaId option may be given to export a single content type.\nMultiple --schemaId options may be given to export multiple content types at the same time.', + 'The Schema ID of a Content Type to be exported.\nIf no --schemaId option is given, all content types for the hub are exported.\nA regex can be provided to select multiple types with similar or matching schema ids (eg /schema(0-9)\\.json/).\nA single --schemaId option may be given to export a single content type.\nMultiple --schemaId options may be given to export multiple content types at the same time.', requiresArg: true }) .alias('f', 'force') @@ -78,7 +81,7 @@ export const filterContentTypesByUri = (listToFilter: ContentType[], contentType } const unmatchedContentTypeUriList: string[] = contentTypeUriList.filter( - uri => !listToFilter.some(contentType => contentType.contentTypeUri === uri) + match => !listToFilter.some(contentType => equalsOrRegex(contentType.contentTypeUri as string, match)) ); if (unmatchedContentTypeUriList.length > 0) { throw new Error( @@ -88,7 +91,9 @@ export const filterContentTypesByUri = (listToFilter: ContentType[], contentType ); } - return listToFilter.filter(contentType => contentTypeUriList.some(uri => contentType.contentTypeUri === uri)); + return listToFilter.filter(contentType => + contentTypeUriList.some(match => equalsOrRegex(contentType.contentTypeUri as string, match)) + ); }; export const getReposNamesForContentType = ( @@ -211,17 +216,18 @@ export const processContentTypes = async ( await ensureDirectoryExists(outputDir); - const data: string[][] = []; + const progress = progressBar(allExports.length, 0, { title: 'Exporting content types' }); - data.push([chalk.bold('File'), chalk.bold('Schema ID'), chalk.bold('Result')]); + const data: [string, string, string][] = [[chalk.bold('File'), chalk.bold('Schema ID'), chalk.bold('Result')]]; for (const { filename, status, contentType } of allExports) { if (status !== 'UP-TO-DATE') { delete contentType.id; // do not export id writeJsonToFile(filename, contentType); } data.push([filename, contentType.contentTypeUri || '', status]); + progress.increment(); } - + progress.stop(); log.appendLine(table(data, streamTableOptions)); }; @@ -235,9 +241,17 @@ export const handler = async (argv: Arguments(dir, ContentType); validateNoDuplicateContentTypeUris(previouslyExportedContentTypes); - const storedContentTypes = await paginator(hub.related.contentTypes.list, { status: Status.ACTIVE }); + const storedContentTypes = await paginateWithProgress( + hub.related.contentTypes.list, + { status: Status.ACTIVE }, + { title: 'Retrieving active content types' } + ); if (argv.archived) { - const archivedContentTypes = await paginator(hub.related.contentTypes.list, { status: Status.ARCHIVED }); + const archivedContentTypes = await paginateWithProgress( + hub.related.contentTypes.list, + { status: Status.ARCHIVED }, + { title: 'Retrieving archived content types' } + ); Array.prototype.push.apply(storedContentTypes, archivedContentTypes); } const schemaIdArray: string[] = schemaId ? (Array.isArray(schemaId) ? schemaId : [schemaId]) : []; diff --git a/src/commands/content-type/get.spec.ts b/src/commands/content-type/get.spec.ts index cc2e24ec..29348b0c 100644 --- a/src/commands/content-type/get.spec.ts +++ b/src/commands/content-type/get.spec.ts @@ -15,12 +15,12 @@ describe('content-type get command', () => { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('get '); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); @@ -35,7 +35,7 @@ describe('content-type get command', () => { }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], diff --git a/src/commands/content-type/import.spec.ts b/src/commands/content-type/import.spec.ts index 21457526..3f0d64f1 100644 --- a/src/commands/content-type/import.spec.ts +++ b/src/commands/content-type/import.spec.ts @@ -507,7 +507,7 @@ describe('content-type import command', (): void => { }), new Map([]) ) - ).rejects.toThrowError( + ).rejects.toThrow( new Error('Invalid format supplied for repositories. Please provide an array of repository names') ); }); @@ -522,7 +522,7 @@ describe('content-type import command', (): void => { }), new Map([]) ) - ).rejects.toThrowError( + ).rejects.toThrow( new Error('Invalid format supplied for repositories. Please provide an array of repository names') ); }); @@ -786,7 +786,7 @@ describe('content-type import command', (): void => { }); }); - describe('validateNoDuplicateContentTypeUris', function() { + describe('validateNoDuplicateContentTypeUris', function () { it('should not throw an error when there are no duplicates', () => { const contentTypesToProcess = { 'file-1': new ContentTypeWithRepositoryAssignments({ @@ -927,12 +927,22 @@ describe('content-type import command', (): void => { ); }); - it('should throw an error when no content found in import directory', async (): Promise => { + it('should exit early when no content found in import directory', async (): Promise => { const argv = { ...yargArgs, ...config, dir: 'my-empty-dir', sync: false, logFile: new FileLog() }; (loadJsonFromDirectory as jest.Mock).mockReturnValue([]); - await expect(handler(argv)).rejects.toThrowErrorMatchingSnapshot(); + await handler(argv); + + expect(argv.logFile.closed).toBeTruthy(); + expect(argv.logFile.accessGroup).toMatchInlineSnapshot(` +Array [ + Object { + "comment": true, + "data": "No content types found in my-empty-dir", + }, +] +`); }); }); }); diff --git a/src/commands/content-type/import.ts b/src/commands/content-type/import.ts index deb3e9a7..dae0bc58 100644 --- a/src/commands/content-type/import.ts +++ b/src/commands/content-type/import.ts @@ -11,6 +11,7 @@ import { streamTableOptions } from '../../common/table/table.consts'; import { ImportBuilderOptions } from '../../interfaces/import-builder-options.interface'; import { FileLog } from '../../common/file-log'; import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { progressBar } from '../../common/progress-bar/progress-bar'; export const command = 'import '; @@ -256,13 +257,14 @@ export const processContentTypes = async ( log: FileLog, skipAssign = false ): Promise => { - const data: string[][] = []; const contentRepositoryList = await paginator(hub.related.contentRepositories.list, {}); const namedRepositories: MappedContentRepositories = new Map( contentRepositoryList.map(value => [value.name || '', value]) ); - data.push([chalk.bold('ID'), chalk.bold('Schema ID'), chalk.bold('Result')]); + const progress = progressBar(contentTypes.length, 0, { title: 'Importing content types' }); + + const data: [string, string, string][] = [[chalk.bold('ID'), chalk.bold('Schema ID'), chalk.bold('Result')]]; for (const contentType of contentTypes) { let status: ImportResult; let contentTypeResult: ContentType; @@ -297,8 +299,10 @@ export const processContentTypes = async ( status = contentType.id ? 'UPDATED' : 'CREATED'; } + progress.increment(); data.push([contentTypeResult.id || 'UNKNOWN', contentType.contentTypeUri || '', status]); } + progress.stop(); log.appendLine(table(data, streamTableOptions)); @@ -311,8 +315,6 @@ export const processContentTypes = async ( '\nContent types were not automatically registered to the repositories because of --skipAssign argument.' ); } - - log.appendLine(); }; export const handler = async ( @@ -320,12 +322,15 @@ export const handler = async ( idFilter?: string[] ): Promise => { const { dir, sync, logFile, skipAssign } = argv; + const log = logFile.open(); const importedContentTypes = loadJsonFromDirectory( dir, ContentTypeWithRepositoryAssignments ); if (Object.keys(importedContentTypes).length === 0) { - throw new Error(`No content types found in ${dir}`); + log.appendLine(`No content types found in ${dir}`); + await log.close(); + return; } validateNoDuplicateContentTypeUris(importedContentTypes); @@ -335,7 +340,6 @@ export const handler = async ( const client = dynamicContentClientFactory(argv); const hub = await client.hubs.get(argv.hubId); - const log = logFile.open(); const activeContentTypes = await paginator(hub.related.contentTypes.list, { status: Status.ACTIVE }); const archivedContentTypes = await paginator(hub.related.contentTypes.list, { status: Status.ARCHIVED }); diff --git a/src/commands/content-type/list.spec.ts b/src/commands/content-type/list.spec.ts index 6c00fa74..046feb1d 100644 --- a/src/commands/content-type/list.spec.ts +++ b/src/commands/content-type/list.spec.ts @@ -67,15 +67,15 @@ describe('content-type list command', (): void => { const argv = { ...yargArgs, ...config, ...pagingOptions }; await handler(argv); - expect(mockGetHub).toBeCalledWith('hub-id'); - expect(mockList).toBeCalledWith({ size: DEFAULT_SIZE, ...pagingOptions }); + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(mockList).toHaveBeenCalledWith({ size: DEFAULT_SIZE, ...pagingOptions }); expect(mockDataPresenter).toHaveBeenCalledWith(plainListContentTypes); expect(mockDataPresenter.mock.instances[0].render).toHaveBeenCalledWith({ json: argv.json, itemMapFn }); }); - describe('itemMapFn tests', function() { - it('should render settings.label', function() { + describe('itemMapFn tests', function () { + it('should render settings.label', function () { const result = itemMapFn( new ContentType({ id: 'id', @@ -96,7 +96,7 @@ describe('content-type list command', (): void => { }); }); - it('should default settings.label to empty string', function() { + it('should default settings.label to empty string', function () { const result = itemMapFn( new ContentType({ id: 'id', diff --git a/src/commands/content-type/register.spec.ts b/src/commands/content-type/register.spec.ts index 641984de..e09acc3f 100644 --- a/src/commands/content-type/register.spec.ts +++ b/src/commands/content-type/register.spec.ts @@ -12,7 +12,7 @@ describe('content-type register command', () => { expect(command).toEqual('register'); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'src/index.ts', _: ['content-type', 'register'], @@ -164,7 +164,7 @@ describe('content-type register command', () => { await handler(argv); - expect(mockGetHub).toBeCalledWith('hub-id'); + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); expect(mockRegister).toHaveBeenCalledWith(expect.objectContaining(registerResponse.toJSON())); expect(mockDataPresenter).toHaveBeenCalledWith(plainContentType); expect(mockDataPresenter.mock.instances[0].render).toHaveBeenCalledWith({ diff --git a/src/commands/content-type/sync.spec.ts b/src/commands/content-type/sync.spec.ts index 0ffb7713..84e8d3c1 100644 --- a/src/commands/content-type/sync.spec.ts +++ b/src/commands/content-type/sync.spec.ts @@ -25,12 +25,12 @@ describe('ContentType.sync', () => { afterEach((): void => { jest.restoreAllMocks(); }); - it('should command should defined', function() { - expect(command).toEqual('sync '); + it('should have an optional id', function () { + expect(command).toEqual('sync [id]'); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); @@ -45,7 +45,7 @@ describe('ContentType.sync', () => { }); }); - describe('handler tests', function() { + describe('handler tests', function () { it('should sync a content type with the schema', async () => { const mockGet = jest.fn(); const mockUpdate = jest.fn(); diff --git a/src/commands/content-type/sync.ts b/src/commands/content-type/sync.ts index aaaddfc1..9438d0c9 100644 --- a/src/commands/content-type/sync.ts +++ b/src/commands/content-type/sync.ts @@ -5,8 +5,11 @@ import { ContentType, ContentTypeCachedSchema } from 'dc-management-sdk-js'; import { ConfigurationParameters } from '../configure'; import BuilderOptions from '../../interfaces/builder-options'; import { singleItemTableOptions } from '../../common/table/table.consts'; +import paginator from '../../common/dc-management-sdk-js/paginator'; +import { extractSortable, PagingParameters } from '../../common/yargs/sorting-options'; +import { progressBar } from '../../common/progress-bar/progress-bar'; -export const command = 'sync '; +export const command = 'sync [id]'; export const desc = 'Sync Content Type with the schema'; @@ -20,10 +23,44 @@ export const builder = (yargs: Argv): void => { }; export const handler = async ( - argv: Arguments + argv: Arguments ): Promise => { const client = dynamicContentClientFactory(argv); + if (!argv.id) { + const hub = await client.hubs.get(argv.hubId); + const contentTypeList = await paginator(hub.related.contentTypes.list, extractSortable(argv)); + const updatedContentTypeSchemas: ContentTypeCachedSchema[] = []; + + if (contentTypeList.length === 0) { + console.log('No content types found to sync, aborting.'); + return; + } + + const progress = progressBar(contentTypeList.length, 0, { + title: `Syncing ${contentTypeList.length} content types` + }); + + try { + for (const contentType of contentTypeList) { + const updatedContentTypeSchema = await contentType.related.contentTypeSchema.update(); + updatedContentTypeSchemas.push(updatedContentTypeSchema); + progress.increment(); + } + } catch (e) { + throw e; + } finally { + progress.stop(); + } + + new DataPresenter(updatedContentTypeSchemas.map(v => v.toJSON())).render({ + json: argv.json, + itemMapFn + }); + + return; + } + const contentType: ContentType = await client.contentTypes.get(argv.id); const contentTypeCachedSchema: ContentTypeCachedSchema = await contentType.related.contentTypeSchema.update(); new DataPresenter(contentTypeCachedSchema.toJSON()).render({ @@ -31,3 +68,8 @@ export const handler = async ( tableUserConfig: singleItemTableOptions }); }; + +export const itemMapFn = ({ hubId, contentTypeUri }: ContentTypeCachedSchema): object => ({ + hubId, + contentTypeUri +}); diff --git a/src/commands/content-type/unarchive.spec.ts b/src/commands/content-type/unarchive.spec.ts index 1398da91..f82c14a8 100644 --- a/src/commands/content-type/unarchive.spec.ts +++ b/src/commands/content-type/unarchive.spec.ts @@ -1,6 +1,6 @@ import { builder, command, handler, LOG_FILENAME } from './unarchive'; import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; -import { ContentType, Hub } from 'dc-management-sdk-js'; +import { ContentType, HttpError, Hub } from 'dc-management-sdk-js'; import Yargs from 'yargs/yargs'; import MockPage from '../../common/dc-management-sdk-js/mock-page'; import { dirname } from 'path'; @@ -17,12 +17,12 @@ describe('content-type unarchive command', () => { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('unarchive [id]'); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); @@ -74,7 +74,7 @@ describe('content-type unarchive command', () => { }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'], @@ -612,64 +612,107 @@ describe('content-type unarchive command', () => { await handler(argv); }); - it('should exit cleanly when revert log is missing', async () => { + it('should throw an error when revert log is missing', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockHubGet = jest.fn(); + const mockHubList = jest.fn(); + + const mockHub = new Hub(); + mockHubList.mockResolvedValue( + generateMockTypeList([{ name: 'name', schemaId: 'http://schemas.com/schema1' }], () => {}, false) + ); + mockHub.related.contentTypes.list = mockHubList; + mockHubGet.mockResolvedValue(mockHub); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockHubGet + } + }); + const argv = { ...yargArgs, ...config, - logFile: LOG_FILENAME(), - force: true, + schemaId: 'http://schemas.com/schema1', silent: true, revertLog: 'doesntExist.txt' }; - await handler(argv); + + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error - could not read archive log']); }); - it('should exit cleanly when hub is not configured, or on invalid input.', async () => { - // Content list/get is not init, so it will throw. + it('should throw an error when fails to get content type by id', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockGet = jest.fn(); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + contentTypes: { + get: mockGet + } + }); + + mockGet.mockRejectedValue(new HttpError('Failed to get content type by id')); + + const argv = { + ...yargArgs, + ...config, + silent: true, + id: 'test-content-type-id' + }; + + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error: could not find content type with ID test-content-type-id']); + }); + it('should throw an error when fails to get hub by id', async () => { + const logSpy = jest.spyOn(console, 'log'); const mockHubGet = jest.fn(); + mockHubGet.mockRejectedValue(new HttpError('Failed to get hub by id')); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ hubs: { get: mockHubGet } }); - const mockHub = new Hub(); - mockHubGet.mockResolvedValue(mockHub); - - // All const argv = { ...yargArgs, ...config, - logFile: LOG_FILENAME(), - force: true, + schemaId: 'http://schemas.com/schema1', silent: true }; - await handler(argv); - // Id - const argv2 = { - ...yargArgs, - ...config, - logFile: LOG_FILENAME(), - force: true, - silent: true, - id: 'test' - }; - await handler(argv2); + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error: could not retrieve content types to unarchive']); + }); + + it('should throw an error when fails to list hub content types', async () => { + const logSpy = jest.spyOn(console, 'log'); + const mockHubGet = jest.fn(); + const mockHubList = jest.fn(); - // Id and Schema id - const argv3 = { + const mockHub = new Hub(); + mockHubList.mockRejectedValue(new HttpError('Failed to list content types')); + mockHub.related.contentTypes.list = mockHubList; + mockHubGet.mockResolvedValue(mockHub); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockHubGet + } + }); + + const argv = { ...yargArgs, ...config, - logFile: LOG_FILENAME(), - force: true, - silent: true, - id: 'test', - schemaId: 'conflict' + schemaId: 'http://schemas.com/schema1', + silent: true }; - await handler(argv3); + + await expect(handler(argv)).resolves.toBeUndefined(); + expect(logSpy.mock.lastCall).toEqual(['Fatal error: could not retrieve content types to unarchive']); }); }); }); diff --git a/src/commands/content-type/unarchive.ts b/src/commands/content-type/unarchive.ts index 2ecc99db..a8ed90a9 100644 --- a/src/commands/content-type/unarchive.ts +++ b/src/commands/content-type/unarchive.ts @@ -5,7 +5,7 @@ import dynamicContentClientFactory from '../../services/dynamic-content-client-f import { ArchiveLog } from '../../common/archive/archive-log'; import { equalsOrRegex } from '../../common/filter/filter'; import paginator from '../../common/dc-management-sdk-js/paginator'; -import { confirmArchive } from '../../common/archive/archive-helpers'; +import { confirmAllContent } from '../../common/content-item/confirm-all-content'; import UnarchiveOptions from '../../common/archive/unarchive-options'; import { getDefaultLogPath } from '../../common/log-helpers'; @@ -76,7 +76,7 @@ export const handler = async (argv: Arguments { expect(command).toEqual('update '); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); diff --git a/src/commands/event.spec.ts b/src/commands/event.spec.ts index f5889343..0f94db66 100644 --- a/src/commands/event.spec.ts +++ b/src/commands/event.spec.ts @@ -1,12 +1,17 @@ import { builder } from './event'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; import Yargs from 'yargs/yargs'; +import { configureCommandOptions } from './configure'; -describe('event command', function() { +describe('event command', function () { it('should include the commands in the event dir', () => { const argv = Yargs(process.argv.slice(2)); const spyCommandDir = jest.spyOn(argv, 'commandDir').mockReturnValue(argv); + const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); + const spyConfig = jest.spyOn(argv, 'config').mockReturnThis(); builder(argv); expect(spyCommandDir).toHaveBeenCalledWith('event', YargsCommandBuilderOptions); + expect(spyOptions).toHaveBeenCalledWith(configureCommandOptions); + expect(spyConfig).toHaveBeenCalledWith('config', expect.any(Function)); }); }); diff --git a/src/commands/event.ts b/src/commands/event.ts index 1133340c..768f1003 100644 --- a/src/commands/event.ts +++ b/src/commands/event.ts @@ -1,5 +1,7 @@ import { Argv } from 'yargs'; +import { readConfig } from '../cli'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import { configureCommandOptions } from './configure'; export const command = 'event'; @@ -8,5 +10,7 @@ export const desc = 'Event'; export const builder = (yargs: Argv): Argv => yargs .commandDir('event', YargsCommandBuilderOptions) + .options(configureCommandOptions) + .config('config', readConfig) .demandCommand() .help(); diff --git a/src/commands/event/__snapshots__/export.spec.ts.snap b/src/commands/event/__snapshots__/export.spec.ts.snap new file mode 100644 index 00000000..00814a39 --- /dev/null +++ b/src/commands/event/__snapshots__/export.spec.ts.snap @@ -0,0 +1,468 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`event export command enrichEditions tests should request and populate slots for each of the provided editions 1`] = ` +Array [ + Object { + "id": "ed1", + "name": "ed1", + "publishingStatus": "DRAFT", + "slots": Array [ + Object { + "conflicts": false, + "content": Object { + "body": Object { + "_meta": Object { + "name": "example-slot-test", + "schema": "http://schema.com/test.json", + }, + "link": Array [ + Object { + "_meta": Object { + "locked": "true", + "rootContentItemId": "content-item-1", + "schema": "http://bigcontent.io/cms/schema/v1/core#/definitions/content-link", + }, + "contentType": "http://schema.com/test.json", + "id": "snapshot1", + }, + ], + }, + }, + "contentTypeId": "testType", + "createdDate": "2021-05-06T09:52:27.065Z", + "editionId": "ed1", + "empty": false, + "eventId": "test1", + "id": "slot1", + "lastModifiedDate": "2021-05-06T09:52:27.065Z", + "locale": null, + "slotId": "testSlotId", + "slotLabel": "example-slot-test", + "slotStatus": "ACTIVE", + "status": "VALID", + }, + ], + }, +] +`; + +exports[`event export command enrichEvents tests should request and populate editions for each of the provided events 1`] = ` +Array [ + Object { + "editions": Array [ + Object { + "id": "ed1", + "name": "ed1", + "publishingStatus": "DRAFT", + "slots": Array [ + Object { + "conflicts": false, + "content": Object { + "body": Object { + "_meta": Object { + "name": "example-slot-test", + "schema": "http://schema.com/test.json", + }, + "link": Array [ + Object { + "_meta": Object { + "locked": "true", + "rootContentItemId": "content-item-1", + "schema": "http://bigcontent.io/cms/schema/v1/core#/definitions/content-link", + }, + "contentType": "http://schema.com/test.json", + "id": "snapshot1", + }, + ], + }, + }, + "contentTypeId": "testType", + "createdDate": "2021-05-06T09:52:27.065Z", + "editionId": "ed1", + "empty": false, + "eventId": "test1", + "id": "slot1", + "lastModifiedDate": "2021-05-06T09:52:27.065Z", + "locale": null, + "slotId": "testSlotId", + "slotLabel": "example-slot-test", + "slotStatus": "ACTIVE", + "status": "VALID", + }, + ], + }, + ], + "end": "2021-05-06T12:00:00.000Z", + "id": "test1", + "name": "test1", + "start": "2021-05-05T12:00:00.000Z", + }, + Object { + "editions": Array [ + Object { + "id": "ed1", + "name": "ed1", + "publishingStatus": "DRAFT", + "slots": Array [ + Object { + "conflicts": false, + "content": Object { + "body": Object { + "_meta": Object { + "name": "example-slot-test", + "schema": "http://schema.com/test.json", + }, + "link": Array [ + Object { + "_meta": Object { + "locked": "true", + "rootContentItemId": "content-item-1", + "schema": "http://bigcontent.io/cms/schema/v1/core#/definitions/content-link", + }, + "contentType": "http://schema.com/test.json", + "id": "snapshot1", + }, + ], + }, + }, + "contentTypeId": "testType", + "createdDate": "2021-05-06T09:52:27.065Z", + "editionId": "ed1", + "empty": false, + "eventId": "test1", + "id": "slot1", + "lastModifiedDate": "2021-05-06T09:52:27.065Z", + "locale": null, + "slotId": "testSlotId", + "slotLabel": "example-slot-test", + "slotStatus": "ACTIVE", + "status": "VALID", + }, + ], + }, + ], + "end": "2021-05-08T12:00:00.000Z", + "id": "test2", + "name": "test2", + "start": "2021-05-07T12:00:00.000Z", + }, +] +`; + +exports[`event export command handler tests should exit early if getting the hub fails 1`] = ` +"// dc-cli test-ver - temp/exportEvent/noHub.log +ERROR +// ERROR: Couldn't get hub with id hub-id, aborting. +// Error: Error +FAILURE" +`; + +exports[`event export command handler tests should export snapshots when --snapshots is provided 1`] = ` +Array [ + "{ + \\"name\\": \\"test1\\", + \\"id\\": \\"1\\", + \\"start\\": \\"2021-05-05T12:00:00.000Z\\", + \\"end\\": \\"2021-05-06T12:00:00.000Z\\", + \\"editions\\": [ + { + \\"name\\": \\"ed1\\", + \\"id\\": \\"ed1\\", + \\"publishingStatus\\": \\"DRAFT\\", + \\"slots\\": [ + { + \\"id\\": \\"slot1\\", + \\"eventId\\": \\"test1\\", + \\"editionId\\": \\"ed1\\", + \\"createdDate\\": \\"2021-05-06T09:52:27.065Z\\", + \\"lastModifiedDate\\": \\"2021-05-06T09:52:27.065Z\\", + \\"content\\": { + \\"body\\": { + \\"_meta\\": { + \\"schema\\": \\"http://schema.com/test.json\\", + \\"name\\": \\"example-slot-test\\" + }, + \\"link\\": [ + { + \\"_meta\\": { + \\"schema\\": \\"http://bigcontent.io/cms/schema/v1/core#/definitions/content-link\\", + \\"rootContentItemId\\": \\"content-item-1\\", + \\"locked\\": \\"true\\" + }, + \\"contentType\\": \\"http://schema.com/test.json\\", + \\"id\\": \\"snapshot1\\" + } + ] + } + }, + \\"status\\": \\"VALID\\", + \\"slotStatus\\": \\"ACTIVE\\", + \\"contentTypeId\\": \\"testType\\", + \\"slotId\\": \\"testSlotId\\", + \\"slotLabel\\": \\"example-slot-test\\", + \\"conflicts\\": false, + \\"locale\\": null, + \\"empty\\": false + } + ] + } + ] +}", + "{ + \\"id\\": \\"snapshot-1\\", + \\"comment\\": \\"\\", + \\"createdDate\\": \\"2018-04-04T16:00:06.945Z\\", + \\"createdBy\\": \\"user\\", + \\"createdFrom\\": \\"content-item\\", + \\"type\\": \\"USER\\", + \\"meta\\": [], + \\"taggedEditions\\": [ + { + \\"editionId\\": \\"ed1\\", + \\"createdDate\\": \\"2018-04-04T16:00:07Z\\", + \\"createdBy\\": \\"user\\" + } + ], + \\"locale\\": null, + \\"rootContentItem\\": { + \\"label\\": \\"Content Item\\", + \\"contentTypeUri\\": \\"http://schema.com/test.json\\", + \\"id\\": \\"content-item-1\\" + }, + \\"rootContentItems\\": [ + { + \\"label\\": \\"Content Item\\", + \\"contentTypeUri\\": \\"http://schema.com/test.json\\", + \\"id\\": \\"content-item-1\\" + } + ], + \\"content\\": [ + { + \\"id\\": \\"content-item-1\\", + \\"contentRepositoryId\\": \\"repo1\\", + \\"body\\": { + \\"_meta\\": { + \\"name\\": \\"test\\", + \\"schema\\": \\"http://schema.com/test.json\\" + }, + \\"simpleContent\\": \\"test\\" + }, + \\"version\\": 9, + \\"label\\": \\"Content Item\\", + \\"status\\": \\"ACTIVE\\" + } + ] +}", +] +`; + +exports[`event export command handler tests should export snapshots when --snapshots is provided 2`] = ` +"// dc-cli test-ver - temp/exportEvent/snapshots.log +// Exporting single event test1. +// Fetching test1 with editions. +// Scanning slots for snapshots. +// Saving 1 snapshots to './snapshots/'. +// Fetching snapshot snapshot1. +// Done. +SUCCESS" +`; + +exports[`event export command handler tests should list and export a single edition 1`] = ` +Array [ + "{ + \\"name\\": \\"test1\\", + \\"id\\": \\"1\\", + \\"start\\": \\"2021-05-05T12:00:00.000Z\\", + \\"end\\": \\"2021-05-06T12:00:00.000Z\\", + \\"editions\\": [ + { + \\"name\\": \\"ed1\\", + \\"id\\": \\"ed1\\", + \\"publishingStatus\\": \\"DRAFT\\", + \\"slots\\": [ + { + \\"id\\": \\"slot1\\", + \\"eventId\\": \\"test1\\", + \\"editionId\\": \\"ed1\\", + \\"createdDate\\": \\"2021-05-06T09:52:27.065Z\\", + \\"lastModifiedDate\\": \\"2021-05-06T09:52:27.065Z\\", + \\"content\\": { + \\"body\\": { + \\"_meta\\": { + \\"schema\\": \\"http://schema.com/test.json\\", + \\"name\\": \\"example-slot-test\\" + }, + \\"link\\": [ + { + \\"_meta\\": { + \\"schema\\": \\"http://bigcontent.io/cms/schema/v1/core#/definitions/content-link\\", + \\"rootContentItemId\\": \\"content-item-1\\", + \\"locked\\": \\"true\\" + }, + \\"contentType\\": \\"http://schema.com/test.json\\", + \\"id\\": \\"snapshot1\\" + } + ] + } + }, + \\"status\\": \\"VALID\\", + \\"slotStatus\\": \\"ACTIVE\\", + \\"contentTypeId\\": \\"testType\\", + \\"slotId\\": \\"testSlotId\\", + \\"slotLabel\\": \\"example-slot-test\\", + \\"conflicts\\": false, + \\"locale\\": null, + \\"empty\\": false + } + ] + } + ] +}", +] +`; + +exports[`event export command handler tests should list and export a single edition 2`] = ` +"// dc-cli test-ver - temp/exportEvent/single.log +// Exporting single event test1. +// Fetching test1 with editions. +// Done. +SUCCESS" +`; + +exports[`event export command handler tests should list and export all editions 1`] = ` +Array [ + "{ + \\"id\\": \\"test1\\", + \\"name\\": \\"test1\\", + \\"start\\": \\"2021-05-05T12:00:00.000Z\\", + \\"end\\": \\"2021-05-06T12:00:00.000Z\\", + \\"editions\\": [ + { + \\"name\\": \\"ed1\\", + \\"id\\": \\"ed1\\", + \\"publishingStatus\\": \\"DRAFT\\", + \\"slots\\": [ + { + \\"id\\": \\"slot1\\", + \\"eventId\\": \\"test1\\", + \\"editionId\\": \\"ed1\\", + \\"createdDate\\": \\"2021-05-06T09:52:27.065Z\\", + \\"lastModifiedDate\\": \\"2021-05-06T09:52:27.065Z\\", + \\"content\\": { + \\"body\\": { + \\"_meta\\": { + \\"schema\\": \\"http://schema.com/test.json\\", + \\"name\\": \\"example-slot-test\\" + }, + \\"link\\": [ + { + \\"_meta\\": { + \\"schema\\": \\"http://bigcontent.io/cms/schema/v1/core#/definitions/content-link\\", + \\"rootContentItemId\\": \\"content-item-1\\", + \\"locked\\": \\"true\\" + }, + \\"contentType\\": \\"http://schema.com/test.json\\", + \\"id\\": \\"snapshot1\\" + } + ] + } + }, + \\"status\\": \\"VALID\\", + \\"slotStatus\\": \\"ACTIVE\\", + \\"contentTypeId\\": \\"testType\\", + \\"slotId\\": \\"testSlotId\\", + \\"slotLabel\\": \\"example-slot-test\\", + \\"conflicts\\": false, + \\"locale\\": null, + \\"empty\\": false + } + ] + } + ] +}", + "{ + \\"id\\": \\"test2\\", + \\"name\\": \\"test2\\", + \\"start\\": \\"2021-05-07T12:00:00.000Z\\", + \\"end\\": \\"2021-05-08T12:00:00.000Z\\", + \\"editions\\": [ + { + \\"name\\": \\"ed1\\", + \\"id\\": \\"ed1\\", + \\"publishingStatus\\": \\"DRAFT\\", + \\"slots\\": [ + { + \\"id\\": \\"slot1\\", + \\"eventId\\": \\"test1\\", + \\"editionId\\": \\"ed1\\", + \\"createdDate\\": \\"2021-05-06T09:52:27.065Z\\", + \\"lastModifiedDate\\": \\"2021-05-06T09:52:27.065Z\\", + \\"content\\": { + \\"body\\": { + \\"_meta\\": { + \\"schema\\": \\"http://schema.com/test.json\\", + \\"name\\": \\"example-slot-test\\" + }, + \\"link\\": [ + { + \\"_meta\\": { + \\"schema\\": \\"http://bigcontent.io/cms/schema/v1/core#/definitions/content-link\\", + \\"rootContentItemId\\": \\"content-item-1\\", + \\"locked\\": \\"true\\" + }, + \\"contentType\\": \\"http://schema.com/test.json\\", + \\"id\\": \\"snapshot1\\" + } + ] + } + }, + \\"status\\": \\"VALID\\", + \\"slotStatus\\": \\"ACTIVE\\", + \\"contentTypeId\\": \\"testType\\", + \\"slotId\\": \\"testSlotId\\", + \\"slotLabel\\": \\"example-slot-test\\", + \\"conflicts\\": false, + \\"locale\\": null, + \\"empty\\": false + } + ] + } + ] +}", +] +`; + +exports[`event export command handler tests should list and export all editions 2`] = ` +"// dc-cli test-ver - temp/exportEvent/all.log +// Exporting 2 of 2 events... +// Fetching test1 with editions. +// Fetching test2 with editions. +// Done. +SUCCESS" +`; + +exports[`event export command handler tests should log an error when getting a single event fails 1`] = ` +"// dc-cli test-ver - temp/exportEvent/singleError.log +ERROR +// ERROR: Failed to get event with id missing, aborting. +// Error: Error +FAILURE" +`; + +exports[`event export command handler tests should log an error when listing events fails 1`] = ` +"// dc-cli test-ver - temp/exportEvent/listError.log +ERROR +// ERROR: Failed to list events. +// Error: Error +// No events to export from this hub, exiting. +// Done. +FAILURE" +`; + +exports[`event export command handler tests should pass from and to date parameters to filterEvents 2`] = ` +"// dc-cli test-ver - temp/exportEvent/date.log +// Exporting 0 of 2 events... +// No events to export from this hub, exiting. +// Done. +SUCCESS" +`; diff --git a/src/commands/event/archive.spec.ts b/src/commands/event/archive.spec.ts index b4fc336a..049bb8ce 100644 --- a/src/commands/event/archive.spec.ts +++ b/src/commands/event/archive.spec.ts @@ -31,12 +31,12 @@ describe('event archive command', () => { logFile: new FileLog() }; - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('archive [id]'); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); @@ -74,7 +74,7 @@ describe('event archive command', () => { }); }); - it('should generate a log with coerceLog with the appropriate title', function() { + it('should generate a log with coerceLog with the appropriate title', function () { const logFile = coerceLog('filename.log'); expect(logFile).toEqual(expect.any(FileLog)); @@ -91,6 +91,7 @@ describe('event archive command', () => { getEventError = false }): { mockGet: () => void; + mockEditionGet: () => void; mockEditionsList: () => void; deleteMock: () => void; archiveMock: () => void; @@ -98,6 +99,7 @@ describe('event archive command', () => { mockEventsList: () => void; } => { const mockGet = jest.fn(); + const mockEditionGet = jest.fn(); const mockEditionsList = jest.fn(); const deleteMock = jest.fn(); const archiveMock = jest.fn(); @@ -118,6 +120,9 @@ describe('event archive command', () => { delete: deleteMock, archive: archiveMock } + }, + editions: { + get: mockEditionGet } }); @@ -291,6 +296,8 @@ describe('event archive command', () => { } mockEditionsList.mockResolvedValue(new MockPage(Edition, editions)); + mockEditionGet.mockResolvedValue({ ...editions[0], publishingStatus: 'DRAFT' }); + if (archiveError) { archiveMock.mockRejectedValue(new Error('Error')); deleteMock.mockRejectedValue(new Error('Error')); @@ -306,6 +313,7 @@ describe('event archive command', () => { return { mockGet, + mockEditionGet, mockEditionsList, archiveMock, deleteMock, @@ -314,7 +322,7 @@ describe('event archive command', () => { }; }; - describe('handler tests', function() { + describe('handler tests', function () { it('should delete event with draft edition', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any (readline as any).setResponses(['y']); @@ -330,7 +338,7 @@ describe('event archive command', () => { expect(mockGet).toHaveBeenCalled(); expect(mockEditionsList).toHaveBeenCalled(); - expect(deleteMock).toBeCalledTimes(1); + expect(deleteMock).toHaveBeenCalledTimes(1); }); it('should archive event with published', async () => { @@ -348,7 +356,7 @@ describe('event archive command', () => { expect(mockGet).toHaveBeenCalled(); expect(mockEditionsList).toHaveBeenCalled(); - expect(archiveMock).toBeCalledTimes(2); + expect(archiveMock).toHaveBeenCalledTimes(2); }); it('should archive events when multiple ids provided', async () => { @@ -366,7 +374,7 @@ describe('event archive command', () => { expect(mockGet).toHaveBeenCalledTimes(4); expect(mockEditionsList).toHaveBeenCalledTimes(2); - expect(archiveMock).toBeCalledTimes(4); + expect(archiveMock).toHaveBeenCalledTimes(4); }); it('should delete event with scheduled edition', async () => { @@ -384,7 +392,30 @@ describe('event archive command', () => { expect(mockGet).toHaveBeenCalled(); expect(mockEditionsList).toHaveBeenCalled(); - expect(deleteMock).toBeCalledTimes(2); + expect(deleteMock).toHaveBeenCalledTimes(2); + }); + + it('should archive event with published+scheduled edition, after deleting the scheduled one', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['y']); + + const { mockGet, mockEditionsList, deleteMock, archiveMock, mockEditionGet } = mockValues({ + status: 'SCHEDULED', + mixedEditions: true + }); + + const argv = { + ...yargArgs, + ...config, + id: '1' + }; + await handler(argv); + + expect(mockGet).toHaveBeenCalled(); + expect(mockEditionGet).toHaveBeenCalled(); + expect(mockEditionsList).toHaveBeenCalled(); + expect(deleteMock).toHaveBeenCalledTimes(2); + expect(archiveMock).toHaveBeenCalledTimes(2); }); it("shouldn't archive event, no id", async () => { @@ -422,7 +453,7 @@ describe('event archive command', () => { expect(mockEventsList).toHaveBeenCalled(); expect(mockEditionsList).toHaveBeenCalled(); expect(mockGet).toHaveBeenCalled(); - expect(deleteMock).toBeCalledTimes(2); + expect(deleteMock).toHaveBeenCalledTimes(2); }); it("shouldn't archive event by name", async () => { @@ -460,7 +491,7 @@ describe('event archive command', () => { expect(mockGet).toHaveBeenCalled(); expect(mockEditionsList).toHaveBeenCalled(); - expect(deleteMock).toBeCalledTimes(0); + expect(deleteMock).toHaveBeenCalledTimes(0); }); it('should log error, no resource', async () => { diff --git a/src/commands/event/archive.ts b/src/commands/event/archive.ts index 9f8e05d9..d80d6997 100644 --- a/src/commands/event/archive.ts +++ b/src/commands/event/archive.ts @@ -2,9 +2,9 @@ import { Arguments, Argv } from 'yargs'; import { ConfigurationParameters } from '../configure'; import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; import paginator from '../../common/dc-management-sdk-js/paginator'; -import { confirmArchive } from '../../common/archive/archive-helpers'; +import { confirmAllContent } from '../../common/content-item/confirm-all-content'; import ArchiveEventOptions from '../../common/archive/archive-event-options'; -import { Edition, Event, DynamicContent } from 'dc-management-sdk-js'; +import { Edition, Event, DynamicContent, HalResource } from 'dc-management-sdk-js'; import { equalsOrRegex } from '../../common/filter/filter'; import { createLog, getDefaultLogPath } from '../../common/log-helpers'; import { FileLog } from '../../common/file-log'; @@ -50,23 +50,23 @@ export const builder = (yargs: Argv): void => { }); }; -const getEventUntilSuccess = async ({ +const getResourceUntilSuccess = async ({ id = '', resource = 'archive', - client + getter }: { id: string; resource: string; - client: DynamicContent; -}): Promise => { + getter: (id: string) => Promise; +}): Promise => { let resourceEvent; for (let i = 0; i < maxAttempts; i++) { - const event: Event = await client.events.get(id); + const obj: HalResource = await getter(id); // eslint-disable-next-line @typescript-eslint/no-explicit-any - const link = event._links && (event._links as any)[resource]; + const link = obj._links && (obj._links as any)[resource]; if (link) { - resourceEvent = event; + resourceEvent = obj; break; } } @@ -74,6 +74,30 @@ const getEventUntilSuccess = async ({ return resourceEvent; }; +const getEventUntilSuccess = async ({ + id = '', + resource = 'archive', + client +}: { + id: string; + resource: string; + client: DynamicContent; +}): Promise => { + return (await getResourceUntilSuccess({ id, resource, getter: client.events.get })) as Event | undefined; +}; + +const getEditionUntilSuccess = async ({ + id = '', + resource = 'archive', + client +}: { + id: string; + resource: string; + client: DynamicContent; +}): Promise => { + return (await getResourceUntilSuccess({ id, resource, getter: client.editions.get })) as Edition | undefined; +}; + export const getEvents = async ({ id, client, @@ -204,7 +228,7 @@ export const processItems = async ({ console.log(`Total: ${events.length}`); if (!force) { - const yes = await confirmArchive('perform', 'actions', false, missingContent); + const yes = await confirmAllContent('perform', 'actions', false, missingContent); if (!yes) { return; } @@ -216,7 +240,31 @@ export const processItems = async ({ for (let i = 0; i < events.length; i++) { try { - await Promise.all(events[i].unscheduleEditions.map(edition => edition.related.unschedule())); + const index = i; + + await Promise.all( + events[i].unscheduleEditions.map(async edition => { + await edition.related.unschedule(); + + if (events[index].command === 'ARCHIVE') { + // Unscheduled editions need to be deleted before the event can be archived. + const unscheduled = await getEditionUntilSuccess({ + id: edition.id as string, + resource: 'delete', + client + }); + + if (unscheduled) { + await unscheduled.related.delete(); + } else { + log.addComment(`UNSCHEDULE+DELETE FAILED: ${edition.id}`); + log.addComment( + `The edition may have taken too long to unschedule. Try again later or contact support.` + ); + } + } + }) + ); if (events[i].command === 'ARCHIVE') { await Promise.all(events[i].deleteEditions.map(edition => edition.related.delete())); diff --git a/src/commands/event/event-test-helpers.ts b/src/commands/event/event-test-helpers.ts new file mode 100644 index 00000000..7482cf3b --- /dev/null +++ b/src/commands/event/event-test-helpers.ts @@ -0,0 +1,368 @@ +import { Hub, Event, Edition, EditionSlot, Snapshot, ContentItem } from 'dc-management-sdk-js'; +import MockPage from '../../common/dc-management-sdk-js/mock-page'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; + +export const mockValues = ({ + status = 'DRAFT', + deleteResource = false, + mixedEditions = false, + getHubError = false, + getEventError = false, + listEventError = false, + listEditionError = false, + getSnapshotError = false +}): { + mockGet: () => void; + mockEditionsList: () => void; + mockEditionGet: () => void; + mockEditionUpdate: () => void; + getHubMock: () => void; + mockEventsList: () => void; + mockEventUpdate: () => void; + mockEventCreate: () => void; + mockSlotsList: () => void; + mockSlotContent: () => void; + mockSnapshotGet: () => void; + mockSnapshotItem: () => void; + mockSnapshotCreate: () => void; + mockEditionUnschedule: () => void; + mockEdition: Edition; +} => { + const mockGet = jest.fn(); + const getHubMock = jest.fn(); + const mockEditionsList = jest.fn(); + const mockEditionGet = jest.fn(); + const mockEditionUpdate = jest.fn(); + const mockEventsList = jest.fn(); + const mockEventUpdate = jest.fn(); + const mockEventCreate = jest.fn(); + const mockSlotsList = jest.fn(); + const mockSlotContent = jest.fn(); + const mockSnapshotGet = jest.fn(); + const mockSnapshotItem = jest.fn(); + const mockSnapshotCreate = jest.fn(); + const mockEditionUnschedule = jest.fn(); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: getHubMock + }, + events: { + get: mockGet + }, + editions: { + get: mockEditionGet + }, + snapshots: { + get: mockSnapshotGet + } + }); + + const hub = new Hub({ + name: '1', + id: '1', + _links: { + events: { + href: 'https://api.amplience.net/v2/content/events', + templated: true + } + } + }); + + getHubMock.mockResolvedValue(hub); + + hub.related.events.list = mockEventsList; + hub.related.events.create = mockEventCreate; + hub.related.snapshots.create = mockSnapshotCreate; + + const events = [ + new Event({ + id: 'test1', + name: 'test1', + start: '2021-05-05T12:00:00.000Z', + end: '2021-05-06T12:00:00.000Z', + client: { + fetchLinkedResource: mockEditionsList + }, + _links: { + editions: { + href: 'https://api.amplience.net/v2/content/events/1/editions{?projection,page,size,sort}', + templated: true + }, + delete: { + href: 'https://api.amplience.net/v2/content/events/1' + }, + archive: { + href: 'https://api.amplience.net/v2/content/events/1/archive' + } + }, + related: { + editions: { + list: mockEditionsList + } + } + }), + new Event({ + id: 'test2', + name: 'test2', + start: '2021-05-07T12:00:00.000Z', + end: '2021-05-08T12:00:00.000Z', + client: { + fetchLinkedResource: mockEditionsList + }, + _links: { + editions: { + href: 'https://api.amplience.net/v2/content/events/2/editions{?projection,page,size,sort}', + templated: true + }, + delete: { + href: 'https://api.amplience.net/v2/content/events/2' + }, + archive: { + href: 'https://api.amplience.net/v2/content/events/2/archive' + } + }, + related: { + editions: { + list: mockEditionsList + } + } + }) + ]; + + mockEventsList.mockResolvedValue(new MockPage(Event, events)); + + const event = new Event({ + name: 'test1', + id: '1', + start: '2021-05-05T12:00:00.000Z', + end: '2021-05-06T12:00:00.000Z', + client: { + fetchLinkedResource: mockEditionsList + }, + _links: { + editions: { + href: 'https://api.amplience.net/v2/content/events/1/editions{?projection,page,size,sort}', + templated: true + }, + delete: !deleteResource && { + href: 'https://api.amplience.net/v2/content/events/1' + }, + archive: { + href: 'https://api.amplience.net/v2/content/events/1/archive' + } + }, + related: { + editions: { + list: mockEditionsList + } + } + }); + + mockGet.mockResolvedValue(event); + + event.related.update = mockEventUpdate; + + const editions = [ + new Edition({ + name: 'ed1', + id: 'ed1', + publishingStatus: status, + client: { + fetchLinkedResource: mockSlotsList + }, + _links: { + 'list-slots': { + href: 'https://api.amplience.net/v2/content/editions/ed1/slots{?includedSlots}', + templated: true + }, + archive: { + href: 'https://api.amplience.net/v2/content/editions/ed1/archive' + }, + delete: { + href: 'https://api.amplience.net/v2/content/editions/ed1' + }, + schedule: { + href: 'https://api.amplience.net/v2/content/editions/ed1/schedule' + } + } + }) + ]; + + const slots = [ + new EditionSlot({ + id: 'slot1', + eventId: 'test1', + editionId: 'ed1', + createdDate: '2021-05-06T09:52:27.065Z', + lastModifiedDate: '2021-05-06T09:52:27.065Z', + content: { + body: { + _meta: { schema: 'http://schema.com/test.json', name: 'example-slot-test' }, + link: [ + { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-link', + rootContentItemId: 'content-item-1', + locked: 'true' + }, + contentType: 'http://schema.com/test.json', + id: 'snapshot1' + } + ] + } + }, + status: 'VALID', + slotStatus: 'ACTIVE', + contentTypeId: 'testType', + slotId: 'testSlotId', + slotLabel: 'example-slot-test', + conflicts: false, + locale: null, + empty: false, + _links: { + self: { + href: 'https://api.amplience.net/v2/content/editions/ed1/slots/slot1' + }, + 'edition-slot': { + href: 'https://api.amplience.net/v2/content/editions/ed1/slots/slot1' + }, + edition: { + href: 'https://api.amplience.net/v2/content/editions/ed1' + }, + slot: { + href: 'https://api.amplience.net/v2/content/content-items/testSlotId{?projection}', + templated: true + }, + content: { + href: 'https://api.amplience.net/v2/content/editions/ed1/slots/slot1/content' + }, + 'safe-update-content': { + href: 'https://api.amplience.net/v2/content/editions/ed1/slots/slot1/content{?lastModifiedDate,page,size,sort}', + templated: true + } + } + }) + ]; + + if (mixedEditions) { + editions.push( + new Edition({ + name: 'ed2', + id: 'ed2', + publishingStatus: 'PUBLISHED', + client: { + fetchLinkedResource: mockEventsList + }, + _links: { + archive: { + href: 'https://api.amplience.net/v2/content/editions/ed2/archive' + }, + delete: { + href: 'https://api.amplience.net/v2/content/editions/ed2' + }, + schedule: { + href: 'https://api.amplience.net/v2/content/editions/ed2/schedule' + } + } + }) + ); + } + mockEditionsList.mockResolvedValue(new MockPage(Edition, editions)); + + mockSlotsList.mockResolvedValue(new MockPage(EditionSlot, slots)); + + const snapshot = new Snapshot({ + id: 'snapshot-1', + comment: '', + createdDate: '2018-04-04T16:00:06.945Z', + createdBy: 'user', + createdFrom: 'content-item', + type: 'USER', + meta: [], + taggedEditions: [ + { + editionId: 'ed1', + createdDate: '2018-04-04T16:00:07Z', + createdBy: 'user' + } + ], + locale: null, + rootContentItem: { + label: 'Content Item', + contentTypeUri: 'http://schema.com/test.json', + id: 'content-item-1' + }, + rootContentItems: [ + { + label: 'Content Item', + contentTypeUri: 'http://schema.com/test.json', + id: 'content-item-1' + } + ] + }); + + snapshot.related.snapshotContentItem = mockSnapshotItem; + + mockSnapshotGet.mockResolvedValue(snapshot); + + mockSnapshotItem.mockResolvedValue( + new ContentItem({ + id: 'content-item-1', + contentRepositoryId: 'repo1', + body: { + _meta: { + name: 'test', + schema: 'http://schema.com/test.json' + }, + simpleContent: 'test' + }, + version: 9, + label: 'Content Item', + status: 'ACTIVE' + }) + ); + + editions[0].related.update = mockEditionUpdate; + editions[0].related.unschedule = mockEditionUnschedule; + slots[0].related.content = mockSlotContent; + mockEditionGet.mockResolvedValue(editions[0]); + + if (getHubError) { + getHubMock.mockRejectedValue(new Error('Error')); + } + + if (getEventError) { + mockGet.mockRejectedValue(new Error('Error')); + } + + if (listEventError) { + mockEventsList.mockRejectedValue(new Error('Error')); + } + + if (listEditionError) { + mockEditionsList.mockRejectedValue(new Error('Error')); + } + + if (getSnapshotError) { + mockSnapshotGet.mockRejectedValue(new Error('Error')); + } + + return { + mockGet, + getHubMock, + mockEditionsList, + mockEditionGet, + mockEditionUpdate, + mockEditionUnschedule, + mockEventsList, + mockEventUpdate, + mockEventCreate, + mockSlotsList, + mockSlotContent, + mockSnapshotGet, + mockSnapshotItem, + mockSnapshotCreate, + mockEdition: editions[0] + }; +}; diff --git a/src/commands/event/export.spec.ts b/src/commands/event/export.spec.ts new file mode 100644 index 00000000..b169024e --- /dev/null +++ b/src/commands/event/export.spec.ts @@ -0,0 +1,585 @@ +import { + builder, + command, + handler, + enrichEditions, + enrichEvents, + filterEvents, + LOG_FILENAME, + locateSnapshots, + exportSnapshots +} from './export'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { Event, Edition, EditionSlot, Page } from 'dc-management-sdk-js'; +import Yargs from 'yargs/yargs'; +import { promisify } from 'util'; +import { exists, readFile, readdirSync } from 'fs'; +import paginator from '../../common/dc-management-sdk-js/paginator'; + +import rmdir from 'rimraf'; +import * as facet from '../../common/filter/facet'; +import * as exportService from '../../services/export.service'; +import { FileLog, setVersion } from '../../common/file-log'; +import { LogErrorLevel } from '../../common/archive/archive-log'; + +import { mockValues } from './event-test-helpers'; +import { createLog } from '../../common/log-helpers'; + +setVersion('test-ver'); + +jest.mock('../../services/dynamic-content-client-factory'); + +jest.mock('../../common/filter/facet', () => ({ + relativeDate: jest + .fn() + .mockImplementation((relative: string) => jest.requireActual('../../common/filter/facet').relativeDate(relative)) +})); + +function rimraf(dir: string): Promise { + return new Promise((resolve): void => { + rmdir(dir, resolve); + }); +} + +describe('event export command', () => { + afterEach((): void => { + jest.restoreAllMocks(); + }); + const yargArgs = { + $0: 'test', + _: ['test'], + json: true, + silent: true + }; + const config = { + clientId: 'client-id', + clientSecret: 'client-id', + hubId: 'hub-id' + }; + + it('should command should defined', function () { + expect(command).toEqual('export '); + }); + + describe('builder tests', function () { + it('should configure yargs', function () { + const argv = Yargs(process.argv.slice(2)); + const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); + const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); + + builder(argv); + + expect(spyPositional).toHaveBeenCalledWith('dir', { + describe: 'Output directory for the exported Events.', + type: 'string' + }); + + expect(spyOption).toHaveBeenCalledWith('id', { + describe: 'Export a single event by ID, rather then fetching all of them.', + type: 'string' + }); + + expect(spyOption).toHaveBeenCalledWith('fromDate', { + describe: + 'Start date for filtering events. Either "NOW" or in the format ":", example: "-7:DAYS".', + type: 'string' + }); + + expect(spyOption).toHaveBeenCalledWith('toDate', { + describe: 'To date for filtering events. Either "NOW" or in the format ":", example: "-7:DAYS".', + type: 'string' + }); + + expect(spyOption).toHaveBeenCalledWith('snapshots', { + describe: 'Save content snapshots with events, in subfolder "snapshots/".', + type: 'boolean', + boolean: true + }); + + expect(spyOption).toHaveBeenCalledWith('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: createLog + }); + }); + }); + + describe('handler tests', function () { + beforeAll(async () => { + await rimraf('temp/exportEvent/'); + }); + + afterAll(async () => { + await rimraf('temp/exportEvent/'); + }); + + it('should list and export all editions', async () => { + const { mockEventsList, mockEditionsList, mockSlotsList } = mockValues({}); + + const argv = { + ...yargArgs, + ...config, + dir: 'temp/exportEvent/all/', + logFile: new FileLog('temp/exportEvent/all.log'), + snapshots: false + }; + await handler(argv); + + expect(mockEventsList).toHaveBeenCalled(); + expect(mockEditionsList).toHaveBeenCalledTimes(2); + expect(mockSlotsList).toHaveBeenCalledTimes(2); + + const results = [ + await promisify(readFile)('temp/exportEvent/all/test1.json', { encoding: 'utf-8' }), + await promisify(readFile)('temp/exportEvent/all/test2.json', { encoding: 'utf-8' }) + ]; + + const log = await promisify(readFile)('temp/exportEvent/all.log', { encoding: 'utf-8' }); + + expect(results).toMatchSnapshot(); + expect(log).toMatchSnapshot(); + }); + + it('should list and export a single edition', async () => { + const { mockEventsList, mockEditionsList, mockSlotsList, mockGet } = mockValues({}); + + const argv = { + ...yargArgs, + ...config, + id: 'item1', + dir: 'temp/exportEvent/single/', + logFile: new FileLog('temp/exportEvent/single.log'), + snapshots: false + }; + await handler(argv); + + expect(mockGet).toHaveBeenCalledWith('item1'); + expect(mockEventsList).not.toHaveBeenCalled(); + expect(mockEditionsList).toHaveBeenCalledTimes(1); + expect(mockSlotsList).toHaveBeenCalledTimes(1); + + const results = [await promisify(readFile)('temp/exportEvent/single/test1.json', { encoding: 'utf-8' })]; + + const log = await promisify(readFile)('temp/exportEvent/single.log', { encoding: 'utf-8' }); + + expect(results).toMatchSnapshot(); + expect(log).toMatchSnapshot(); + }); + + it('should pass from and to date parameters to filterEvents', async () => { + const { mockEventsList, mockEditionsList, mockSlotsList } = mockValues({}); + + const argv = { + ...yargArgs, + ...config, + dir: 'temp/exportEvent/date/', + logFile: new FileLog('temp/exportEvent/date.log'), + fromDate: '-1:DAYS', + toDate: '1:DAYS', + snapshots: false + }; + await handler(argv); + + expect((facet.relativeDate as jest.Mock).mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "-1:DAYS", + ], + Array [ + "1:DAYS", + ], + ] + `); + + expect(mockEventsList).toHaveBeenCalled(); + expect(mockEditionsList).not.toHaveBeenCalled(); + expect(mockSlotsList).not.toHaveBeenCalled(); + + const dirExists = await promisify(exists)('temp/exportEvent/date/'); + const log = await promisify(readFile)('temp/exportEvent/date.log', { encoding: 'utf-8' }); + + expect(dirExists).toBeFalsy(); + expect(log).toMatchSnapshot(); + }); + + it('should exit early if getting the hub fails', async () => { + const { getHubMock, mockEventsList, mockEditionsList, mockSlotsList, mockGet } = mockValues({ + getEventError: true, + getHubError: true + }); + + const argv = { + ...yargArgs, + ...config, + id: 'missing', + dir: 'temp/exportEvent/noHub/', + logFile: new FileLog('temp/exportEvent/noHub.log'), + snapshots: false + }; + await handler(argv); + + expect(getHubMock).toHaveBeenCalled(); + expect(mockGet).not.toHaveBeenCalled(); + expect(mockEventsList).not.toHaveBeenCalled(); + expect(mockEditionsList).not.toHaveBeenCalled(); + expect(mockSlotsList).not.toHaveBeenCalled(); + + const dirExists = await promisify(exists)('temp/exportEvent/noHub/'); + const log = await promisify(readFile)('temp/exportEvent/noHub.log', { encoding: 'utf-8' }); + + expect(dirExists).toBeFalsy(); + expect(log).toMatchSnapshot(); + }); + + it('should log an error when getting a single event fails', async () => { + const { mockEventsList, mockEditionsList, mockSlotsList, mockGet } = mockValues({ getEventError: true }); + + const argv = { + ...yargArgs, + ...config, + id: 'missing', + dir: 'temp/exportEvent/singleError/', + logFile: new FileLog('temp/exportEvent/singleError.log'), + snapshots: false + }; + await handler(argv); + + expect(mockGet).toHaveBeenCalledWith('missing'); + expect(mockEventsList).not.toHaveBeenCalled(); + expect(mockEditionsList).not.toHaveBeenCalled(); + expect(mockSlotsList).not.toHaveBeenCalled(); + + const dirExists = await promisify(exists)('temp/exportEvent/singleError/'); + const log = await promisify(readFile)('temp/exportEvent/singleError.log', { encoding: 'utf-8' }); + + expect(dirExists).toBeFalsy(); + expect(log).toMatchSnapshot(); + }); + + it('should log an error when listing events fails', async () => { + const { mockEventsList, mockEditionsList, mockSlotsList, mockGet } = mockValues({ listEventError: true }); + + const argv = { + ...yargArgs, + ...config, + dir: 'temp/exportEvent/listError/', + logFile: new FileLog('temp/exportEvent/listError.log'), + snapshots: false + }; + await handler(argv); + + expect(mockGet).not.toHaveBeenCalled(); + expect(mockEventsList).toHaveBeenCalled(); + expect(mockEditionsList).not.toHaveBeenCalled(); + expect(mockSlotsList).not.toHaveBeenCalled(); + + const dirExists = await promisify(exists)('temp/exportEvent/listError/'); + const log = await promisify(readFile)('temp/exportEvent/listError.log', { encoding: 'utf-8' }); + + expect(dirExists).toBeFalsy(); + expect(log).toMatchSnapshot(); + }); + + it('should export snapshots when --snapshots is provided', async () => { + const { mockEventsList, mockEditionsList, mockSlotsList, mockGet, mockSnapshotGet, mockSnapshotItem } = + mockValues({}); + + const argv = { + ...yargArgs, + ...config, + id: 'item1', + dir: 'temp/exportEvent/snapshots/', + logFile: new FileLog('temp/exportEvent/snapshots.log'), + snapshots: true + }; + await handler(argv); + + expect(mockGet).toHaveBeenCalledWith('item1'); + expect(mockEventsList).not.toHaveBeenCalled(); + expect(mockEditionsList).toHaveBeenCalledTimes(1); + expect(mockSlotsList).toHaveBeenCalledTimes(1); + expect(mockSnapshotGet).toHaveBeenCalledTimes(1); + expect(mockSnapshotItem).toHaveBeenCalledTimes(1); + + const results = [ + await promisify(readFile)('temp/exportEvent/snapshots/test1.json', { encoding: 'utf-8' }), + await promisify(readFile)('temp/exportEvent/snapshots/snapshots/snapshot1.json', { encoding: 'utf-8' }) + ]; + + const log = await promisify(readFile)('temp/exportEvent/snapshots.log', { encoding: 'utf-8' }); + + expect(results).toMatchSnapshot(); + expect(log).toMatchSnapshot(); + }); + + it('should return event file name', async () => { + const logFile = LOG_FILENAME(); + + expect(logFile).toContain('event-export-.log'); + }); + }); + + describe('enrichEvents tests', () => { + it('should request and populate editions for each of the provided events', async () => { + const { mockEventsList, mockEditionsList } = mockValues({}); + + const events = await paginator(mockEventsList as unknown as () => Promise>); + + await expect(enrichEvents(events)).resolves.toMatchSnapshot(); + + expect(mockEditionsList).toHaveBeenCalledTimes(2); + }); + + it('should omit events when fetching their editions failed', async () => { + const { mockEventsList, mockEditionsList } = mockValues({ listEditionError: true }); + + const events = await paginator(mockEventsList as unknown as () => Promise>); + + const log = new FileLog(); + + await expect(enrichEvents(events, log)).resolves.toEqual([]); + + expect(log.errorLevel).toEqual(LogErrorLevel.WARNING); + expect(mockEditionsList).toHaveBeenCalledTimes(2); + }); + + it('should return empty array if no events provided', async () => { + expect(enrichEvents([])).resolves.toEqual([]); + }); + }); + + describe('enrichEditions tests', () => { + it('should request and populate slots for each of the provided editions', async () => { + const { mockEditionsList, mockSlotsList } = mockValues({}); + + const editions = await paginator(mockEditionsList as unknown as () => Promise>); + + await expect(enrichEditions(editions)).resolves.toMatchSnapshot(); + + expect(mockSlotsList).toHaveBeenCalledTimes(1); + }); + + it('should return empty array if no editions provided', async () => { + expect(enrichEditions([])).resolves.toEqual([]); + }); + }); + + describe('filterEvents tests', () => { + const testEvents = [ + new Event({ start: '2021-01-01T12:00:00.000Z', end: '2021-05-05T12:00:00.000Z' }), + new Event({ start: '2021-04-04T12:00:00.000Z', end: '2021-06-06T12:00:00.000Z' }), + new Event({ start: '2021-08-08T12:00:00.000Z', end: '2021-09-09T12:00:00.000Z' }), + new Event({ start: '2021-01-01T12:00:00.000Z', end: '2021-10-10T12:00:00.000Z' }) + ]; + + it('should return the input events if from and to are undefined', async () => { + expect(filterEvents(testEvents, undefined, undefined)).toEqual(testEvents); + }); + + it('should filter out events from before the from date when provided', async () => { + expect(filterEvents(testEvents, new Date('2021-08-08T12:00:00.000Z'), undefined)).toEqual(testEvents.slice(2)); + }); + + it('should filter out events from after the to date when provided', async () => { + expect(filterEvents(testEvents, undefined, new Date('2021-07-07T12:00:00.000Z'))).toEqual([ + testEvents[0], + testEvents[1], + testEvents[3] + ]); + }); + + it('should filter out events outwith the from and to dates when both are provided', async () => { + expect( + filterEvents(testEvents, new Date('2021-05-06T12:00:00.000Z'), new Date('2021-07-07T12:00:00.000Z')) + ).toEqual([testEvents[1], testEvents[3]]); + }); + }); + + describe('locateSnapshots tests', () => { + it('should locate snapshots within the provided slots, alongside empty slots', async () => { + const slots = [ + new EditionSlot({ + id: 'emptySlot', + eventId: 'test1', + editionId: 'ed1', + content: { body: { _meta: { schema: 'http://schema.com/test.json', name: 'example-slot-test' } } }, + status: 'VALID', + slotStatus: 'ACTIVE', + contentTypeId: 'testType', + slotId: 'slot1', + slotLabel: 'example-slot-test', + empty: true + }), + new EditionSlot({ + id: 'referencesSlot', + eventId: 'test1', + editionId: 'ed1', + content: { + label: 'references', + body: { + _meta: { schema: 'http://schema.com/test.json', name: 'example-slot-test' }, + array: [ + { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-link', + rootContentItemId: 'content-item-1', + locked: true + }, + contentType: 'http://schema.com/test.json', + id: 'snapshot1' + } + ], + property: { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-reference', + rootContentItemId: 'content-item-2', + locked: true + }, + contentType: 'http://schema.com/test.json', + id: 'snapshot2' + }, + propertyNested: { + property: { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-link', + rootContentItemId: 'content-item-3', + locked: true + }, + contentType: 'http://schema.com/test.json', + id: 'snapshot3' + } + } + } + }, + status: 'VALID', + slotStatus: 'ACTIVE', + contentTypeId: 'testType', + slotId: 'slot2', + slotLabel: 'example-slot-test2', + empty: false + }), + new EditionSlot({ + id: 'referencesSlot', + eventId: 'test1', + editionId: 'ed1', + content: { + label: 'references', + body: { + _meta: { schema: 'http://schema.com/test.json', name: 'example-slot-test' }, + noReferences: 'none!' + } + }, + status: 'VALID', + slotStatus: 'ACTIVE', + contentTypeId: 'testType', + slotId: 'slot3', + slotLabel: 'example-slot-test3', + empty: false + }), + new EditionSlot({ + id: 'referencesSlot', + eventId: 'test1', + editionId: 'ed1', + content: { + label: 'references', + body: { + _meta: { schema: 'http://schema.com/test.json', name: 'example-slot-test' }, + oneReference: { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-reference', + rootContentItemId: 'content-item-2', + locked: true + }, + contentType: 'http://schema.com/test.json', + id: 'snapshot4' + } + } + }, + status: 'VALID', + slotStatus: 'ACTIVE', + contentTypeId: 'testType', + slotId: 'slot3', + slotLabel: 'example-slot-test3', + empty: false + }) + ]; + + const snapshots = new Set(); + locateSnapshots(slots, snapshots); + + expect(Array.from(snapshots)).toEqual(['snapshot1', 'snapshot2', 'snapshot3', 'snapshot4']); + }); + + it('should not add snapshots when no slots are provided', async () => { + const snapshots = new Set(); + locateSnapshots([], snapshots); + + expect(snapshots.size).toEqual(0); + }); + }); + + describe('exportSnapshots tests', () => { + const config = { + clientId: 'client-id', + clientSecret: 'client-id', + hubId: 'hub-id' + }; + + it('should export snapshots to a "snapshots" subfolder in the provided directory', async () => { + const { mockSnapshotGet, mockSnapshotItem } = mockValues({}); + + const client = await dynamicContentClientFactory(config); + + const log = new FileLog(); + + await exportSnapshots(client, 'temp/exportSnapshot/snapshots', new Set(['snapshot1', 'snapshot2']), log); + + expect(mockSnapshotGet).toHaveBeenCalledTimes(2); + expect(mockSnapshotItem).toHaveBeenCalledTimes(2); + expect(log.errorLevel).toEqual(LogErrorLevel.NONE); + + const exportDir = readdirSync('temp/exportSnapshot/snapshots/snapshots'); + + expect(exportDir).toMatchInlineSnapshot(` + Array [ + "snapshot1.json", + "snapshot2.json", + ] + `); + }); + + it('should warn and skip when the snapshot cannot be fetched', async () => { + const { mockSnapshotGet, mockSnapshotItem } = mockValues({ getSnapshotError: true }); + + const client = await dynamicContentClientFactory(config); + + const log = new FileLog(); + + await exportSnapshots(client, 'temp/exportSnapshot/snapshotFail1', new Set(['snapshot1']), log); + + expect(mockSnapshotGet).toHaveBeenCalledWith('snapshot1'); + expect(mockSnapshotItem).not.toHaveBeenCalled(); + expect(readdirSync('temp/exportSnapshot/snapshotFail1/snapshots').length).toEqual(0); + expect(log.errorLevel).toEqual(LogErrorLevel.WARNING); + }); + + it('should warn and skip when the snapshot cannot be saved', async () => { + const { mockSnapshotGet, mockSnapshotItem } = mockValues({}); + + jest.spyOn(exportService, 'writeJsonToFile').mockImplementation(() => { + throw new Error('Error'); + }); + const client = await dynamicContentClientFactory(config); + + const log = new FileLog(); + + await exportSnapshots(client, 'temp/exportSnapshot/snapshotFail2', new Set(['snapshot1']), log); + + expect(mockSnapshotGet).toHaveBeenCalledWith('snapshot1'); + expect(mockSnapshotItem).toHaveBeenCalledWith('content-item-1'); + expect(readdirSync('temp/exportSnapshot/snapshotFail2/snapshots').length).toEqual(0); + expect(log.errorLevel).toEqual(LogErrorLevel.WARNING); + }); + }); +}); diff --git a/src/commands/event/export.ts b/src/commands/event/export.ts new file mode 100644 index 00000000..99250be8 --- /dev/null +++ b/src/commands/event/export.ts @@ -0,0 +1,385 @@ +import { Arguments, Argv } from 'yargs'; +import { ConfigurationParameters } from '../configure'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import paginator from '../../common/dc-management-sdk-js/paginator'; +import { ContentRepository, DynamicContent, Edition, EditionSlot, Event, Hub, Snapshot } from 'dc-management-sdk-js'; +import { createStream } from 'table'; +import { streamTableOptions } from '../../common/table/table.consts'; +import { TableStream } from '../../interfaces/table.interface'; +import chalk from 'chalk'; +import { + ExportResult, + nothingExportedExit, + promptToOverwriteExports, + uniqueFilenamePath, + writeJsonToFile +} from '../../services/export.service'; +import { loadJsonFromDirectory } from '../../services/import.service'; +import { ExportEventBuilderOptions } from '../../interfaces/export-event-builder-options.interface'; +import { ensureDirectoryExists } from '../../common/import/directory-utils'; +import { relativeDate } from '../../common/filter/facet'; +import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { FileLog } from '../../common/file-log'; +import { ContentDependancyTree } from '../../common/content-item/content-dependancy-tree'; +import { ContentMapping } from '../../common/content-mapping'; +import { join } from 'path'; + +export const command = 'export '; + +export const desc = 'Export Events'; + +export const LOG_FILENAME = (platform: string = process.platform): string => + getDefaultLogPath('event', 'export', platform); + +export const builder = (yargs: Argv): void => { + yargs + .positional('dir', { + describe: 'Output directory for the exported Events.', + type: 'string' + }) + .option('id', { + describe: 'Export a single event by ID, rather then fetching all of them.', + type: 'string' + }) + .option('fromDate', { + describe: 'Start date for filtering events. Either "NOW" or in the format ":", example: "-7:DAYS".', + type: 'string' + }) + .option('toDate', { + describe: 'To date for filtering events. Either "NOW" or in the format ":", example: "-7:DAYS".', + type: 'string' + }) + .option('snapshots', { + describe: 'Save content snapshots with events, in subfolder "snapshots/".', + type: 'boolean', + boolean: true + }) + .option('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: createLog + }); +}; + +interface ExportRecord { + readonly filename: string; + readonly status: ExportResult; + readonly event: Event; +} + +export class EditionWithSlots extends Edition { + slots: EditionSlot[]; +} + +export class EventWithEditions extends Event { + editions: EditionWithSlots[]; +} + +export const exportSnapshots = async ( + client: DynamicContent, + outputDir: string, + snapshots: Set, + log: FileLog +): Promise => { + const baseDir = join(outputDir, 'snapshots/'); + await ensureDirectoryExists(baseDir); + + log.appendLine(`Saving ${snapshots.size} snapshots to './snapshots/'.`); + + for (const id of snapshots) { + log.appendLine(`Fetching snapshot ${id}.`); + + let snapshot: Snapshot; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let snapshotJson: any; + try { + snapshot = await client.snapshots.get(id); + snapshotJson = snapshot.toJSON(); + + const content = await Promise.all( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (snapshotJson.rootContentItems as any[]).map((item: { id: string }) => + snapshot.related.snapshotContentItem(item.id) + ) + ); + + for (const item of content) { + const itemTree = new ContentDependancyTree( + [{ repo: new ContentRepository(), content: item }], + new ContentMapping() + ); + + for (const subItem of itemTree.all[0].dependancies) { + log.appendLine('... scanning item ' + subItem.dependancy.id + ' ' + subItem.dependancy._meta.schema); + try { + await snapshot.related.snapshotContentItem(subItem.dependancy.id as string); + log.appendLine('yep'); + } catch { + log.appendLine('nope!'); + } + } + } + + snapshotJson.content = content; + } catch (e) { + log.warn(`Could not fetch snapshot ${id}, continuing: `, e); + continue; + } + + const filename = join(baseDir, id + '.json'); + + try { + writeJsonToFile(filename, snapshotJson); + } catch (e) { + log.warn(`Could not write snapshot ${id}, continuing: `, e); + } + } +}; + +export const locateSnapshots = (slots: EditionSlot[], snapshots: Set): void => { + for (const slot of slots) { + if (slot.content.body) { + const item = { repo: new ContentRepository(), content: slot.content }; + const tree = new ContentDependancyTree([item], new ContentMapping()); + + const dependencies = tree.all[0].dependancies; + + for (const link of dependencies) { + if (link.dependancy.id) { + snapshots.add(link.dependancy.id); + } + } + } + } +}; + +export const locateAndExportSnapshots = async ( + client: DynamicContent, + outputDir: string, + events: EventWithEditions[], + log: FileLog +): Promise => { + const snapshots = new Set(); + + log.appendLine(`Scanning slots for snapshots.`); + + for (const event of events) { + for (const edition of event.editions) { + locateSnapshots(edition.slots, snapshots); + } + } + + await exportSnapshots(client, outputDir, snapshots, log); +}; + +export const enrichEditions = async (editions: Edition[]): Promise => { + for (const edition of editions) { + const withEditions = edition as EditionWithSlots; + const slots = await paginator(edition.related.slots.list); + withEditions.slots = slots; + + // SLOT todo + // content.body contains the version of the slot that will be scheduled in its entirety. + // this is simply a _meta.schema and _meta.name if the slot is empty, + // but if it isn't, it contains the full slot contents (with no depth) + // any links and references, however, have additional fields: + // + // ._meta.rootContentItemId - the true content id that the reference/link is pointing to + // ._meta.locked - not sure + // ._meta.schema - link or reference + // .id - this is NOT a content id, it's a snapshot ID of the content at the time it was selected by the content chooser. + // .contentType - type schema for the referenced content type + } + + return editions as EditionWithSlots[]; +}; + +export const enrichEvents = async (events: Event[], log?: FileLog): Promise => { + for (const event of events) { + if (log) { + log.appendLine(`Fetching ${event.name} with editions.`); + } + + const withEditions = event as EventWithEditions; + + try { + const editions = await paginator(event.related.editions.list); + withEditions.editions = await enrichEditions(editions); + } catch (e) { + if (log) { + log.warn(`Failed to fetch editions for ${event.name}, skipping.`, e); + } + } + } + + const result = events as EventWithEditions[]; + + return result.filter(event => event.editions != undefined); +}; + +export const getExportRecordForEvent = ( + event: EventWithEditions, + outputDir: string, + previouslyExportedEvents: { [filename: string]: EventWithEditions } +): ExportRecord => { + const indexOfExportedEvent = Object.values(previouslyExportedEvents).findIndex(c => c.id === event.id); + if (indexOfExportedEvent < 0) { + const filename = uniqueFilenamePath(outputDir, event.name, 'json', Object.keys(previouslyExportedEvents)); + + // This filename is now used. + previouslyExportedEvents[filename] = event; + + return { + filename: filename, + status: 'CREATED', + event + }; + } + const filename = Object.keys(previouslyExportedEvents)[indexOfExportedEvent]; + /* + const previouslyExportedEvent = Object.values(previouslyExportedEvents)[indexOfExportedEvent]; + + if (equals(previouslyExportedEvent, event)) { + return { filename, status: 'UP-TO-DATE', event }; + } + */ + return { + filename, + status: 'UPDATED', + event + }; +}; + +type ExportsMap = { + uri: string; + filename: string; +}; + +export const getEventExports = ( + outputDir: string, + previouslyExportedEvents: { [filename: string]: EventWithEditions }, + eventsBeingExported: EventWithEditions[] +): [ExportRecord[], ExportsMap[]] => { + const allExports: ExportRecord[] = []; + const updatedExportsMap: ExportsMap[] = []; // uri x filename + for (const event of eventsBeingExported) { + if (!event.id) { + continue; + } + + const exportRecord = getExportRecordForEvent(event, outputDir, previouslyExportedEvents); + allExports.push(exportRecord); + if (exportRecord.status === 'UPDATED') { + updatedExportsMap.push({ uri: event.id, filename: exportRecord.filename }); + } + } + return [allExports, updatedExportsMap]; +}; + +export const processEvents = async ( + outputDir: string, + previouslyExportedEvents: { [filename: string]: EventWithEditions }, + enrichedEvents: EventWithEditions[], + log: FileLog +): Promise => { + if (enrichedEvents.length === 0) { + nothingExportedExit(log, 'No events to export from this hub, exiting.'); + return; + } + + const [allExports, updatedExportsMap] = getEventExports(outputDir, previouslyExportedEvents, enrichedEvents); + if ( + allExports.length === 0 || + (Object.keys(updatedExportsMap).length > 0 && !(await promptToOverwriteExports(updatedExportsMap, log))) + ) { + nothingExportedExit(log); + return; + } + + await ensureDirectoryExists(outputDir); + + const tableStream = createStream(streamTableOptions) as unknown as TableStream; + tableStream.write([chalk.bold('File'), chalk.bold('Schema ID'), chalk.bold('Result')]); + for (const { filename, status, event } of allExports) { + if (status !== 'UP-TO-DATE') { + writeJsonToFile(filename, event); + } + tableStream.write([filename, event.name || '', status]); + } + process.stdout.write('\n'); +}; + +export const filterEvents = (events: Event[], from: Date | undefined, to: Date | undefined): Event[] => { + return events.filter(event => { + const eventStart = new Date(event.start as string); + const eventEnd = new Date(event.end as string); + + if (from && eventEnd < from) { + return false; + } + + if (to && eventStart > to) { + return false; + } + + return true; + }); +}; + +export const handler = async (argv: Arguments): Promise => { + const { dir, fromDate, toDate, logFile, id, snapshots } = argv; + + const log = logFile.open(); + + const from = fromDate === undefined ? undefined : relativeDate(fromDate); + const to = toDate === undefined ? undefined : relativeDate(toDate); + + const previouslyExportedEvents = loadJsonFromDirectory(dir, EventWithEditions); + + const client = dynamicContentClientFactory(argv); + + let hub: Hub; + try { + hub = await client.hubs.get(argv.hubId); + } catch (e) { + log.error(`Couldn't get hub with id ${argv.hubId}, aborting.`, e); + await log.close(); + return; + } + + let filteredEvents: Event[]; + if (id) { + try { + filteredEvents = [await client.events.get(id)]; + log.appendLine(`Exporting single event ${filteredEvents[0].name}.`); + } catch (e) { + log.error(`Failed to get event with id ${id}, aborting.`, e); + await log.close(); + return; + } + } else { + try { + const storedEvents = await paginator(hub.related.events.list); + + filteredEvents = filterEvents(storedEvents, from, to); + + log.appendLine(`Exporting ${filteredEvents.length} of ${storedEvents.length} events...`); + } catch (e) { + log.error(`Failed to list events.`, e); + filteredEvents = []; + } + } + + const enrichedEvents = await enrichEvents(filteredEvents, log); + + await processEvents(dir, previouslyExportedEvents, enrichedEvents, log); + + if (snapshots) { + await locateAndExportSnapshots(client, dir, enrichedEvents, log); + } + + log.appendLine(`Done.`); + + await log.close(); +}; diff --git a/src/commands/event/import.spec.ts b/src/commands/event/import.spec.ts new file mode 100644 index 00000000..12ea95b1 --- /dev/null +++ b/src/commands/event/import.spec.ts @@ -0,0 +1,1522 @@ +import { + builder, + command, + getDefaultMappingPath, + handler, + importEditions, + importEvents, + importSlots, + LOG_FILENAME, + trySaveMapping +} from './import'; +import * as importModule from './import'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { Event, Edition, Hub, EditionSlot, Snapshot, DynamicContent, PublishingStatus } from 'dc-management-sdk-js'; +import Yargs from 'yargs/yargs'; +import MockPage from '../../common/dc-management-sdk-js/mock-page'; + +import rmdir from 'rimraf'; +import { FileLog } from '../../common/file-log'; +import { ContentMapping } from '../../common/content-mapping'; +import { mockValues } from './event-test-helpers'; +import { EditionWithSlots, EventWithEditions } from './export'; +import { ImportEventBuilderOptions } from '../../interfaces/import-event-builder-options.interface'; +import { loadJsonFromDirectory } from '../../services/import.service'; +import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { dateOffset } from '../../common/import/date-helpers'; +import { ensureDirectoryExists } from '../../common/import/directory-utils'; + +jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../services/import.service'); + +jest.mock('../../common/log-helpers', () => ({ + ...jest.requireActual('../../common/log-helpers'), + getDefaultLogPath: jest.fn() +})); + +function rimraf(dir: string): Promise { + return new Promise((resolve): void => { + rmdir(dir, resolve); + }); +} + +describe('event import command', () => { + afterEach((): void => { + jest.restoreAllMocks(); + }); + + const yargArgs = { + $0: 'test', + _: ['test'], + json: true, + silent: true + }; + + const config = { + clientId: 'client-id', + clientSecret: 'client-id', + hubId: 'hub-id', + schedule: false, + acceptSnapshotLimits: true, + catchup: true + }; + + const commonMock = async ( + customArgs = {} + ): Promise<{ + client: DynamicContent; + hub: Hub; + argv: ImportEventBuilderOptions; + log: FileLog; + mapping: ContentMapping; + }> => { + const client = await dynamicContentClientFactory(config); + const log = new FileLog(); + return { + client, + hub: await client.hubs.get('hub-id'), + log: log, + mapping: new ContentMapping(), + argv: { + ...yargArgs, + ...config, + dir: '', + originalIds: false, + acceptSnapshotLimits: true, + logFile: log, + ...customArgs + } + }; + }; + + it('should command should defined', function () { + expect(command).toEqual('import '); + }); + + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { + LOG_FILENAME(); + + expect(getDefaultLogPath).toHaveBeenCalledWith('event', 'import', process.platform); + }); + + it('should generate a default mapping path containing the given name', function () { + expect(getDefaultMappingPath('hub-1').indexOf('hub-1')).not.toEqual(-1); + }); + + describe('builder tests', function () { + it('should configure yargs', function () { + const argv = Yargs(process.argv.slice(2)); + const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); + const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); + + builder(argv); + + expect(spyPositional).toHaveBeenCalledWith('dir', { + describe: 'Directory containing Events', + type: 'string' + }); + + expect(spyOption).toHaveBeenCalledWith('acceptSnapshotLimits', { + type: 'boolean', + boolean: true, + describe: + 'Must be passed to use the event import command. Only use this command if you fully understand its limitations.' + }); + + expect(spyOption).toHaveBeenCalledWith('mapFile', { + type: 'string', + describe: + 'Mapping file to use when updating content that already exists. Updated with any new mappings that are generated. If not present, will be created.' + }); + + expect(spyOption).toHaveBeenCalledWith('f', { + type: 'boolean', + boolean: true, + describe: 'Overwrite existing events, editions, slots and snapshots without asking.' + }); + + expect(spyOption).toHaveBeenCalledWith('originalIds', { + type: 'boolean', + boolean: true, + describe: 'Use original ids' + }); + + expect(spyOption).toHaveBeenCalledWith('schedule', { + type: 'boolean', + boolean: true, + describe: + 'Schedule events in the destination repo if they are scheduled in the source. If any new or updated scheduled events started in the past, they will be moved to happen at the time of import. If they ended in the past, they will be skipped by default.' + }); + + expect(spyOption).toHaveBeenCalledWith('catchup', { + type: 'boolean', + boolean: true, + describe: 'Scheduling events that ended in the past will move to the current date, so that their publishes run.' + }); + + expect(spyOption).toHaveBeenCalledWith('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: createLog + }); + }); + }); + + describe('handler tests', function () { + beforeAll(async () => { + await rimraf(`temp_${process.env.JEST_WORKER_ID}/importEvent/`); + }); + + afterAll(async () => { + await rimraf(`temp_${process.env.JEST_WORKER_ID}/importEvent/`); + }); + + it('should return immediately if acceptSnapshotLimits is false', async function () { + const { getHubMock } = mockValues({}); + + const logFile = new FileLog(); + const argv = { + ...yargArgs, + ...config, + logFile, + dir: `temp_${process.env.JEST_WORKER_ID}/importEvent/`, + acceptSnapshotLimits: false, + catchup: false, + originalIds: false + }; + const event = new EventWithEditions({ id: 'id-1' }); + + (loadJsonFromDirectory as jest.Mock).mockResolvedValue({ + 'event1.json': event + }); + + const importEvents = jest.spyOn(importModule, 'importEvents').mockResolvedValue(); + const trySaveMapping = jest.spyOn(importModule, 'trySaveMapping').mockResolvedValue(); + const getDefaultMappingPath = jest.spyOn(importModule, 'getDefaultMappingPath').mockReturnValue('mapping.json'); + + await handler(argv); + + expect(getHubMock).not.toHaveBeenCalled(); + expect(loadJsonFromDirectory as jest.Mock).not.toHaveBeenCalled(); + + expect(importEvents).not.toHaveBeenCalled(); + expect(getDefaultMappingPath).not.toHaveBeenCalled(); + expect(trySaveMapping).not.toHaveBeenCalled(); + expect(logFile.closed).toBeFalsy(); + }); + + it('should call importEvents with the loaded events, then save the mapping', async function () { + const { getHubMock } = mockValues({}); + + const logFile = new FileLog(); + const argv = { + ...yargArgs, + ...config, + logFile, + dir: `temp_${process.env.JEST_WORKER_ID}/importEvent/`, + originalIds: false + }; + const event = new EventWithEditions({ id: 'id-1' }); + + (loadJsonFromDirectory as jest.Mock).mockResolvedValue({ + 'event1.json': event + }); + + const importEvents = jest.spyOn(importModule, 'importEvents').mockResolvedValue(); + const trySaveMapping = jest.spyOn(importModule, 'trySaveMapping').mockResolvedValue(); + const getDefaultMappingPath = jest.spyOn(importModule, 'getDefaultMappingPath').mockReturnValue('mapping.json'); + + await handler(argv); + + expect(getHubMock).toHaveBeenCalledWith('hub-id'); //from returned hub + expect(loadJsonFromDirectory as jest.Mock).toHaveBeenCalledWith( + `temp_${process.env.JEST_WORKER_ID}/importEvent/`, + EventWithEditions + ); + + expect(importEvents).toHaveBeenCalledWith( + [event], + expect.any(ContentMapping), + expect.any(Object), + expect.any(Hub), + argv, + logFile + ); + expect(getDefaultMappingPath).toHaveBeenCalledWith('hub-1'); + expect(trySaveMapping).toHaveBeenCalledWith('mapping.json', expect.any(ContentMapping), logFile); + expect(logFile.closed).toBeTruthy(); + }); + + it('should load an existing mapping file', async function () { + const { getHubMock } = mockValues({}); + + const logFile = new FileLog(); + const argv = { + ...yargArgs, + ...config, + logFile, + mapFile: `temp_${process.env.JEST_WORKER_ID}/importEvent/importEvent.json`, + dir: `temp_${process.env.JEST_WORKER_ID}/importEvent/`, + originalIds: false + }; + const event = new EventWithEditions({ id: 'id-1' }); + + (loadJsonFromDirectory as jest.Mock).mockResolvedValue({ + 'event1.json': event + }); + + const importEvents = jest.spyOn(importModule, 'importEvents').mockResolvedValue(); + const trySaveMapping = jest.spyOn(importModule, 'trySaveMapping').mockResolvedValue(); + const getDefaultMappingPath = jest.spyOn(importModule, 'getDefaultMappingPath'); + + await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/importEvent/`); + + const existingMapping = new ContentMapping(); + await existingMapping.save(argv.mapFile); + + await handler(argv); + + expect(getHubMock).toHaveBeenCalledWith('hub-id'); //from returned hub + expect(loadJsonFromDirectory as jest.Mock).toHaveBeenCalledWith( + `temp_${process.env.JEST_WORKER_ID}/importEvent/`, + EventWithEditions + ); + + expect(importEvents).toHaveBeenCalledWith( + [event], + expect.any(ContentMapping), + expect.any(Object), + expect.any(Hub), + argv, + logFile + ); + expect(getDefaultMappingPath).not.toHaveBeenCalled(); + expect(trySaveMapping).toHaveBeenCalledWith(argv.mapFile, expect.any(ContentMapping), logFile); + expect(logFile.closed).toBeTruthy(); + }); + + it('should save the mapping even if importEvents throws', async function () { + const { getHubMock } = mockValues({}); + + const logFile = new FileLog(); + const argv = { + ...yargArgs, + ...config, + logFile, + dir: `temp_${process.env.JEST_WORKER_ID}/importEvent/`, + originalIds: false + }; + const event = new EventWithEditions({ id: 'id-1' }); + + (loadJsonFromDirectory as jest.Mock).mockResolvedValue({ + 'event1.json': event + }); + + const importEvents = jest.spyOn(importModule, 'importEvents').mockRejectedValue(new Error('Example')); + const trySaveMapping = jest.spyOn(importModule, 'trySaveMapping').mockResolvedValue(); + const getDefaultMappingPath = jest.spyOn(importModule, 'getDefaultMappingPath').mockReturnValue('mapping.json'); + + await handler(argv); + + expect(getHubMock).toHaveBeenCalledWith('hub-id'); //from returned hub + expect(loadJsonFromDirectory as jest.Mock).toHaveBeenCalledWith( + `temp_${process.env.JEST_WORKER_ID}/importEvent/`, + EventWithEditions + ); + + expect(importEvents).toHaveBeenCalledWith( + [event], + expect.any(ContentMapping), + expect.any(Object), + expect.any(Hub), + argv, + logFile + ); + expect(getDefaultMappingPath).toHaveBeenCalledWith('hub-1'); + expect(trySaveMapping).toHaveBeenCalledWith('mapping.json', expect.any(ContentMapping), logFile); + expect(logFile.closed).toBeTruthy(); + }); + }); + + describe('shouldUpdateSlot tests', function () { + it('should return false if content matches, true otherwise', async function () { + const slot1 = new EditionSlot({ content: { example: 'test', example2: { deep: 'is here' } } }); + const slot1dupe = new EditionSlot({ content: { example: 'test', example2: { deep: 'is here' } } }); + const slot2 = new EditionSlot({ content: { example: 'test', example2: { deep: 'mismatch' } } }); + const slot3 = new EditionSlot({ content: { example2: 'diff' } }); + + expect(importModule.shouldUpdateSlot(slot1, slot1dupe)).toBeFalsy(); + expect(importModule.shouldUpdateSlot(slot1, slot2)).toBeTruthy(); + expect(importModule.shouldUpdateSlot(slot2, slot3)).toBeTruthy(); + expect(importModule.shouldUpdateSlot(slot1, slot3)).toBeTruthy(); + }); + }); + + describe('shouldUpdateEvent tests', function () { + it('should call boundTimeRange, return false if fields match, true otherwise', async function () { + const event1 = new Event({ name: 'name', brief: '//brief', comment: 'comment', start: '1', end: '2' }); + const event1dupe = new Event({ name: 'name', brief: '//brief', comment: 'comment', start: '1', end: '2' }); + const event2 = new Event({ name: 'name2', brief: '//brief', comment: 'comment', start: '1', end: '2' }); + const event3 = new Event({ name: 'name', brief: '//brief2', comment: 'comment', start: '1', end: '2' }); + const event4 = new Event({ name: 'name', brief: '//brief', comment: 'comment2', start: '1', end: '2' }); + const event5 = new Event({ name: 'name', brief: '//brief', comment: 'comment', start: '1.5', end: '2' }); + const event6 = new Event({ name: 'name', brief: '//brief', comment: 'comment', start: '1', end: '2.5' }); + + jest.spyOn(importModule, 'boundTimeRange').mockReturnValue(); + + expect(importModule.shouldUpdateEvent(event1, event1dupe)).toBeFalsy(); + + expect(importModule.boundTimeRange).toHaveBeenCalledWith(event1, event1dupe); + + expect(importModule.shouldUpdateEvent(event1, event2)).toBeTruthy(); + expect(importModule.shouldUpdateEvent(event1, event3)).toBeTruthy(); + expect(importModule.shouldUpdateEvent(event1, event4)).toBeTruthy(); + expect(importModule.shouldUpdateEvent(event1, event5)).toBeTruthy(); + expect(importModule.shouldUpdateEvent(event1, event6)).toBeTruthy(); + expect(importModule.shouldUpdateEvent(event3, event4)).toBeTruthy(); + + jest.resetAllMocks(); + }); + }); + + describe('shouldUpdateEdition tests', function () { + it('should call boundTimeRange, return false if fields match, true otherwise', async function () { + const edition1 = new Edition({ name: 'name', activeEndDate: false, comment: 'comment', start: '1', end: '2' }); + const edition1dupe = new EditionWithSlots({ + name: 'name', + activeEndDate: false, + comment: 'comment', + start: '1', + end: '2', + slots: [] + }); + const edition2 = new EditionWithSlots({ + name: 'name2', + activeEndDate: false, + comment: 'comment', + start: '1', + end: '2', + slots: [] + }); + const edition3 = new EditionWithSlots({ + name: 'name', + activeEndDate: true, + comment: 'comment', + start: '1', + end: '2', + slots: [] + }); + const edition4 = new EditionWithSlots({ + name: 'name', + activeEndDate: false, + comment: 'comment2', + start: '1', + end: '2', + slots: [] + }); + const edition5 = new EditionWithSlots({ + name: 'name', + activeEndDate: false, + comment: 'comment', + start: '1.5', + end: '2', + slots: [] + }); + const edition6 = new EditionWithSlots({ + name: 'name', + activeEndDate: false, + comment: 'comment', + start: '1', + end: '2.5', + slots: [] + }); + + jest.spyOn(importModule, 'boundTimeRange').mockReturnValue(); + + expect(importModule.shouldUpdateEdition(edition1, [], edition1dupe)).toBeFalsy(); + + expect(importModule.boundTimeRange).toHaveBeenCalledWith(edition1, edition1dupe); + + expect(importModule.shouldUpdateEdition(edition1, [], edition2)).toBeTruthy(); + expect(importModule.shouldUpdateEdition(edition1, [], edition3)).toBeTruthy(); + expect(importModule.shouldUpdateEdition(edition1, [], edition4)).toBeTruthy(); + expect(importModule.shouldUpdateEdition(edition1, [], edition5)).toBeTruthy(); + expect(importModule.shouldUpdateEdition(edition1, [], edition6)).toBeTruthy(); + expect(importModule.shouldUpdateEdition(edition3, [], edition4)).toBeTruthy(); + + jest.resetAllMocks(); + }); + + it('should call boundTimeRange, return false if slots match, true otherwise', async function () { + const edition1 = new Edition({ name: 'name', activeEndDate: false, comment: 'comment', start: '1', end: '2' }); + const edition1dupe = new EditionWithSlots({ + name: 'name', + activeEndDate: false, + comment: 'comment', + start: '1', + end: '2', + slots: [new EditionSlot(), new EditionSlot()] + }); + + jest.spyOn(importModule, 'boundTimeRange').mockReturnValue(); + const spyShouldUpdateSlot = jest.spyOn(importModule, 'shouldUpdateSlot'); + + // Length different, return true immediately + expect(importModule.shouldUpdateEdition(edition1, [], edition1dupe)).toBeTruthy(); + expect(importModule.boundTimeRange).toHaveBeenCalledWith(edition1, edition1dupe); + expect(importModule.shouldUpdateEdition(edition1, [new EditionSlot()], edition1dupe)).toBeTruthy(); + expect( + importModule.shouldUpdateEdition( + edition1, + [new EditionSlot(), new EditionSlot(), new EditionSlot()], + edition1dupe + ) + ).toBeTruthy(); + + expect(importModule.shouldUpdateSlot).not.toHaveBeenCalled(); + + // Identical + spyShouldUpdateSlot.mockReturnValueOnce(false); + spyShouldUpdateSlot.mockReturnValueOnce(false); + expect( + importModule.shouldUpdateEdition(edition1, [new EditionSlot(), new EditionSlot()], edition1dupe) + ).toBeFalsy(); + + // First different + spyShouldUpdateSlot.mockReturnValueOnce(true); + spyShouldUpdateSlot.mockReturnValueOnce(false); + expect( + importModule.shouldUpdateEdition(edition1, [new EditionSlot(), new EditionSlot()], edition1dupe) + ).toBeTruthy(); + + // Second different + spyShouldUpdateSlot.mockReturnValueOnce(false); + spyShouldUpdateSlot.mockReturnValueOnce(true); + expect( + importModule.shouldUpdateEdition(edition1, [new EditionSlot(), new EditionSlot()], edition1dupe) + ).toBeTruthy(); + + // Both different + spyShouldUpdateSlot.mockReturnValueOnce(true); + spyShouldUpdateSlot.mockReturnValueOnce(true); + expect( + importModule.shouldUpdateEdition(edition1, [new EditionSlot(), new EditionSlot()], edition1dupe) + ).toBeTruthy(); + + jest.resetAllMocks(); + }); + }); + + describe('moveDateToFuture tests', function () { + it('should return the input date if it is in the future', async function () { + const future = new Date(); + const event = new Event(); + event.related.update = jest.fn(); + future.setSeconds(future.getSeconds() + 60); + + expect(await importModule.moveDateToFuture(future.toISOString(), event, 10)).toEqual(future.toISOString()); + + expect(event.related.update).not.toHaveBeenCalled(); + }); + + it('should choose a date the given offset from the current date if it is in the past', async function () { + const past = new Date(); + const futureEvent = new Date(); + const event = new Event(); + event.related.update = jest.fn(); + past.setSeconds(past.getSeconds() - 5); + futureEvent.setSeconds(futureEvent.getSeconds() + 60); + event.end = futureEvent.toISOString(); + + const result = new Date(await importModule.moveDateToFuture(past.toISOString(), event, 10)); + const expected = new Date(); + const error = 500; + expected.setSeconds(expected.getSeconds() + 10); + expect(Math.abs(result.getTime() - expected.getTime())).toBeLessThan(error); + + expect(event.related.update).not.toHaveBeenCalled(); + }); + + it("should update the given event's end date if the new date ends up being after it ends", async function () { + const past = new Date(); + const futureEvent = new Date(); + const event = new Event(); + event.related.update = jest.fn(); + past.setSeconds(past.getSeconds() - 5); + futureEvent.setSeconds(futureEvent.getSeconds() + 60); + event.end = futureEvent.toISOString(); + + const result = new Date(await importModule.moveDateToFuture(past.toISOString(), event, 120)); + const expected = new Date(); + const error = 500; + expected.setSeconds(expected.getSeconds() + 120); + expect(Math.abs(result.getTime() - expected.getTime())).toBeLessThan(error); + + expect(event.related.update).toHaveBeenCalled(); + const updateEvent = (event.related.update as jest.Mock).mock.calls[0][0]; + expect(Math.abs(new Date(updateEvent.end).getTime() - expected.getTime())).toBeLessThan(error); + }); + }); + + describe('prepareEditionForSchedule tests', function () { + it('should move the start and end dates to the future if the edition is scheduled', async function () { + const edition = new Edition({ start: '1', end: '2', publishingStatus: PublishingStatus.DRAFT }); + const event = new Event(); + + const futureSpy = jest.spyOn(importModule, 'moveDateToFuture'); + futureSpy.mockResolvedValueOnce('3'); + futureSpy.mockResolvedValueOnce('4'); + + await importModule.prepareEditionForSchedule(edition, event); + expect(importModule.moveDateToFuture).not.toHaveBeenCalled(); + + edition.publishingStatus = PublishingStatus.SCHEDULED; + await importModule.prepareEditionForSchedule(edition, event); + expect(importModule.moveDateToFuture).toHaveBeenNthCalledWith( + 1, + '1', + event, + importModule.EditionSecondsAllowance + ); + expect(importModule.moveDateToFuture).toHaveBeenNthCalledWith( + 2, + '2', + event, + importModule.ScheduleSecondsAllowance + ); + expect(edition.start).toEqual('3'); + expect(edition.end).toEqual('4'); + + jest.resetAllMocks(); + }); + + it('should move the start and end dates to the future if the force parameter is true', async function () { + const edition = new Edition({ start: '1', end: '2', publishingStatus: PublishingStatus.DRAFT }); + const event = new Event(); + + const futureSpy = jest.spyOn(importModule, 'moveDateToFuture'); + futureSpy.mockResolvedValueOnce('3'); + futureSpy.mockResolvedValueOnce('4'); + + await importModule.prepareEditionForSchedule(edition, event); + expect(importModule.moveDateToFuture).not.toHaveBeenCalled(); + + await importModule.prepareEditionForSchedule(edition, event, true); + expect(importModule.moveDateToFuture).toHaveBeenNthCalledWith( + 1, + '1', + event, + importModule.EditionSecondsAllowance + ); + expect(importModule.moveDateToFuture).toHaveBeenNthCalledWith( + 2, + '2', + event, + importModule.ScheduleSecondsAllowance + ); + expect(edition.start).toEqual('3'); + expect(edition.end).toEqual('4'); + + jest.resetAllMocks(); + }); + }); + + describe('skipScheduleIfNeeded tests', function () { + it('should remove scheduled status if the event end is in the past and catchup is false', async function () { + const date = new Date(); + date.setSeconds(date.getSeconds() - 10); + + const edition = new Edition({ end: date.toISOString(), publishingStatus: PublishingStatus.SCHEDULED }); + + importModule.skipScheduleIfNeeded(edition, false); + + expect(edition.publishingStatus).toEqual(PublishingStatus.DRAFT); + }); + + it('should not remove scheduled status if the event end is in the future', async function () { + const date = new Date(); + date.setSeconds(date.getSeconds() + 10); + + const edition = new Edition({ end: date.toISOString(), publishingStatus: PublishingStatus.SCHEDULED }); + + importModule.skipScheduleIfNeeded(edition, false); + + expect(edition.publishingStatus).toEqual(PublishingStatus.SCHEDULED); + }); + + it('should leave the edition unscheduled if it was before', async function () { + const date = new Date(); + date.setSeconds(date.getSeconds() - 10); + + const edition = new Edition({ end: date.toISOString(), publishingStatus: PublishingStatus.DRAFT }); + + importModule.skipScheduleIfNeeded(edition, false); + + expect(edition.publishingStatus).toEqual(PublishingStatus.DRAFT); + }); + + it('should not remove scheduled status if catchup is true, even if the event end is in the past', async function () { + const date = new Date(); + date.setSeconds(date.getSeconds() - 10); + + const edition = new Edition({ end: date.toISOString(), publishingStatus: PublishingStatus.SCHEDULED }); + + importModule.skipScheduleIfNeeded(edition, true); + + expect(edition.publishingStatus).toEqual(PublishingStatus.SCHEDULED); + }); + }); + + describe('scheduleEdition tests', function () { + it('should schedule without logging anything if no warnings are returned', async function () { + const edition = new Edition({ lastModifiedDate: 'date' }); + const log = new FileLog(); + + edition.related.schedule = jest.fn().mockResolvedValue({}); + + await importModule.scheduleEdition(edition, log); + + expect(edition.related.schedule).toHaveBeenCalledTimes(1); + expect(edition.related.schedule).toHaveBeenCalledWith(false, 'date'); + expect(log.accessGroup).toEqual([]); + }); + it('should log warnings/errors if they are returned, and try again with ignoreWarnings true', async function () { + const edition = new Edition({ lastModifiedDate: 'date' }); + const log = new FileLog(); + + edition.related.schedule = jest + .fn() + .mockRejectedValueOnce({ + response: { + data: { + errors: [ + { + level: 'WARNING', + code: 'EDITION_SCHEDULE_OVERLAP', + message: 'Edition Schedule Overlap. Please try again later.', + overlaps: [ + { + editionId: 'edition-id', + name: 'Test schedule edition', + start: '2022-01-07T15:31:47.337Z' + } + ] + }, + { + level: 'WARNING', + code: 'EDITION_CONTAINS_SLOT_COLLISIONS', + message: 'Edition contains slots that collide with other editions.' + }, + { + level: 'ERROR', + code: 'FAKE_ERROR', + message: 'This is an error.' + } + ] + } + } + }) + .mockResolvedValueOnce({}); // Second call is resolved. + + await importModule.scheduleEdition(edition, log); + + expect(edition.related.schedule).toHaveBeenCalledTimes(2); + expect(edition.related.schedule).toHaveBeenNthCalledWith(1, false, 'date'); + expect(edition.related.schedule).toHaveBeenNthCalledWith(2, true, 'date'); + expect(log.accessGroup).toMatchInlineSnapshot(` +Array [ + Object { + "action": "WARNING", + "comment": false, + "data": "", + }, + Object { + "comment": true, + "data": "WARNING: EDITION_SCHEDULE_OVERLAP: Edition Schedule Overlap. Please try again later. (Test schedule edition - edition-id 2022-01-07T15:31:47.337Z)", + }, + Object { + "action": "WARNING", + "comment": false, + "data": "", + }, + Object { + "comment": true, + "data": "WARNING: EDITION_CONTAINS_SLOT_COLLISIONS: Edition contains slots that collide with other editions.", + }, + Object { + "action": "ERROR", + "comment": false, + "data": "", + }, + Object { + "comment": true, + "data": "ERROR: FAKE_ERROR: This is an error.", + }, +] +`); + }); + }); + + describe('rewriteSnapshots tests', function () { + it('should create new snapshots if no mapping is present, and use existing when it is', async function () { + const { mockSnapshotCreate } = mockValues({}); + + const { hub, log, mapping } = await commonMock(); + + mapping.registerContentItem('item1', 'realItem1'); + mapping.registerContentItem('item2', 'realItem2'); + + mapping.registerSnapshot('snap2', 'existingSnap'); + + const content = { + label: 'example', + body: { + _meta: { + name: 'example', + schema: 'https://amplience.com/example.json' + }, + chooser: [ + { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-link', + locked: false, + rootContentItemId: 'item1' + }, + contentType: 'https://amplience.com/example.json', + id: 'snap1' + }, + { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-link', + locked: false, + rootContentItemId: 'item2' + }, + contentType: 'https://amplience.com/example.json', + id: 'snap2' + } + ] + } + }; + + (mockSnapshotCreate as jest.Mock).mockResolvedValue({ snapshots: [new Snapshot({ id: 'newSnap' })] }); + + await importModule.rewriteSnapshots(content, mapping, hub, log); + + expect(mockSnapshotCreate).toHaveBeenCalledTimes(1); + expect((mockSnapshotCreate as jest.Mock).mock.calls[0][0]).toMatchInlineSnapshot(` + Array [ + Object { + "comment": "", + "contentRoot": "realItem1", + "createdFrom": "content-item", + "type": "GENERATED", + }, + ] + `); + expect(mapping.getSnapshot('snap1')).toEqual('newSnap'); + expect(content.body.chooser[0].id).toEqual('newSnap'); + expect(content.body.chooser[0]._meta.rootContentItemId).toEqual('realItem1'); + expect(content.body.chooser[1].id).toEqual('existingSnap'); + expect(content.body.chooser[1]._meta.rootContentItemId).toEqual('realItem2'); + }); + + it('should not create snapshots when content has no references', async function () { + const { mockSnapshotCreate } = mockValues({}); + + const { hub, log, mapping } = await commonMock(); + + const content = { + label: 'example', + body: { + _meta: { + name: 'example', + schema: 'https://amplience.com/example.json' + } + } + }; + + await importModule.rewriteSnapshots(content, mapping, hub, log); + + expect(mockSnapshotCreate).toHaveBeenCalledTimes(0); + }); + }); + + describe('importSlots tests', function () { + it('should look up existing slot from mapping if present, and update it', async function () { + mockValues({}); + + const realSlot = new EditionSlot({ id: 'id-2', content: 'updated' }); + realSlot.related.content = jest.fn().mockResolvedValue(realSlot); + + const { hub, argv, log, mapping } = await commonMock(); + + mapping.registerSlot('id-1', 'id-2'); + + const rewriteSnapshots = jest.spyOn(importModule, 'rewriteSnapshots').mockResolvedValue(false); + const importTest = [ + new EditionSlot({ + id: 'id-1', + content: '{ "content": "test" }' + }) + ]; + + const realEdition = new Edition(); + realEdition.related.slots.list = jest.fn().mockResolvedValue(new MockPage(EditionSlot, [realSlot])); + + const result = await importSlots(importTest, mapping, hub, realEdition, argv, log); + + expect(result).toBeFalsy(); // rewriteSnapshots returns false. + + expect(realEdition.related.slots.list).toHaveBeenCalledTimes(1); + expect(realSlot.related.content).toHaveBeenCalledTimes(1); + + expect(rewriteSnapshots).toHaveBeenCalledWith('{ "content": "test" }', mapping, hub, log); + }); + + it('should look up original id if no mapping present and originalIds set', async function () { + mockValues({}); + + const realSlot = new EditionSlot({ id: 'id-1', content: 'updated' }); + realSlot.related.content = jest.fn().mockResolvedValue(realSlot); + + const { hub, argv, log, mapping } = await commonMock({ originalIds: true }); + + const rewriteSnapshots = jest.spyOn(importModule, 'rewriteSnapshots').mockResolvedValue(false); + const importTest = [ + new EditionSlot({ + id: 'id-1', + content: '{ "content": "test" }' + }) + ]; + + const realEdition = new Edition(); + realEdition.related.slots.list = jest.fn().mockResolvedValue(new MockPage(EditionSlot, [realSlot])); + + await importSlots(importTest, mapping, hub, realEdition, argv, log); + + expect(realEdition.related.slots.list).toHaveBeenCalledTimes(1); + expect(realSlot.related.content).toHaveBeenCalledTimes(1); + + expect(rewriteSnapshots).toHaveBeenCalledWith('{ "content": "test" }', mapping, hub, log); + }); + + it('should create a new slot if no existing one is found', async function () { + mockValues({}); + + const realSlot = new EditionSlot({ id: 'id-new', content: 'updated' }); + realSlot.related.content = jest.fn().mockResolvedValue(realSlot); + + const { hub, argv, log, mapping } = await commonMock({ originalIds: false }); + + const rewriteSnapshots = jest.spyOn(importModule, 'rewriteSnapshots').mockResolvedValue(false); + const importTest = [ + new EditionSlot({ + id: 'id-1', + content: '{ "content": "test" }' + }) + ]; + + const realEdition = new Edition(); + realEdition.related.slots.create = jest.fn().mockResolvedValue(new MockPage(EditionSlot, [realSlot])); + realEdition.related.slots.list = jest.fn().mockResolvedValue(new MockPage(EditionSlot, [])); + + await importSlots(importTest, mapping, hub, realEdition, argv, log); + + expect(realEdition.related.slots.list).toHaveBeenCalledTimes(1); + expect(realEdition.related.slots.create).toHaveBeenCalledTimes(1); + expect(realSlot.related.content).toHaveBeenCalledTimes(1); + + expect(mapping.getSlot('id-1')).toEqual('id-new'); + + expect(rewriteSnapshots).toHaveBeenCalledWith('{ "content": "test" }', mapping, hub, log); + }); + + it('should return true if any rewriteSnapshots call returns true', async function () { + mockValues({}); + + const realSlot = new EditionSlot({ id: 'id-new', content: 'updated' }); + realSlot.related.content = jest.fn().mockResolvedValue(realSlot); + + const { hub, argv, log, mapping } = await commonMock({ originalIds: false }); + + const rewriteSnapshots = jest + .spyOn(importModule, 'rewriteSnapshots') + .mockResolvedValueOnce(false) + .mockResolvedValueOnce(true); + const importTest = [ + new EditionSlot({ + id: 'id-1', + content: '{ "content": "test" }' + }), + new EditionSlot({ + id: 'id-2', + content: '{ "content": "test" }' + }) + ]; + + const realEdition = new Edition(); + realEdition.related.slots.create = jest.fn().mockResolvedValue(new MockPage(EditionSlot, [realSlot])); + realEdition.related.slots.list = jest.fn().mockResolvedValue(new MockPage(EditionSlot, [])); + + const result = await importSlots(importTest, mapping, hub, realEdition, argv, log); + + expect(result).toBeTruthy(); + + expect(realEdition.related.slots.list).toHaveBeenCalledTimes(1); + expect(realEdition.related.slots.create).toHaveBeenCalledTimes(2); + expect(realSlot.related.content).toHaveBeenCalledTimes(2); + + expect(rewriteSnapshots).toHaveBeenCalledTimes(2); + }); + }); + + describe('importEditions tests', function () { + it('should look up existing edition from mapping if present, and update it', async function () { + const { mockEditionGet, mockEditionUpdate } = mockValues({}); + + const realEdition = new Edition({ id: 'id-2', name: 'updated' }); + (mockEditionUpdate as jest.Mock).mockResolvedValue(realEdition); + + const { client, hub, argv, log, mapping } = await commonMock(); + + mapping.registerEdition('id-1', 'id-2'); + + const importSlots = jest.spyOn(importModule, 'importSlots').mockResolvedValue(false); + const slots = [new EditionSlot({ id: 'slot1' }), new EditionSlot({ id: 'slot2' })]; + const importTest = [ + new EditionWithSlots({ + id: 'id-1', + name: 'Edition', + start: '0', + end: '1', + comment: 'comment', + slots + }) + ]; + + const realEvent = new Event(); + + await importEditions(importTest, mapping, client, hub, realEvent, argv, log); + + expect(mockEditionGet).toHaveBeenCalledWith('id-2'); + expect(mockEditionUpdate).toHaveBeenCalledTimes(1); + + expect(importSlots).toHaveBeenCalledWith(slots, mapping, hub, realEdition, argv, log); + }); + + it('should look up original id if no mapping present and originalIds set', async function () { + const { mockEditionGet, mockEditionUpdate } = mockValues({}); + + const realEdition = new Edition({ id: 'id-1', name: 'updated' }); + (mockEditionUpdate as jest.Mock).mockResolvedValue(realEdition); + + const { client, hub, argv, log, mapping } = await commonMock({ originalIds: true }); + + const importSlots = jest.spyOn(importModule, 'importSlots').mockResolvedValue(false); + const slots = [new EditionSlot({ id: 'slot1' }), new EditionSlot({ id: 'slot2' })]; + const importTest = [ + new EditionWithSlots({ + id: 'id-1', + name: 'Edition', + start: '0', + end: '1', + comment: 'comment', + slots + }) + ]; + + const realEvent = new Event(); + + await importEditions(importTest, mapping, client, hub, realEvent, argv, log); + + expect(mockEditionGet).toHaveBeenCalledWith('id-1'); + expect(mockEditionUpdate).toHaveBeenCalledTimes(1); + + expect(importSlots).toHaveBeenCalledWith(slots, mapping, hub, realEdition, argv, log); + }); + + it('should create a new edition if no existing one is found', async function () { + const { mockEditionGet, mockEditionUpdate } = mockValues({}); + + const realEdition = new Edition({ id: 'id-1', name: 'updated' }); + const realEvent = new Event(); + realEvent.related.editions.create = jest.fn().mockResolvedValue(realEdition); + + const { client, hub, argv, log, mapping } = await commonMock({ originalIds: false }); + + const importSlots = jest.spyOn(importModule, 'importSlots').mockResolvedValue(false); + const slots = [new EditionSlot({ id: 'slot1' }), new EditionSlot({ id: 'slot2' })]; + const importTest = [ + new EditionWithSlots({ + id: 'id-1', + name: 'Edition', + start: '0', + end: '1', + comment: 'comment', + slots + }) + ]; + + await importEditions(importTest, mapping, client, hub, realEvent, argv, log); + + expect(mockEditionGet).not.toHaveBeenCalled(); + expect(mockEditionUpdate).not.toHaveBeenCalled(); + expect(realEvent.related.editions.create).toHaveBeenCalledTimes(1); + + expect(importSlots).toHaveBeenCalledWith(slots, mapping, hub, realEdition, argv, log); + }); + + it('should try schedule an edition if its scheduled status indicates that it was in the source', async function () { + const { mockEditionGet, mockEditionUpdate } = mockValues({}); + + const realEdition = new Edition({ id: 'id-2', name: 'updated', publishingStatus: PublishingStatus.DRAFT }); + (mockEditionUpdate as jest.Mock).mockResolvedValue(realEdition); + + const { client, hub, argv, log, mapping } = await commonMock(); + + argv.schedule = true; + mapping.registerEdition('id-1', 'id-2'); + + const importSlots = jest.spyOn(importModule, 'importSlots').mockResolvedValue(false); + const scheduleEdition = jest.spyOn(importModule, 'scheduleEdition').mockResolvedValue(); + const skipSchedule = jest.spyOn(importModule, 'skipScheduleIfNeeded').mockReturnValue(); + const prepareEdition = jest.spyOn(importModule, 'prepareEditionForSchedule').mockResolvedValue(); + + const slots = [new EditionSlot({ id: 'slot1' }), new EditionSlot({ id: 'slot2' })]; + const importTest = [ + new EditionWithSlots({ + id: 'id-1', + name: 'Edition', + start: dateOffset(10).toISOString(), + end: dateOffset(15).toISOString(), + publishingStatus: PublishingStatus.SCHEDULED, + comment: 'comment', + slots + }) + ]; + + const realEvent = new Event({ + start: dateOffset(5).toISOString(), + end: dateOffset(20).toISOString() + }); + + await importEditions(importTest, mapping, client, hub, realEvent, argv, log); + + expect(mockEditionGet).toHaveBeenCalledWith('id-2'); + expect(mockEditionUpdate).toHaveBeenCalledTimes(1); + + expect(skipSchedule).toHaveBeenCalledWith(importTest[0], true); + expect(prepareEdition).toHaveBeenCalledWith(expect.any(Edition), realEvent); + + expect(importSlots).toHaveBeenCalledWith(slots, mapping, hub, realEdition, argv, log); + expect(scheduleEdition).toHaveBeenCalledWith(expect.any(Edition), log); + }); + + it('should try unschedule the existing edition if already scheduled, update if succeeded, reschedule', async function () { + const { mockEditionGet, mockEditionUpdate, mockEditionUnschedule, mockSlotsList, mockEdition } = mockValues({ + status: PublishingStatus.SCHEDULED + }); + + const baseEdition = { id: 'id-2', name: 'updated', publishingStatus: PublishingStatus.DRAFT }; + (mockEditionGet as jest.Mock).mockReset(); + (mockEditionGet as jest.Mock).mockResolvedValueOnce(mockEdition); + + const newEdition = new Edition(baseEdition); + newEdition.related.update = mockEdition.related.update; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (newEdition as any).client = { fetchLinkedResource: mockSlotsList }; + (mockEditionGet as jest.Mock).mockResolvedValueOnce(newEdition); + (mockEditionGet as jest.Mock).mockResolvedValueOnce(newEdition); + (mockEditionUpdate as jest.Mock).mockResolvedValue(newEdition); + (mockEditionUnschedule as jest.Mock).mockResolvedValue(undefined); + + const { client, hub, argv, log, mapping } = await commonMock(); + + argv.schedule = true; + mapping.registerEdition('id-1', 'id-2'); + + const importSlots = jest.spyOn(importModule, 'importSlots').mockResolvedValue(false); + const scheduleEdition = jest.spyOn(importModule, 'scheduleEdition').mockResolvedValue(); + const skipSchedule = jest.spyOn(importModule, 'skipScheduleIfNeeded').mockReturnValue(); + const prepareEdition = jest.spyOn(importModule, 'prepareEditionForSchedule').mockResolvedValue(); + + const slots = [new EditionSlot({ id: 'slot1' }), new EditionSlot({ id: 'slot2' })]; + const importTest = [ + new EditionWithSlots({ + id: 'id-1', + name: 'Edition', + start: dateOffset(10).toISOString(), + end: dateOffset(15).toISOString(), + publishingStatus: PublishingStatus.SCHEDULED, + comment: 'comment', + slots + }) + ]; + + const realEvent = new Event({ + start: dateOffset(5).toISOString(), + end: dateOffset(20).toISOString() + }); + + await importEditions(importTest, mapping, client, hub, realEvent, argv, log); + + expect(mockEditionUnschedule).toHaveBeenCalled(); + expect(mockEditionGet).toHaveBeenNthCalledWith(1, 'id-2'); + expect(mockEditionGet).toHaveBeenNthCalledWith(3, 'id-2'); + expect(mockEditionUpdate).toHaveBeenCalledTimes(1); + + expect(skipSchedule).toHaveBeenCalledWith(importTest[0], true); + expect(prepareEdition).toHaveBeenCalledWith(expect.any(Edition), realEvent); + + expect(importSlots).toHaveBeenCalledWith(slots, mapping, hub, newEdition, argv, log); + expect(scheduleEdition).toHaveBeenCalledWith(expect.any(Edition), log); + }); + + it('should try unschedule the existing edition if already scheduled, do not update if failed', async function () { + const { mockEditionGet, mockEditionUpdate, mockEditionUnschedule, mockSlotsList, mockEdition } = mockValues({ + status: PublishingStatus.SCHEDULED + }); + + const baseEdition = { id: 'id-2', name: 'updated', publishingStatus: PublishingStatus.DRAFT }; + (mockEditionGet as jest.Mock).mockReset(); + (mockEditionGet as jest.Mock).mockResolvedValueOnce(mockEdition); + + const newEdition = new Edition(baseEdition); + newEdition.related.update = mockEdition.related.update; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (newEdition as any).client = { fetchLinkedResource: mockSlotsList }; + (mockEditionGet as jest.Mock).mockResolvedValueOnce(newEdition); + (mockEditionUnschedule as jest.Mock).mockRejectedValue(new Error('Unschedule Failed')); + + const { client, hub, argv, log, mapping } = await commonMock(); + + argv.schedule = true; + mapping.registerEdition('id-1', 'id-2'); + + const importSlots = jest.spyOn(importModule, 'importSlots').mockResolvedValue(false); + const scheduleEdition = jest.spyOn(importModule, 'scheduleEdition').mockResolvedValue(); + const skipSchedule = jest.spyOn(importModule, 'skipScheduleIfNeeded').mockReturnValue(); + const prepareEdition = jest.spyOn(importModule, 'prepareEditionForSchedule').mockResolvedValue(); + + const slots = [new EditionSlot({ id: 'slot1' }), new EditionSlot({ id: 'slot2' })]; + const importTest = [ + new EditionWithSlots({ + id: 'id-1', + name: 'Edition', + start: dateOffset(10).toISOString(), + end: dateOffset(15).toISOString(), + publishingStatus: PublishingStatus.SCHEDULED, + comment: 'comment', + slots + }) + ]; + + const realEvent = new Event({ + start: dateOffset(5).toISOString(), + end: dateOffset(20).toISOString() + }); + + await importEditions(importTest, mapping, client, hub, realEvent, argv, log); + + expect(mockEditionUnschedule).toHaveBeenCalled(); + expect(mockEditionGet).toHaveBeenCalledWith('id-2'); + expect(mockEditionUpdate).not.toHaveBeenCalled(); + + expect(skipSchedule).toHaveBeenCalledWith(importTest[0], true); + expect(prepareEdition).not.toHaveBeenCalled(); + + expect(importSlots).not.toHaveBeenCalled(); + expect(scheduleEdition).not.toHaveBeenCalled(); + }); + + it('should not unschedule or update an edition published in the past', async function () { + const { mockEditionGet, mockEditionUpdate, mockEditionUnschedule, mockSlotsList, mockEdition } = mockValues({ + status: PublishingStatus.PUBLISHED + }); + + const baseEdition = { id: 'id-2', name: 'updated', publishingStatus: PublishingStatus.DRAFT }; + (mockEditionGet as jest.Mock).mockReset(); + (mockEditionGet as jest.Mock).mockResolvedValueOnce(mockEdition); + + const newEdition = new Edition(baseEdition); + newEdition.related.update = mockEdition.related.update; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (newEdition as any).client = { fetchLinkedResource: mockSlotsList }; + (mockEditionGet as jest.Mock).mockResolvedValueOnce(newEdition); + + const { client, hub, argv, log, mapping } = await commonMock(); + + argv.schedule = true; + mapping.registerEdition('id-1', 'id-2'); + + const importSlots = jest.spyOn(importModule, 'importSlots').mockResolvedValue(false); + const scheduleEdition = jest.spyOn(importModule, 'scheduleEdition').mockResolvedValue(); + const skipSchedule = jest.spyOn(importModule, 'skipScheduleIfNeeded').mockReturnValue(); + const prepareEdition = jest.spyOn(importModule, 'prepareEditionForSchedule').mockResolvedValue(); + + const slots = [new EditionSlot({ id: 'slot1' }), new EditionSlot({ id: 'slot2' })]; + const importTest = [ + new EditionWithSlots({ + id: 'id-1', + name: 'Edition', + start: dateOffset(-20).toISOString(), + end: dateOffset(-15).toISOString(), + publishingStatus: PublishingStatus.PUBLISHED, + comment: 'comment', + slots + }) + ]; + + const realEvent = new Event({ + start: dateOffset(-25).toISOString(), + end: dateOffset(-10).toISOString() + }); + + await importEditions(importTest, mapping, client, hub, realEvent, argv, log); + + expect(mockEditionGet).toHaveBeenCalledWith('id-2'); + expect(mockEditionUnschedule).not.toHaveBeenCalled(); + expect(mockEditionUpdate).not.toHaveBeenCalled(); + + expect(skipSchedule).toHaveBeenCalledWith(importTest[0], true); + expect(prepareEdition).not.toHaveBeenCalled(); + + expect(importSlots).not.toHaveBeenCalled(); + expect(scheduleEdition).not.toHaveBeenCalled(); + }); + + it('should not update edition if it is identical', async function () { + const { mockEditionGet, mockEditionUpdate } = mockValues({}); + + const realEdition = new Edition({ id: 'id-2', name: 'updated' }); + (mockEditionUpdate as jest.Mock).mockResolvedValue(realEdition); + + const { client, hub, argv, log, mapping } = await commonMock(); + + mapping.registerEdition('id-1', 'id-2'); + + const importSlots = jest.spyOn(importModule, 'importSlots').mockResolvedValue(false); + const shouldUpdate = jest.spyOn(importModule, 'shouldUpdateEdition').mockReturnValue(false); + const slots = [new EditionSlot({ id: 'slot1' }), new EditionSlot({ id: 'slot2' })]; + const importTest = [ + new EditionWithSlots({ + id: 'id-1', + name: 'Edition', + start: '0', + end: '1', + comment: 'comment', + slots + }) + ]; + + const realEvent = new Event(); + + await importEditions(importTest, mapping, client, hub, realEvent, argv, log); + + expect(mockEditionGet).toHaveBeenCalledWith('id-2'); + expect(shouldUpdate).toHaveBeenCalled(); + expect(mockEditionUpdate).not.toHaveBeenCalled(); + + expect(importSlots).not.toHaveBeenCalled(); + }); + + it('should refetch and update editions so that their start dates are not in the past after snapshot creation when publishing', async function () { + const { mockEditionGet, mockEditionUpdate } = mockValues({}); + + const realEdition = new Edition({ id: 'id-2', name: 'updated', publishingStatus: PublishingStatus.DRAFT }); + (mockEditionUpdate as jest.Mock).mockResolvedValue(realEdition); + + const { client, hub, argv, log, mapping } = await commonMock(); + + argv.schedule = true; + mapping.registerEdition('id-1', 'id-2'); + + // Indicate that the snapshot creation has happened. + const importSlots = jest.spyOn(importModule, 'importSlots').mockResolvedValue(true); + const scheduleEdition = jest.spyOn(importModule, 'scheduleEdition').mockResolvedValue(); + const skipSchedule = jest.spyOn(importModule, 'skipScheduleIfNeeded').mockReturnValue(); + const prepareEdition = jest.spyOn(importModule, 'prepareEditionForSchedule').mockImplementation(async edition => { + edition.start = dateOffset(5).toISOString(); + }); + + const slots = [new EditionSlot({ id: 'slot1' }), new EditionSlot({ id: 'slot2' })]; + const importTest = [ + new EditionWithSlots({ + id: 'id-1', + name: 'Edition', + start: dateOffset(-10).toISOString(), + end: dateOffset(15).toISOString(), + publishingStatus: PublishingStatus.SCHEDULED, + comment: 'comment', + slots + }) + ]; + + const realEvent = new Event({ + start: dateOffset(-10).toISOString(), + end: dateOffset(20).toISOString() + }); + + await importEditions(importTest, mapping, client, hub, realEvent, argv, log); + + expect(mockEditionGet).toHaveBeenCalledWith('id-2'); + expect(mockEditionUpdate).toHaveBeenCalledTimes(2); + + expect(skipSchedule).toHaveBeenCalledWith(importTest[0], true); + expect(prepareEdition).toHaveBeenCalledWith(expect.any(Edition), realEvent); + + expect(importSlots).toHaveBeenCalledWith(slots, mapping, hub, realEdition, argv, log); + expect(scheduleEdition).toHaveBeenCalledWith(expect.any(Edition), log); + + expect(importModule.prepareEditionForSchedule).toHaveBeenCalledTimes(2); // This should be called again just before schedule. + }); + }); + + describe('importEvents tests', function () { + it('should look up existing event from mapping if present, and update it', async function () { + const { mockGet, mockEventUpdate } = mockValues({}); + + const realEvent = new Event({ id: 'id-2', name: 'updated' }); + (mockEventUpdate as jest.Mock).mockResolvedValue(realEvent); + + const { client, hub, argv, log, mapping } = await commonMock(); + + mapping.registerEvent('id-1', 'id-2'); + + const importEditions = jest.spyOn(importModule, 'importEditions').mockResolvedValue(); + const editions = [new EditionWithSlots({ id: 'edition1' }), new EditionWithSlots({ id: 'edition2' })]; + const importTest = [ + new EventWithEditions({ + id: 'id-1', + name: 'event', + start: '0', + end: '1', + comment: 'comment', + brief: 'brief', + editions + }) + ]; + + await importEvents(importTest, mapping, client, hub, argv, log); + + expect(mockGet).toHaveBeenCalledWith('id-2'); + expect(mockEventUpdate).toHaveBeenCalledTimes(1); + + expect(importEditions).toHaveBeenCalledWith(editions, mapping, client, hub, realEvent, argv, log); + }); + + it('should look up original id if no mapping present and originalIds set', async function () { + const { mockGet, mockEventUpdate } = mockValues({}); + + const realEvent = new Event({ id: 'id-1', name: 'updated' }); + (mockEventUpdate as jest.Mock).mockResolvedValue(realEvent); + + const { client, hub, argv, log, mapping } = await commonMock({ originalIds: true }); + + const importEditions = jest.spyOn(importModule, 'importEditions').mockResolvedValue(); + const editions = [new EditionWithSlots({ id: 'edition1' }), new EditionWithSlots({ id: 'edition2' })]; + const importTest = [ + new EventWithEditions({ + id: 'id-1', + name: 'event', + start: '0', + end: '1', + comment: 'comment', + brief: 'brief', + editions + }) + ]; + + await importEvents(importTest, mapping, client, hub, argv, log); + + expect(mockGet).toHaveBeenCalledWith('id-1'); + expect(mockEventUpdate).toHaveBeenCalledTimes(1); + + expect(importEditions).toHaveBeenCalledWith(editions, mapping, client, hub, realEvent, argv, log); + }); + + it('should create a new event if no existing one is found', async function () { + const { mockGet, mockEventCreate, mockEventUpdate } = mockValues({}); + + const realEvent = new Event({ id: 'new-id', name: 'updated' }); + (mockEventCreate as jest.Mock).mockResolvedValue(realEvent); + + const { client, hub, argv, log, mapping } = await commonMock({ originalIds: false }); + + const importEditions = jest.spyOn(importModule, 'importEditions').mockResolvedValue(); + const editions = [new EditionWithSlots({ id: 'edition1' }), new EditionWithSlots({ id: 'edition2' })]; + const importTest = [ + new EventWithEditions({ + id: 'id-1', + name: 'event', + start: '0', + end: '1', + comment: 'comment', + brief: 'brief', + editions + }) + ]; + + await importEvents(importTest, mapping, client, hub, argv, log); + + expect(mockGet).not.toHaveBeenCalled(); + expect(mockEventUpdate).toHaveBeenCalledTimes(0); + expect(mockEventCreate).toHaveBeenCalledTimes(1); + + expect(mapping.getEvent('id-1')).toEqual('new-id'); + + expect(importEditions).toHaveBeenCalledWith(editions, mapping, client, hub, realEvent, argv, log); + }); + }); + + describe('trySaveMapping tests', function () { + it('should save a given mapping file', async function () { + const log = new FileLog(); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const fakeMapping: any = { + save: jest.fn().mockResolvedValue(true) + }; + + await trySaveMapping('file.txt', fakeMapping as ContentMapping, log); + + expect(fakeMapping.save).toHaveBeenCalledWith('file.txt'); + expect(log.accessGroup.length).toEqual(0); + }); + + it('should log an error if mapping save fails', async function () { + const log = new FileLog(); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const fakeMapping: any = { + save: jest.fn().mockRejectedValue('error') + }; + + await trySaveMapping('file.txt', fakeMapping as ContentMapping, log); + + expect(fakeMapping.save).toHaveBeenCalledWith('file.txt'); + expect(log.accessGroup.length).toEqual(1); + expect(log.accessGroup[0]).toMatchInlineSnapshot(` + Object { + "comment": true, + "data": "Failed to save the mapping. error", + } + `); + }); + + it('should do nothing for an undefined mapFile', async function () { + const log = new FileLog(); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const fakeMapping: any = { + save: jest.fn().mockRejectedValue('error') + }; + + await trySaveMapping(undefined, fakeMapping, log); + + expect(log.accessGroup.length).toEqual(0); + expect(fakeMapping.save).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/src/commands/event/import.ts b/src/commands/event/import.ts new file mode 100644 index 00000000..eacbb439 --- /dev/null +++ b/src/commands/event/import.ts @@ -0,0 +1,574 @@ +import { Arguments, Argv } from 'yargs'; +import { ConfigurationParameters } from '../configure'; +import { + DynamicContent, + Event, + Edition, + EditionSlot, + Hub, + ContentRepository, + Snapshot, + SnapshotType, + PublishingStatus +} from 'dc-management-sdk-js'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import paginator from '../../common/dc-management-sdk-js/paginator'; +import { loadJsonFromDirectory } from '../../services/import.service'; +import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { ImportEventBuilderOptions } from '../../interfaces/import-event-builder-options.interface'; +import { EditionWithSlots, EventWithEditions } from './export'; +import { ContentMapping } from '../../common/content-mapping'; +import { join } from 'path'; +import { FileLog } from '../../common/file-log'; +import { + ContentDependancy, + ContentDependancyTree, + DependancyContentTypeSchema +} from '../../common/content-item/content-dependancy-tree'; +import { SnapshotCreator } from 'dc-management-sdk-js/build/main/lib/model/SnapshotCreator'; +import { isEqual } from 'lodash'; +import { dateMax, dateOffset, sortByEndDate, TimeRange } from '../../common/import/date-helpers'; +import { EditionScheduleStatus } from '../../common/dc-management-sdk-js/event-schedule-error'; + +export const InstantSecondsAllowance = 5; +export const EditionSecondsAllowance = 5; +export const EventSecondsAllowance = 60; +export const ScheduleSecondsAllowance = 5; + +export const command = 'import '; + +export const desc = 'Import Events'; + +export const LOG_FILENAME = (platform: string = process.platform): string => + getDefaultLogPath('event', 'import', platform); + +export const getDefaultMappingPath = (name: string, platform: string = process.platform): string => { + return join( + process.env[platform == 'win32' ? 'USERPROFILE' : 'HOME'] || __dirname, + '.amplience', + `imports/`, + `${name}.json` + ); +}; + +export const builder = (yargs: Argv): void => { + yargs + .positional('dir', { + describe: 'Directory containing Events', + type: 'string' + }) + + .option('acceptSnapshotLimits', { + type: 'boolean', + boolean: true, + describe: + 'Must be passed to use the event import command. Only use this command if you fully understand its limitations.' + }) + + .option('mapFile', { + type: 'string', + describe: + 'Mapping file to use when updating content that already exists. Updated with any new mappings that are generated. If not present, will be created.' + }) + + .alias('f', 'force') + .option('f', { + type: 'boolean', + boolean: true, + describe: 'Overwrite existing events, editions, slots and snapshots without asking.' + }) + + .option('schedule', { + type: 'boolean', + boolean: true, + describe: + 'Schedule events in the destination repo if they are scheduled in the source. If any new or updated scheduled events started in the past, they will be moved to happen at the time of import. If they ended in the past, they will be skipped by default.' + }) + + .option('catchup', { + type: 'boolean', + boolean: true, + describe: 'Scheduling events that ended in the past will move to the current date, so that their publishes run.' + }) + + .option('originalIds', { + type: 'boolean', + boolean: true, + describe: 'Use original ids' + }) + + .option('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: createLog + }); +}; + +interface SlotDependencyMeta { + name: string; + rootContentItemId: string; + locked: boolean; + schema: DependancyContentTypeSchema; +} + +interface SlotDependency extends ContentDependancy { + _meta: SlotDependencyMeta; +} + +export const boundTimeRange = (realRange: TimeRange, range: TimeRange): void => { + // Only update the resource start time if it is in the future, and less than existing. + // Only update the resource end time if it is greater than existing. + const eventStart = new Date(range.start as string); + const realEventStart = new Date(range.start as string); + const nowOffset = dateOffset(InstantSecondsAllowance); + + if (new Date(range.end as string) < new Date(realRange.end as string)) { + range.end = realRange.end; + } + + if (eventStart > realEventStart || realEventStart < nowOffset) { + range.start = realRange.start; + } +}; + +export const shouldUpdateSlot = (realSlot: EditionSlot, slot: EditionSlot): boolean => { + return !isEqual(slot.content, realSlot.content); +}; + +export const shouldUpdateEvent = (realEvent: Event, event: Event): boolean => { + boundTimeRange(realEvent, event); + + return ( + event.name !== realEvent.name || + event.brief !== realEvent.brief || + event.comment !== realEvent.comment || + event.start !== realEvent.start || + event.end !== realEvent.end + ); +}; + +export const shouldUpdateEdition = ( + realEdition: Edition, + realSlots: EditionSlot[], + edition: EditionWithSlots +): boolean => { + boundTimeRange(realEdition, edition); + + return ( + edition.name !== realEdition.name || + edition.start !== realEdition.start || + edition.end !== realEdition.end || + edition.comment !== realEdition.comment || + edition.activeEndDate !== realEdition.activeEndDate || + edition.slots.length != realSlots.length || + edition.slots.map((x, i) => shouldUpdateSlot(x, realSlots[i])).reduce((a, b) => a || b, false) + ); +}; + +export const rewriteSnapshots = async ( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + content: any, + mapping: ContentMapping, + hub: Hub, + log: FileLog +): Promise => { + // Search for links/references in the slot content. + const dummyRepo = new ContentRepository(); + const tree = new ContentDependancyTree([{ repo: dummyRepo, content }], new ContentMapping()); + + const dependencies = tree.all[0].dependancies; + + let snapshotCreated = false; + + for (const dep of dependencies) { + const entry = dep.dependancy as SlotDependency; + + // Try find the snapshot in the mapping + let snapshotId = mapping.getSnapshot(entry.id); + const itemId = mapping.getContentItem(entry._meta.rootContentItemId) || entry._meta.rootContentItemId; + + if (snapshotId == null) { + // Create a new snapshot based off of the current content state + const result = await hub.related.snapshots.create([ + new Snapshot({ + contentRoot: itemId, + comment: '', + createdFrom: SnapshotCreator.ContentItem, + type: SnapshotType.GENERATED + }) + ]); + + const snapshot = result.snapshots[0]; + + snapshotId = snapshot.id as string; + + mapping.registerSnapshot(entry.id as string, snapshotId); + + log.addAction('SNAPSHOT-CREATE', snapshotId); + snapshotCreated = true; + } + + dep.dependancy.id = snapshotId; + entry._meta.rootContentItemId = itemId; + } + + return snapshotCreated; +}; + +export const importSlots = async ( + slots: EditionSlot[], + mapping: ContentMapping, + hub: Hub, + edition: Edition, + argv: ImportEventBuilderOptions, + log: FileLog +): Promise => { + const editionSlots = await paginator(edition.related.slots.list); + let snapshot = false; + + for (const slot of slots) { + let realSlot: EditionSlot | undefined = undefined; + + // Attempt to get the existing edition, if present. + const slotId = mapping.getSlot(slot.id); + + if (slotId == null) { + if (argv.originalIds && slot.id) { + // Look up the original ID. + realSlot = editionSlots.find(editionSlot => editionSlot.id === slot.id); + } + } else { + // Look up the mapped ID. + realSlot = editionSlots.find(editionSlot => editionSlot.id === slotId); + } + + // Attempt to link to existing content item + const itemId = mapping.getContentItem(slot.slotId) || (slot.slotId as string); + + const updated = realSlot != null; + + if (realSlot == null) { + // Create a new slot based off of the file. + const slotPage = await edition.related.slots.create([{ slot: itemId }]); + + const items = slotPage.getItems(); + + realSlot = items[0]; + + mapping.registerSlot(slot.id as string, realSlot.id as string); + } + + // Update the existing slot based off of the file. + snapshot = (await rewriteSnapshots(slot.content, mapping, hub, log)) || snapshot; + + realSlot = await realSlot.related.content(slot.content); + + log.addComment(`${updated ? 'Updated' : 'Created'} slot ${realSlot.slotId}.`); + log.addAction(`SLOT-${updated ? 'UPDATE' : 'CREATE'}`, realSlot.id as string); + } + + return snapshot; +}; + +export const isScheduled = (edition: Edition): boolean => + edition.publishingStatus === PublishingStatus.PUBLISHED || + edition.publishingStatus === PublishingStatus.PUBLISHING || + edition.publishingStatus === PublishingStatus.SCHEDULING || + edition.publishingStatus === PublishingStatus.SCHEDULED; + +export const moveDateToFuture = async (date: string, event: Event, offset: number): Promise => { + const newDate = dateMax(new Date(date as string), dateOffset(offset)); + + if (newDate > new Date(event.end as string)) { + event.end = dateMax(dateOffset(EventSecondsAllowance), newDate).toISOString(); + + await event.related.update(event); + } + + return newDate.toISOString(); +}; + +export const prepareEditionForSchedule = async (edition: Edition, event: Event, force = false): Promise => { + if (force || isScheduled(edition)) { + // This edition must start in the future for it to be scheduled. + edition.start = await moveDateToFuture(edition.start as string, event, EditionSecondsAllowance); + edition.end = await moveDateToFuture(edition.end as string, event, ScheduleSecondsAllowance); + } +}; + +export const scheduleEdition = async (edition: Edition, log: FileLog): Promise => { + try { + await edition.related.schedule(false, edition.lastModifiedDate); + } catch (e) { + if (e.response && e.response.data && typeof e.response.data === 'object') { + // Attempt to parse the response data. + + const warning = new EditionScheduleStatus(e.response.data); + + if (warning.errors) { + for (const error of warning.errors) { + if (error.level === 'WARNING') { + let message = `${error.code}: ${error.message}`; + + if (error.overlaps) { + message += ` (${error.overlaps + .map(overlap => `${overlap.name} - ${overlap.editionId} ${overlap.start}`) + .join(', ')})`; + } + + log.warn(message); + } else { + log.error(`${error.code}: ${error.message}`); + } + } + + // Errors the second time will be thrown (ignoreWarnings is passed). + await edition.related.schedule(true, edition.lastModifiedDate); + } + } else { + throw e; + } + } +}; + +export const skipScheduleIfNeeded = (edition: Edition, catchup: boolean): void => { + if (!catchup && isScheduled(edition) && new Date(edition.end as string) < new Date()) { + // Skip publish of events fully in the past, if catchup events are not to be created. + edition.publishingStatus = PublishingStatus.DRAFT; + } +}; + +export const importEditions = async ( + editions: EditionWithSlots[], + mapping: ContentMapping, + client: DynamicContent, + hub: Hub, + event: Event, + argv: ImportEventBuilderOptions, + log: FileLog +): Promise => { + for (const edition of editions) { + let realEdition: Edition | null = null; + + // Attempt to get the existing edition, if present. + const editionId = mapping.getEdition(edition.id); + + if (editionId == null) { + if (argv.originalIds && edition.id) { + // Look up the original ID. + realEdition = await client.editions.get(edition.id); + } + } else { + // Look up the mapped ID. + realEdition = await client.editions.get(editionId); + } + + const filteredEdition = new Edition({ + name: edition.name, + start: edition.start, + end: edition.end, + comment: edition.comment, + activeEndDate: edition.activeEndDate, + publishingStatus: edition.publishingStatus + }); + + let update = true; + let schedule = argv.schedule; + + skipScheduleIfNeeded(edition, argv.catchup); + + if (realEdition == null) { + // Create a new edition based off of the file. + await prepareEditionForSchedule(filteredEdition, event); + + realEdition = await event.related.editions.create(filteredEdition); + + log.addComment(`Created edition ${realEdition.name}.`); + log.addAction('EDITION-CREATE', realEdition.id as string); + + mapping.registerEdition(edition.id as string, realEdition.id as string); + } else { + const slots = await paginator(realEdition.related.slots.list); + + if ( + shouldUpdateEdition(realEdition, slots, edition) || + (schedule && !isScheduled(realEdition) && isScheduled(edition)) + ) { + // If the edition has already published, it cannot be modified. + // Copy back start/end in case they were modified above. + filteredEdition.start = edition.start; + filteredEdition.end = edition.end; + + if ( + realEdition.publishingStatus == PublishingStatus.SCHEDULED || + realEdition.publishingStatus == PublishingStatus.SCHEDULING + ) { + // If the edition is scheduled, it must first be unscheduled. + try { + await realEdition.related.unschedule(); + realEdition.publishingStatus = PublishingStatus.UNSCHEDULING; + schedule = true; // Must reschedule after update. + + // Must fetch the edition again to get the update action + while (realEdition.publishingStatus === PublishingStatus.UNSCHEDULING) { + realEdition = await client.editions.get(realEdition.id as string); + } + } catch { + update = false; // Can't update, as we weren't able to unschedule. + } + } else if (isScheduled(realEdition)) { + update = false; // Can't update, as the edition was already published. + } + + if (update) { + await prepareEditionForSchedule(filteredEdition, event); + + // Update the existing edition based off of the file. + realEdition = await realEdition.related.update(filteredEdition); + + log.addComment(`Updated edition ${realEdition.name}.`); + log.addAction('EDITION-UPDATE', realEdition.id as string); + } else { + log.appendLine(`Skipped updating ${realEdition.name}, as it has already published.`); + } + } else { + update = false; + } + } + + let createdSnapshots = false; + + if (update) { + // Attempt to create/update slots. + createdSnapshots = await importSlots(edition.slots, mapping, hub, realEdition, argv, log); + } + + // If the original edition was scheduled, attempt to schedule the new one. + if (schedule && !isScheduled(realEdition) && isScheduled(edition)) { + if (update && edition.slots.length > 0) { + // Refetch the edition to make sure it's up to date before scheduling. + realEdition = await client.editions.get(realEdition.id as string); + + if (createdSnapshots) { + // We might need to move the edition into the future again, + // as creating snapshots may have taken more time than our scheduling grace period. + const lastStart = realEdition.start; + await prepareEditionForSchedule(realEdition, event, true); + + if (realEdition.start != lastStart) { + realEdition = await realEdition.related.update(realEdition); + } + } + } + await scheduleEdition(realEdition, log); + } + } +}; + +export const importEvents = async ( + events: EventWithEditions[], + mapping: ContentMapping, + client: DynamicContent, + hub: Hub, + argv: ImportEventBuilderOptions, + log: FileLog +): Promise => { + for (const event of events) { + let realEvent: Event | null = null; + // Attempt to get the existing event, if present. + + const eventId = mapping.getEvent(event.id); + + if (eventId == null) { + if (argv.originalIds && event.id) { + // Look up the original ID. + realEvent = await client.events.get(event.id); + } + } else { + // Look up the mapped ID. + realEvent = await client.events.get(eventId); + } + + const filteredEvent = new Event({ + name: event.name, + start: event.start, + end: event.end, + comment: event.comment, + brief: event.brief + }); + + if (realEvent == null) { + // Create a new event based off of the file. + realEvent = await hub.related.events.create(filteredEvent); + + log.addComment(`Created event ${realEvent.name}.`); + log.addAction('EVENT-CREATE', realEvent.id as string); + + mapping.registerEvent(event.id as string, realEvent.id as string); + } else if (shouldUpdateEvent(realEvent, event)) { + // Update the existing event based off of the file. + realEvent = await realEvent.related.update(filteredEvent); + + log.addComment(`Updated event ${realEvent.name}.`); + log.addAction('EVENT-UPDATE', realEvent.id as string); + } + + // Attempt to create editions + await importEditions(sortByEndDate(event.editions), mapping, client, hub, realEvent, argv, log); + } +}; + +export const trySaveMapping = async ( + mapFile: string | undefined, + mapping: ContentMapping, + log: FileLog +): Promise => { + if (mapFile != null) { + try { + await mapping.save(mapFile); + } catch (e) { + log.appendLine(`Failed to save the mapping. ${e.toString()}`); + } + } +}; + +export const handler = async (argv: Arguments): Promise => { + const { dir, logFile, acceptSnapshotLimits } = argv; + + if (!acceptSnapshotLimits) { + console.log( + 'Event import may result in a different state from the export due to snapshots of referenced content items being taken at the time of creation. Only use it if you fully understand its limitations. To use this command, pass the --acceptSnapshotLimits flag.' + ); + return; + } + + const client = dynamicContentClientFactory(argv); + const log = logFile.open(); + + const hub = await client.hubs.get(argv.hubId); + + const events = await loadJsonFromDirectory(dir, EventWithEditions); + + const importTitle = `hub-${hub.id}`; + const mapFile = argv.mapFile || getDefaultMappingPath(importTitle); + + const mapping = new ContentMapping(); + if (await mapping.load(mapFile)) { + log.appendLine(`Existing mapping loaded from '${mapFile}', changes will be saved back to it.`); + } else { + log.appendLine(`Creating new mapping file at '${mapFile}'.`); + } + + try { + await importEvents(sortByEndDate(Object.values(events)), mapping, client, hub, argv, log); + } catch (e) { + log.error('Failed to import events.', e); + } + + await trySaveMapping(mapFile, mapping, log); + + log.appendLine('Done.'); + + await log.close(); +}; diff --git a/src/commands/extension.ts b/src/commands/extension.ts index 974e3c5c..add1eaca 100644 --- a/src/commands/extension.ts +++ b/src/commands/extension.ts @@ -1,5 +1,7 @@ import { Argv } from 'yargs'; +import { readConfig } from '../cli'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import { configureCommandOptions } from './configure'; export const command = 'extension'; @@ -8,5 +10,7 @@ export const desc = 'Extension'; export const builder = (yargs: Argv): Argv => yargs .commandDir('extension', YargsCommandBuilderOptions) + .options(configureCommandOptions) + .config('config', readConfig) .demandCommand() .help(); diff --git a/src/commands/extension/__snapshots__/import.spec.ts.snap b/src/commands/extension/__snapshots__/import.spec.ts.snap index 07c2b8c8..74f34b54 100644 --- a/src/commands/extension/__snapshots__/import.spec.ts.snap +++ b/src/commands/extension/__snapshots__/import.spec.ts.snap @@ -18,8 +18,6 @@ exports[`extension import command doUpdate should throw an error when unable to exports[`extension import command doUpdate should throw an error when unable to update extension during update if a string error is returned by sdk 1`] = `"Error updating extension not-matched-name: undefined"`; -exports[`extension import command handler tests should throw an error when no content found in import directory 1`] = `"No extensions found in my-empty-dir"`; - exports[`extension import command validateNoDuplicateExtensionNames should throw and error when there are duplicate uris 1`] = ` "Extensions must have unique name values. Duplicate values found:- name: 'extension-name-1' in files: ['file-1', 'file-4'] diff --git a/src/commands/extension/delete.spec.ts b/src/commands/extension/delete.spec.ts new file mode 100644 index 00000000..b677c3a5 --- /dev/null +++ b/src/commands/extension/delete.spec.ts @@ -0,0 +1,148 @@ +import * as deleteModule from './delete'; +import Yargs from 'yargs/yargs'; +import { builder, coerceLog, LOG_FILENAME, command, handler } from './delete'; +import { getDefaultLogPath } from '../../common/log-helpers'; +import { Extension } from 'dc-management-sdk-js'; +import MockPage from '../../common/dc-management-sdk-js/mock-page'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { FileLog } from '../../common/file-log'; +import { filterExtensionsById } from '../../common/extension/extension-helpers'; +import * as questionHelpers from '../../common/question-helpers'; + +jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../common/log-helpers'); +jest.mock('../../common/question-helpers'); + +describe('delete extensions', () => { + it('should implement an export command', () => { + expect(command).toEqual('delete [id]'); + }); + + describe('builder tests', () => { + it('should configure yargs', () => { + const argv = Yargs(process.argv.slice(2)); + const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); + const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); + + builder(argv); + + expect(spyPositional).toHaveBeenCalledWith('id', { + describe: + 'The ID of the extension to be deleted. If id is not provided, this command will delete ALL extensions in the hub.', + type: 'string' + }); + expect(spyOption).toHaveBeenCalledWith('f', { + type: 'boolean', + boolean: true, + describe: 'If present, there will be no confirmation prompt before deleting the found extensions.' + }); + expect(spyOption).toHaveBeenCalledWith('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: coerceLog + }); + }); + }); + + describe('handler tests', () => { + const yargArgs = { + $0: 'test', + _: ['test'] + }; + + const config = { + clientId: 'client-id', + clientSecret: 'client-id', + hubId: 'hub-id' + }; + + const extensionsToDelete: Extension[] = [ + new Extension({ + id: 'extension-id-1', + name: 'extension-name-1', + label: 'extension-label-1', + status: 'ACTIVE' + }), + new Extension({ + id: 'extension-id-2', + name: 'extension-name-2', + label: 'extension-label-2', + status: 'ACTIVE' + }) + ]; + + let mockGetHub: jest.Mock; + let mockList: jest.Mock; + + const extensionIdsToDelete = (id: unknown) => (id ? (Array.isArray(id) ? id : [id]) : []); + + beforeEach((): void => { + const listResponse = new MockPage(Extension, extensionsToDelete); + mockList = jest.fn().mockResolvedValue(listResponse); + + mockGetHub = jest.fn().mockResolvedValue({ + related: { + extensions: { + list: mockList + } + } + }); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub + } + }); + + jest.spyOn(deleteModule, 'processExtensions').mockResolvedValue(); + }); + + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { + LOG_FILENAME(); + expect(getDefaultLogPath).toHaveBeenCalledWith('extension', 'delete', process.platform); + }); + + it('should delete all extensions in a hub', async (): Promise => { + const id: string[] | undefined = undefined; + const argv = { ...yargArgs, ...config, id, logFile: new FileLog() }; + + const filteredExtensionsToDelete = filterExtensionsById(extensionsToDelete, extensionIdsToDelete(id)); + + jest.spyOn(deleteModule, 'handler'); + + (questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(true); + + await handler(argv); + + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(mockList).toHaveBeenCalledTimes(1); + expect(mockList).toHaveBeenCalledWith({ size: 100 }); + + expect(deleteModule.processExtensions).toHaveBeenCalledWith(filteredExtensionsToDelete, argv.logFile); + }); + + it('should delete an extension by id', async (): Promise => { + const id: string[] | undefined = ['extension-id-2']; + const argv = { + ...yargArgs, + ...config, + id, + logFile: new FileLog() + }; + + const filteredExtensionsToDelete = filterExtensionsById(extensionsToDelete, extensionIdsToDelete(id)); + + jest.spyOn(deleteModule, 'handler'); + + (questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(true); + + await handler(argv); + + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(mockList).toHaveBeenCalledTimes(1); + + expect(deleteModule.processExtensions).toHaveBeenCalledWith(filteredExtensionsToDelete, argv.logFile); + }); + }); +}); diff --git a/src/commands/extension/delete.ts b/src/commands/extension/delete.ts new file mode 100644 index 00000000..7ce147eb --- /dev/null +++ b/src/commands/extension/delete.ts @@ -0,0 +1,113 @@ +import { Arguments, Argv } from 'yargs'; +import { FileLog } from '../../common/file-log'; +import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { ConfigurationParameters } from '../configure'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import paginator from '../../common/dc-management-sdk-js/paginator'; +import { nothingExportedExit as nothingToDeleteExit } from '../../services/export.service'; +import { Extension } from 'dc-management-sdk-js'; +import { asyncQuestion } from '../../common/question-helpers'; +import { progressBar } from '../../common/progress-bar/progress-bar'; +import { filterExtensionsById } from '../../common/extension/extension-helpers'; +import { DeleteExtensionBuilderOptions } from '../../interfaces/delete-extension-builder-options'; + +export const command = 'delete [id]'; + +export const desc = 'Delete Extensions'; + +export const LOG_FILENAME = (platform: string = process.platform): string => + getDefaultLogPath('extension', 'delete', platform); + +export const coerceLog = (logFile: string): FileLog => createLog(logFile, 'Extensions Delete Log'); + +export const builder = (yargs: Argv): void => { + yargs + .positional('id', { + type: 'string', + describe: + 'The ID of the extension to be deleted. If id is not provided, this command will delete ALL extensions in the hub.' + }) + .alias('f', 'force') + .option('f', { + type: 'boolean', + boolean: true, + describe: 'If present, there will be no confirmation prompt before deleting the found extensions.' + }) + .option('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: coerceLog + }); +}; + +export const processExtensions = async (extensionsToDelete: Extension[], log: FileLog): Promise => { + const failedExtensions: Extension[] = []; + + const progress = progressBar(extensionsToDelete.length, 0, { + title: `Deleting ${extensionsToDelete.length} extensions.` + }); + + for (const [i, extension] of extensionsToDelete.entries()) { + try { + await extension.related.delete(); + log.addComment(`Successfully deleted "${extension.label}"`); + progress.increment(); + } catch (e) { + failedExtensions.push(extension); + extensionsToDelete.splice(i, 1); + log.addComment(`Failed to delete ${extension.label}: ${e.toString()}`); + progress.increment(); + } + } + + progress.stop(); + + if (failedExtensions.length > 0) { + log.appendLine(`Failed to delete ${failedExtensions.length} extensions`); + } +}; + +export const handler = async ( + argv: Arguments +): Promise => { + const { id, logFile, force } = argv; + + const client = dynamicContentClientFactory(argv); + + const allExtensions = !id; + + const hub = await client.hubs.get(argv.hubId); + + const storedExtensions = await paginator(hub.related.extensions.list); + + const idArray: string[] = id ? (Array.isArray(id) ? id : [id]) : []; + const extensionsToDelete = filterExtensionsById(storedExtensions, idArray, true); + + const log = logFile.open(); + + if (extensionsToDelete.length === 0) { + nothingToDeleteExit(log, 'No extensions to delete from this hub, exiting.'); + return; + } + + if (!force) { + const baseMessage = 'This action cannot be undone. Are you sure you want to continue? (Y/n)\n'; + const yes = await asyncQuestion( + allExtensions + ? `Providing no ID/s will permanently delete ALL extensions! ${baseMessage}` + : `${extensionsToDelete.length} extensions will be permanently deleted. ${baseMessage}` + ); + if (!yes) { + return; + } + } + + log.addComment(`Deleting ${extensionsToDelete.length} extensions.`); + + await processExtensions(extensionsToDelete, log); + + log.appendLine(`Finished successfully deleting ${extensionsToDelete.length} extensions`); + + await log.close(); +}; diff --git a/src/commands/extension/export.spec.ts b/src/commands/extension/export.spec.ts index a1be36e4..678eee22 100644 --- a/src/commands/extension/export.spec.ts +++ b/src/commands/extension/export.spec.ts @@ -1,9 +1,9 @@ import * as exportModule from './export'; import * as directoryUtils from '../../common/import/directory-utils'; +import * as extensionHelpers from '../../common/extension/extension-helpers'; import { builder, command, - filterExtensionsById, getExtensionExports, getExportRecordForExtension, handler, @@ -22,6 +22,7 @@ import { FileLog } from '../../common/file-log'; import { streamTableOptions } from '../../common/table/table.consts'; import { createLog, getDefaultLogPath } from '../../common/log-helpers'; import { validateNoDuplicateExtensionNames } from './import'; +import { filterExtensionsById } from '../../common/extension/extension-helpers'; jest.mock('../../services/dynamic-content-client-factory'); jest.mock('./import'); @@ -650,7 +651,7 @@ describe('extension export command', (): void => { jest.spyOn(exportModule, 'processExtensions').mockResolvedValue(); }); - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('extension', 'export', process.platform); @@ -661,7 +662,7 @@ describe('extension export command', (): void => { const argv = { ...yargArgs, ...config, dir: 'my-dir', extensionId: extensionIdsToExport, logFile: new FileLog() }; const filteredExtensionsToExport = [...extensionsToExport]; - jest.spyOn(exportModule, 'filterExtensionsById').mockReturnValue(filteredExtensionsToExport); + jest.spyOn(extensionHelpers, 'filterExtensionsById').mockReturnValue(filteredExtensionsToExport); await handler(argv); @@ -670,7 +671,7 @@ describe('extension export command', (): void => { expect(mockList).toHaveBeenCalledWith({ size: 100 }); expect(loadJsonFromDirectory).toHaveBeenCalledWith(argv.dir, Extension); expect(validateNoDuplicateExtensionNames).toHaveBeenCalled(); - expect(exportModule.filterExtensionsById).toHaveBeenCalledWith(extensionsToExport, []); + expect(extensionHelpers.filterExtensionsById).toHaveBeenCalledWith(extensionsToExport, []); expect(exportModule.processExtensions).toHaveBeenCalledWith( argv.dir, [], @@ -685,7 +686,7 @@ describe('extension export command', (): void => { const argv = { ...yargArgs, ...config, dir: 'my-dir', id: idsToExport, logFile: new FileLog() }; const filteredExtensionsToExport = [extensionsToExport[1]]; - jest.spyOn(exportModule, 'filterExtensionsById').mockReturnValue(filteredExtensionsToExport); + jest.spyOn(extensionHelpers, 'filterExtensionsById').mockReturnValue(filteredExtensionsToExport); await handler(argv); @@ -693,7 +694,7 @@ describe('extension export command', (): void => { expect(mockList).toHaveBeenCalled(); expect(loadJsonFromDirectory).toHaveBeenCalledWith(argv.dir, Extension); expect(validateNoDuplicateExtensionNames).toHaveBeenCalled(); - expect(exportModule.filterExtensionsById).toHaveBeenCalledWith(extensionsToExport, idsToExport); + expect(extensionHelpers.filterExtensionsById).toHaveBeenCalledWith(extensionsToExport, idsToExport); expect(exportModule.processExtensions).toHaveBeenCalledWith( argv.dir, [], diff --git a/src/commands/extension/export.ts b/src/commands/extension/export.ts index a654d50f..88d1fe4a 100644 --- a/src/commands/extension/export.ts +++ b/src/commands/extension/export.ts @@ -20,6 +20,7 @@ import { ensureDirectoryExists } from '../../common/import/directory-utils'; import { FileLog } from '../../common/file-log'; import { createLog, getDefaultLogPath } from '../../common/log-helpers'; import { validateNoDuplicateExtensionNames } from './import'; +import { filterExtensionsById } from '../../common/extension/extension-helpers'; export const command = 'export '; @@ -71,25 +72,6 @@ interface ExportRecord { readonly extension: Extension; } -export const filterExtensionsById = (listToFilter: Extension[], extensionUriList: string[]): Extension[] => { - if (extensionUriList.length === 0) { - return listToFilter; - } - - const unmatchedExtensionUriList: string[] = extensionUriList.filter( - id => !listToFilter.some(extension => extension.id === id) - ); - if (unmatchedExtensionUriList.length > 0) { - throw new Error( - `The following extension URI(s) could not be found: [${unmatchedExtensionUriList - .map(u => `'${u}'`) - .join(', ')}].\nNothing was exported, exiting.` - ); - } - - return listToFilter.filter(extension => extensionUriList.some(id => extension.id === id)); -}; - export const getExportRecordForExtension = ( extension: Extension, outputDir: string, diff --git a/src/commands/extension/import.spec.ts b/src/commands/extension/import.spec.ts index e9d4db0c..f1368ffd 100644 --- a/src/commands/extension/import.spec.ts +++ b/src/commands/extension/import.spec.ts @@ -326,7 +326,7 @@ describe('extension import command', (): void => { }); }); - describe('validateNoDuplicateExtensionNames', function() { + describe('validateNoDuplicateExtensionNames', function () { it('should not throw an error when there are no duplicates', () => { const extensionsToProcess = { 'file-1': new Extension({ @@ -360,7 +360,7 @@ describe('extension import command', (): void => { }); }); - describe('filterExtensionsById', function() { + describe('filterExtensionsById', function () { it('should delete extensions without a matching id', () => { const extensionsToProcess = { 'file-1': new Extension({ @@ -427,7 +427,7 @@ describe('extension import command', (): void => { }); }); - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('extension', 'import', process.platform); @@ -499,12 +499,22 @@ describe('extension import command', (): void => { ); }); - it('should throw an error when no content found in import directory', async (): Promise => { + it('should exit early when no content found in import directory', async (): Promise => { const argv = { ...yargArgs, ...config, dir: 'my-empty-dir', logFile: new FileLog() }; (loadJsonFromDirectory as jest.Mock).mockReturnValue([]); - await expect(handler(argv)).rejects.toThrowErrorMatchingSnapshot(); + await handler(argv); + + expect(argv.logFile.closed).toBeTruthy(); + expect(argv.logFile.accessGroup).toMatchInlineSnapshot(` +Array [ + Object { + "comment": true, + "data": "No extensions found in my-empty-dir", + }, +] +`); }); }); }); diff --git a/src/commands/extension/import.ts b/src/commands/extension/import.ts index 77eaac13..2639b6f0 100644 --- a/src/commands/extension/import.ts +++ b/src/commands/extension/import.ts @@ -157,7 +157,9 @@ export const handler = async ( const log = logFile.open(); const extensions = loadJsonFromDirectory(dir, Extension); if (Object.keys(extensions).length === 0) { - throw new Error(`No extensions found in ${dir}`); + log.appendLine(`No extensions found in ${dir}`); + await log.close(); + return; } validateNoDuplicateExtensionNames(extensions); diff --git a/src/commands/hub.spec.ts b/src/commands/hub.spec.ts new file mode 100644 index 00000000..6e23ade5 --- /dev/null +++ b/src/commands/hub.spec.ts @@ -0,0 +1,26 @@ +import Yargs from 'yargs/yargs'; +import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import { builder, hubBuilder } from './hub'; + +describe('hub manager', function () { + it('should build yargs', async () => { + const argv = Yargs(process.argv.slice(2)); + const spyCommandDir = jest.spyOn(argv, 'commandDir').mockReturnValue(argv); + const spyCommand = jest.spyOn(argv, 'command'); + builder(argv); + expect(spyCommandDir).toHaveBeenCalledWith('hub', YargsCommandBuilderOptions); + expect(spyCommand).toHaveBeenCalledTimes(4); + }); + + it('should build hub use args', async () => { + const argv = Yargs(process.argv.slice(2)); + const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); + hubBuilder(argv); + expect(spyPositional).toHaveBeenCalledWith('hub', { + describe: 'hub name', + type: 'string', + demandOption: false, + default: '' + }); + }); +}); diff --git a/src/commands/hub.ts b/src/commands/hub.ts index 3a0f8272..b0ed1a7a 100644 --- a/src/commands/hub.ts +++ b/src/commands/hub.ts @@ -1,12 +1,32 @@ import { Argv } from 'yargs'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import HubManager from '../common/hub-manager'; +import { CommandOptions } from '../interfaces/command-options.interface'; export const command = 'hub'; - export const desc = 'Hub'; +const commandOptions: CommandOptions = { + clientId: { type: 'string' }, + clientSecret: { type: 'string' }, + hubId: { type: 'string' } +}; + +export const hubBuilder = (yargs: Argv): Argv => + yargs.positional('hub', { + describe: 'hub name', + type: 'string', + demandOption: false, + + default: '' + }); + export const builder = (yargs: Argv): Argv => yargs .commandDir('hub', YargsCommandBuilderOptions) .demandCommand() + .command('add', 'Add hub', commandOptions, HubManager.addHub) + .command('list', 'List hubs', HubManager.listHubs) + .command('ls', 'List hubs', HubManager.listHubs) + .command('use [hub]', 'Use hub', hubBuilder, HubManager.useHub) .help(); diff --git a/src/commands/hub/clean.spec.ts b/src/commands/hub/clean.spec.ts index 18053264..733ab08a 100644 --- a/src/commands/hub/clean.spec.ts +++ b/src/commands/hub/clean.spec.ts @@ -79,18 +79,18 @@ describe('hub clean command', () => { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('clean'); }); - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('hub', 'clean', process.platform); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); @@ -118,10 +118,16 @@ describe('hub clean command', () => { describe: 'Start at a specific step. Steps after the one you specify will also run.', choices: steps.map(step => step.getId()) }); + + expect(spyOption).toHaveBeenCalledWith('ignoreSchemaValidation', { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during clean' + }); }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'] @@ -150,7 +156,8 @@ describe('hub clean command', () => { ...config, logFile: createLog(`temp_${process.env.JEST_WORKER_ID}/clean/steps/all.log`), - force: true + force: true, + ignoreSchemaValidation: true }; await handler(argv); diff --git a/src/commands/hub/clean.ts b/src/commands/hub/clean.ts index 5d67e0d6..1e0d35c8 100644 --- a/src/commands/hub/clean.ts +++ b/src/commands/hub/clean.ts @@ -1,11 +1,12 @@ import { createLog, getDefaultLogPath } from '../../common/log-helpers'; import { Argv, Arguments } from 'yargs'; -import { ConfigurationParameters } from '../configure'; +import { ConfigurationParameters, configureCommandOptions } from '../configure'; import { CleanHubBuilderOptions } from '../../interfaces/clean-hub-builder-options'; import { SchemaCleanStep } from './steps/schema-clean-step'; import { TypeCleanStep } from './steps/type-clean-step'; import { ContentCleanStep } from './steps/content-clean-step'; +import { readConfig } from '../../cli'; export const command = 'clean'; @@ -19,6 +20,8 @@ export const steps = [new ContentCleanStep(), new TypeCleanStep(), new SchemaCle export const builder = (yargs: Argv): void => { yargs + .options(configureCommandOptions) + .config('config', readConfig) .alias('f', 'force') .option('f', { type: 'boolean', @@ -38,6 +41,12 @@ export const builder = (yargs: Argv): void => { type: 'string', describe: 'Start at a specific step. Steps after the one you specify will also run.', choices: steps.map(step => step.getId()) + }) + + .option('ignoreSchemaValidation', { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during clean' }); }; @@ -49,7 +58,10 @@ export const handler = async (argv: Arguments step.getId() === argv.step)); + const stepIndex = Math.max( + 0, + steps.findIndex(step => step.getId() === argv.step) + ); for (let i = stepIndex; i < steps.length; i++) { const step = steps[i]; diff --git a/src/commands/hub/clone.spec.ts b/src/commands/hub/clone.spec.ts index 6a0e69e8..04236665 100644 --- a/src/commands/hub/clone.spec.ts +++ b/src/commands/hub/clone.spec.ts @@ -9,6 +9,7 @@ import * as schema from './steps/schema-clone-step'; import * as type from './steps/type-clone-step'; import * as extension from './steps/extension-clone-step'; import * as index from './steps/index-clone-step'; +import * as event from './steps/event-clone-step'; import rmdir from 'rimraf'; import { CloneHubBuilderOptions } from '../../interfaces/clone-hub-builder-options'; @@ -22,7 +23,7 @@ jest.mock('readline'); jest.mock('../../services/dynamic-content-client-factory'); -let success = [true, true, true, true, true, true]; +let success = [true, true, true, true, true, true, true]; // eslint-disable-next-line @typescript-eslint/no-explicit-any function succeedOrFail(mock: any, succeed: () => boolean): jest.Mock { @@ -31,12 +32,13 @@ function succeedOrFail(mock: any, succeed: () => boolean): jest.Mock { } // eslint-disable-next-line @typescript-eslint/no-explicit-any -function mockStep(name: string, id: string, success: () => boolean): any { +function mockStep(name: string, id: string, success: () => boolean, isLimited?: boolean): any { return jest.fn().mockImplementation(() => ({ run: succeedOrFail(jest.fn(), success), revert: succeedOrFail(jest.fn(), success), getName: jest.fn().mockReturnValue(name), - getId: jest.fn().mockReturnValue(id) + getId: jest.fn().mockReturnValue(id), + isLimited })); } @@ -64,6 +66,10 @@ jest.mock('./steps/content-clone-step', () => ({ ContentCloneStep: mockStep('Clone Content', 'content', () => success[5]) })); +jest.mock('./steps/event-clone-step', () => ({ + EventCloneStep: mockStep('Clone Event', 'event', () => success[6], true) +})); + jest.mock('../../common/log-helpers', () => ({ ...jest.requireActual('../../common/log-helpers'), getDefaultLogPath: jest.fn() @@ -82,7 +88,8 @@ function getMocks(): jest.Mock[] { schema.SchemaCloneStep as jest.Mock, type.TypeCloneStep as jest.Mock, index.IndexCloneStep as jest.Mock, - content.ContentCloneStep as jest.Mock + content.ContentCloneStep as jest.Mock, + event.EventCloneStep as jest.Mock ]; } @@ -103,25 +110,25 @@ describe('hub clone command', () => { jest.restoreAllMocks(); }); - it('should command should defined', function() { + it('should command should defined', function () { expect(command).toEqual('clone '); }); - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('hub', 'clone', process.platform); }); - it('should generate a default mapping path containing the given name', function() { + it('should generate a default mapping path containing the given name', function () { expect(getDefaultMappingPath('hub-1').indexOf('hub-1')).not.toEqual(-1); }); - describe('builder tests', function() { - it('should configure yargs', function() { + describe('builder tests', function () { + it('should configure yargs', function () { const argv = Yargs(process.argv.slice(2)); const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); - const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); + const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); builder(argv); @@ -131,102 +138,119 @@ describe('hub clone command', () => { type: 'string' }); - expect(spyOption).toHaveBeenCalledWith('dstHubId', { + const commandOptions = spyOptions.mock.calls[1][0]; + + expect(commandOptions.acceptSnapshotLimits).toEqual({ + type: 'boolean', + boolean: true, + describe: + 'Must be passed to use the event clone step. Only use this argument if you fully understand its limitations.' + }); + + expect(commandOptions.dstHubId).toEqual({ type: 'string', describe: 'Destination hub ID. If not specified, it will be the same as the source.' }); - expect(spyOption).toHaveBeenCalledWith('dstClientId', { + expect(commandOptions.dstClientId).toEqual({ type: 'string', describe: "Destination account's client ID. If not specified, it will be the same as the source." }); - expect(spyOption).toHaveBeenCalledWith('dstSecret', { + expect(commandOptions.dstSecret).toEqual({ type: 'string', describe: "Destination account's secret. Must be used alongside dstClientId." }); - expect(spyOption).toHaveBeenCalledWith('mapFile', { + expect(commandOptions.mapFile).toEqual({ type: 'string', describe: 'Mapping file to use when updating content that already exists. Updated with any new mappings that are generated. If not present, will be created.' }); - expect(spyOption).toHaveBeenCalledWith('f', { + expect(commandOptions.force).toEqual({ type: 'boolean', boolean: true, describe: - 'Overwrite content, create and assign content types, and ignore content with missing types/references without asking.' + 'Overwrite content, create and assign content types, and ignore content with missing types/references without asking.', + alias: 'f' }); - expect(spyOption).toHaveBeenCalledWith('v', { + expect(commandOptions.validate).toEqual({ type: 'boolean', boolean: true, - describe: 'Only recreate folder structure - content is validated but not imported.' + describe: 'Only recreate folder structure - content is validated but not imported.', + alias: 'v' }); - expect(spyOption).toHaveBeenCalledWith('skipIncomplete', { + expect(commandOptions.skipIncomplete).toEqual({ type: 'boolean', boolean: true, describe: 'Skip any content item that has one or more missing dependancy.' }); - expect(spyOption).toHaveBeenCalledWith('lastPublish', { + expect(commandOptions.lastPublish).toEqual({ type: 'boolean', boolean: true, describe: 'When available, export the last published version of a content item rather than its newest version.' }); - expect(spyOption).toHaveBeenCalledWith('publish', { + expect(commandOptions.publish).toEqual({ type: 'boolean', boolean: true, describe: 'Publish any content items that either made a new version on import, or were published more recently in the JSON.' }); - expect(spyOption).toHaveBeenCalledWith('republish', { + expect(commandOptions.republish).toEqual({ type: 'boolean', boolean: true, describe: 'Republish content items regardless of whether the import changed them or not. (--publish not required)' }); - expect(spyOption).toHaveBeenCalledWith('excludeKeys', { + expect(commandOptions.excludeKeys).toEqual({ type: 'boolean', boolean: true, describe: 'Exclude delivery keys when importing content items.' }); - expect(spyOption).toHaveBeenCalledWith('media', { + expect(commandOptions.media).toEqual({ type: 'boolean', boolean: true, describe: "Detect and rewrite media links to match assets in the target account's DAM. Your client must have DAM permissions configured." }); - expect(spyOption).toHaveBeenCalledWith('revertLog', { + expect(commandOptions.revertLog).toEqual({ type: 'string', describe: 'Revert a previous clone using a given revert log and given directory. Reverts steps in reverse order, starting at the specified one.', coerce: openRevertLog }); - expect(spyOption).toHaveBeenCalledWith('logFile', { + expect(commandOptions.logFile).toEqual({ type: 'string', default: LOG_FILENAME, describe: 'Path to a log file to write to.', coerce: createLog }); - expect(spyOption).toHaveBeenCalledWith('step', { + expect(commandOptions.step).toEqual({ type: 'string', describe: 'Start at a specific step. Steps after the one you specify will also run.', choices: steps.map(step => step.getId()) }); + + expect(commandOptions.ignoreSchemaValidation).toEqual({ + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during clone' + }); }); }); - describe('handler tests', function() { + describe('handler tests', function () { const yargArgs = { $0: 'test', _: ['test'] @@ -236,6 +260,7 @@ describe('hub clone command', () => { clientId: 'client-id', clientSecret: 'client-id', hubId: 'hub-id', + acceptSnapshotLimits: true, revertLog: Promise.resolve(undefined) }; @@ -270,7 +295,7 @@ describe('hub clone command', () => { it('should call all steps in order with given parameters', async () => { clearMocks(); - success = [true, true, true, true, true, true]; + success = [true, true, true, true, true, true, true]; const argv: Arguments = { ...yargArgs, @@ -286,7 +311,8 @@ describe('hub clone command', () => { force: false, validate: false, skipIncomplete: false, - media: true + media: true, + ignoreSchemaValidation: true }; const stepConfig = makeState(argv); @@ -308,9 +334,9 @@ describe('hub clone command', () => { }); it('should handle false returns from each of the steps by stopping the process', async () => { - for (let i = 0; i < 6; i++) { + for (let i = 0; i < 7; i++) { clearMocks(); - success = [i != 0, i != 1, i != 2, i != 3, i != 4, i != 5]; + success = [i != 0, i != 1, i != 2, i != 3, i != 4, i != 5, i != 6]; const argv: Arguments = { ...yargArgs, @@ -352,9 +378,9 @@ describe('hub clone command', () => { }); it('should start from the step given as a parameter', async () => { - for (let i = 0; i < 6; i++) { + for (let i = 0; i < 7; i++) { clearMocks(); - success = [true, true, true, true, true, true]; + success = [true, true, true, true, true, true, true]; const argv: Arguments = { ...yargArgs, @@ -397,6 +423,50 @@ describe('hub clone command', () => { } }); + it('should exclude acceptSnapshotLimits steps if acceptSnapshotLimits is false', async () => { + clearMocks(); + success = [true, true, true, true, true, true, true]; + + const argv: Arguments = { + ...yargArgs, + ...config, + acceptSnapshotLimits: false, + + dir: `temp_${process.env.JEST_WORKER_ID}/clone/steps`, + + dstHubId: 'hub2-id', + dstClientId: 'acc2-id', + dstSecret: 'acc2-secret', + logFile: createLog(`temp_${process.env.JEST_WORKER_ID}/clone/steps/all.log`), + + force: false, + validate: false, + skipIncomplete: false, + media: true + }; + + const stepConfig = makeState(argv); + + await handler(argv); + + stepConfig.argv.mapFile = expect.any(String); + + const mocks = getMocks(); + + mocks.forEach(mock => { + const instance = mock.mock.results[0].value; + + if (instance.isLimited) { + expect(instance.run).not.toHaveBeenCalled(); + } else { + expect(instance.run).toHaveBeenCalledWith(stepConfig); + } + }); + + const loadLog = new FileLog(); + await loadLog.loadFromFile(`temp_${process.env.JEST_WORKER_ID}/clone/steps/all.log`); + }); + it('should only have one of each type of step', () => { const stepsSoFar = new Set(); @@ -410,7 +480,7 @@ describe('hub clone command', () => { }); }); - describe('revert tests', function() { + describe('revert tests', function () { const yargArgs = { $0: 'test', _: ['test'] @@ -419,7 +489,8 @@ describe('hub clone command', () => { const config = { clientId: 'client-id', clientSecret: 'client-id', - hubId: 'hub-id' + hubId: 'hub-id', + acceptSnapshotLimits: true }; beforeAll(async () => { @@ -464,7 +535,7 @@ describe('hub clone command', () => { it('should revert all steps in order with given parameters', async () => { clearMocks(); - success = [true, true, true, true, true, true]; + success = [true, true, true, true, true, true, true]; await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/clone-revert/`); await prepareFakeLog(`temp_${process.env.JEST_WORKER_ID}/clone-revert/steps.log`); @@ -504,9 +575,9 @@ describe('hub clone command', () => { }); it('should handle exceptions from each of the revert steps by stopping the process', async () => { - for (let i = 0; i < 6; i++) { + for (let i = 0; i < 7; i++) { clearMocks(); - success = [i != 0, i != 1, i != 2, i != 3, i != 4, i != 5]; + success = [i != 0, i != 1, i != 2, i != 3, i != 4, i != 5, i != 6]; await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/clone-revert/`); await prepareFakeLog(`temp_${process.env.JEST_WORKER_ID}/clone-revert/fail.log`); @@ -553,7 +624,7 @@ describe('hub clone command', () => { it('should exit early if revert log cannot be read', async () => { clearMocks(); - success = [true, true, true, true, true, true]; + success = [true, true, true, true, true, true, true]; await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/clone-revert/`); const argv: Arguments = { @@ -590,9 +661,9 @@ describe('hub clone command', () => { }); it('should start reverting from the step given as a parameter (steps in decreasing order)', async () => { - for (let i = 0; i < 6; i++) { + for (let i = 0; i < 7; i++) { clearMocks(); - success = [true, true, true, true, true, true]; + success = [true, true, true, true, true, true, true]; await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/clone-revert/`); await prepareFakeLog(`temp_${process.env.JEST_WORKER_ID}/clone-revert/step.log`); @@ -638,5 +709,51 @@ describe('hub clone command', () => { await loadLog.loadFromFile(`temp_${process.env.JEST_WORKER_ID}/clone-revert/step/step` + i + '.log'); } }); + + it('should exclude acceptSnapshotLimits steps if acceptSnapshotLimits is false', async () => { + clearMocks(); + success = [true, true, true, true, true, true, true]; + await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/clone-revert/`); + await prepareFakeLog(`temp_${process.env.JEST_WORKER_ID}/clone-revert/steps.log`); + + const argv: Arguments = { + ...yargArgs, + ...config, + acceptSnapshotLimits: false, + + dir: `temp_${process.env.JEST_WORKER_ID}/clone-revert/steps`, + + dstHubId: 'hub2-id', + dstClientId: 'acc2-id', + dstSecret: 'acc2-secret', + logFile: createLog(`temp_${process.env.JEST_WORKER_ID}/clone-revert/steps/all.log`), + revertLog: openRevertLog(`temp_${process.env.JEST_WORKER_ID}/clone-revert/steps.log`), + + mapFile: `temp_${process.env.JEST_WORKER_ID}/clone-revert/steps/all.json`, + force: false, + validate: false, + skipIncomplete: false, + media: true + }; + + const stepConfig = makeState(argv); + + await handler(argv); + + const mocks = getMocks(); + + mocks.forEach(mock => { + const instance = mock.mock.results[0].value; + + if (instance.isLimited) { + expect(instance.revert).not.toHaveBeenCalled(); + } else { + expect(instance.revert).toHaveBeenCalledWith(stepConfig); + } + }); + + const loadLog = new FileLog(); + await loadLog.loadFromFile(`temp_${process.env.JEST_WORKER_ID}/clone-revert/steps/all.log`); + }); }); }); diff --git a/src/commands/hub/clone.ts b/src/commands/hub/clone.ts index 23b88375..245d638c 100644 --- a/src/commands/hub/clone.ts +++ b/src/commands/hub/clone.ts @@ -1,7 +1,8 @@ import { createLog, getDefaultLogPath, openRevertLog } from '../../common/log-helpers'; import { Argv, Arguments } from 'yargs'; import { join } from 'path'; -import { ConfigurationParameters } from '../configure'; +import { ConfigurationParameters, configureCommandOptions } from '../configure'; +import { readConfig } from '../../cli'; import { ensureDirectoryExists } from '../../common/import/directory-utils'; import { CloneHubBuilderOptions } from '../../interfaces/clone-hub-builder-options'; @@ -14,6 +15,8 @@ import { IndexCloneStep } from './steps/index-clone-step'; import { CloneHubState } from './model/clone-hub-state'; import { LogErrorLevel } from '../../common/archive/archive-log'; import { ExtensionCloneStep } from './steps/extension-clone-step'; +import { EventCloneStep } from './steps/event-clone-step'; +import { CloneHubStep } from './model/clone-hub-step'; export function getDefaultMappingPath(name: string, platform: string = process.platform): string { return join( @@ -41,115 +44,117 @@ export const desc = export const LOG_FILENAME = (platform: string = process.platform): string => getDefaultLogPath('hub', 'clone', platform); -export const steps = [ +export const steps: CloneHubStep[] = [ new SettingsCloneStep(), new ExtensionCloneStep(), new SchemaCloneStep(), new TypeCloneStep(), new IndexCloneStep(), - new ContentCloneStep() + new ContentCloneStep(), + new EventCloneStep() ]; export const builder = (yargs: Argv): void => { yargs + .options(configureCommandOptions) + .config('config', readConfig) .positional('dir', { describe: 'Directory to export content to, then import from. This must be set to the previous directory for a revert.', type: 'string' }) - - .option('dstHubId', { - type: 'string', - describe: 'Destination hub ID. If not specified, it will be the same as the source.' - }) - - .option('dstClientId', { - type: 'string', - describe: "Destination account's client ID. If not specified, it will be the same as the source." - }) - - .option('dstSecret', { - type: 'string', - describe: "Destination account's secret. Must be used alongside dstClientId." - }) - - .option('mapFile', { - type: 'string', - describe: - 'Mapping file to use when updating content that already exists. Updated with any new mappings that are generated. If not present, will be created.' - }) - - .alias('f', 'force') - .option('f', { - type: 'boolean', - boolean: true, - describe: - 'Overwrite content, create and assign content types, and ignore content with missing types/references without asking.' - }) - - .alias('v', 'validate') - .option('v', { - type: 'boolean', - boolean: true, - describe: 'Only recreate folder structure - content is validated but not imported.' - }) - - .option('skipIncomplete', { - type: 'boolean', - boolean: true, - describe: 'Skip any content item that has one or more missing dependancy.' - }) - - .option('lastPublish', { - type: 'boolean', - boolean: true, - describe: 'When available, export the last published version of a content item rather than its newest version.' - }) - - .option('publish', { - type: 'boolean', - boolean: true, - describe: - 'Publish any content items that either made a new version on import, or were published more recently in the JSON.' - }) - - .option('republish', { - type: 'boolean', - boolean: true, - describe: 'Republish content items regardless of whether the import changed them or not. (--publish not required)' - }) - - .option('excludeKeys', { - type: 'boolean', - boolean: true, - describe: 'Exclude delivery keys when importing content items.' - }) - - .option('media', { - type: 'boolean', - boolean: true, - describe: - "Detect and rewrite media links to match assets in the target account's DAM. Your client must have DAM permissions configured." - }) - - .option('revertLog', { - type: 'string', - describe: - 'Revert a previous clone using a given revert log and given directory. Reverts steps in reverse order, starting at the specified one.', - coerce: openRevertLog - }) - - .option('step', { - type: 'string', - describe: 'Start at a specific step. Steps after the one you specify will also run.', - choices: steps.map(step => step.getId()) - }) - - .option('logFile', { - type: 'string', - default: LOG_FILENAME, - describe: 'Path to a log file to write to.', - coerce: createLog + .options({ + acceptSnapshotLimits: { + type: 'boolean', + boolean: true, + describe: + 'Must be passed to use the event clone step. Only use this argument if you fully understand its limitations.' + }, + dstHubId: { + type: 'string', + describe: 'Destination hub ID. If not specified, it will be the same as the source.' + }, + dstClientId: { + type: 'string', + describe: "Destination account's client ID. If not specified, it will be the same as the source." + }, + dstSecret: { + type: 'string', + describe: "Destination account's secret. Must be used alongside dstClientId." + }, + mapFile: { + type: 'string', + describe: + 'Mapping file to use when updating content that already exists. Updated with any new mappings that are generated. If not present, will be created.' + }, + force: { + type: 'boolean', + boolean: true, + describe: + 'Overwrite content, create and assign content types, and ignore content with missing types/references without asking.', + alias: 'f' + }, + validate: { + type: 'boolean', + boolean: true, + describe: 'Only recreate folder structure - content is validated but not imported.', + alias: 'v' + }, + skipIncomplete: { + type: 'boolean', + boolean: true, + describe: 'Skip any content item that has one or more missing dependancy.' + }, + lastPublish: { + type: 'boolean', + boolean: true, + describe: 'When available, export the last published version of a content item rather than its newest version.' + }, + publish: { + type: 'boolean', + boolean: true, + describe: + 'Publish any content items that either made a new version on import, or were published more recently in the JSON.' + }, + republish: { + type: 'boolean', + boolean: true, + describe: + 'Republish content items regardless of whether the import changed them or not. (--publish not required)' + }, + excludeKeys: { + type: 'boolean', + boolean: true, + describe: 'Exclude delivery keys when importing content items.' + }, + media: { + type: 'boolean', + boolean: true, + describe: + "Detect and rewrite media links to match assets in the target account's DAM. Your client must have DAM permissions configured." + }, + revertLog: { + type: 'string', + describe: + 'Revert a previous clone using a given revert log and given directory. Reverts steps in reverse order, starting at the specified one.', + coerce: openRevertLog + }, + step: { + type: 'string', + describe: 'Start at a specific step. Steps after the one you specify will also run.', + choices: steps.map(step => step.getId()) + }, + logFile: { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: createLog + }, + ignoreSchemaValidation: { + type: 'boolean', + boolean: false, + describe: 'Ignore content item schema validation during clone' + } }); }; @@ -161,11 +166,12 @@ export const handler = async (argv: Arguments step.getId() === argv.step)); + const stepIndex = Math.max( + 0, + steps.findIndex(step => step.getId() === argv.step) + ); if (revertLog) { if (revertLog.errorLevel === LogErrorLevel.INVALID) { @@ -211,6 +222,10 @@ export const handler = async (argv: Arguments; revert(state: CloneHubState): Promise; } diff --git a/src/commands/hub/steps/content-clone-step.spec.ts b/src/commands/hub/steps/content-clone-step.spec.ts index 7969d821..9c0fe1a8 100644 --- a/src/commands/hub/steps/content-clone-step.spec.ts +++ b/src/commands/hub/steps/content-clone-step.spec.ts @@ -44,6 +44,7 @@ describe('content clone step', () => { ...yargArgs, ...config, logFile: new FileLog(), + acceptSnapshotLimits: false, dir: directory, diff --git a/src/commands/hub/steps/event-clone-step.spec.ts b/src/commands/hub/steps/event-clone-step.spec.ts new file mode 100644 index 00000000..f79ab041 --- /dev/null +++ b/src/commands/hub/steps/event-clone-step.spec.ts @@ -0,0 +1,277 @@ +import { Arguments } from 'yargs'; +import { Event } from 'dc-management-sdk-js'; +import { FileLog } from '../../../common/file-log'; +import { ensureDirectoryExists } from '../../../common/import/directory-utils'; +import { CloneHubBuilderOptions } from '../../../interfaces/clone-hub-builder-options'; +import dynamicContentClientFactory from '../../../services/dynamic-content-client-factory'; +import { ConfigurationParameters } from '../../configure'; +import { CloneHubState } from '../model/clone-hub-state'; +import { join } from 'path'; +import rmdir from 'rimraf'; + +import * as eventImport from '../../event/import'; +import * as eventExport from '../../event/export'; + +import { EventCloneStep } from './event-clone-step'; +import { CloneHubStepId } from '../model/clone-hub-step'; + +jest.mock('../../../services/dynamic-content-client-factory'); +jest.mock('../../event/import'); +jest.mock('../../event/export'); + +function rimraf(dir: string): Promise { + return new Promise((resolve): void => { + rmdir(dir, resolve); + }); +} + +describe('event clone step', () => { + let mockGetEvent: jest.Mock; + let mockArchiveEvent: jest.Mock; + let mockFailArchiveEvent: jest.Mock; + + const yargArgs = { + $0: 'test', + _: ['test'] + }; + + const config = { + clientId: 'client-id', + clientSecret: 'client-id', + hubId: 'hub-id' + }; + + function reset(): void { + jest.resetAllMocks(); + + mockGetEvent = jest.fn(); + mockArchiveEvent = jest.fn(); + mockFailArchiveEvent = jest.fn().mockRejectedValue(new Error('Already archived')); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + events: { + get: mockGetEvent + } + }); + + const event = new Event({ + id: 'event1' + }); + + event.related.archive = mockArchiveEvent; + + const event3 = new Event({ + id: 'event3' + }); + + event3.related.archive = mockFailArchiveEvent; + + mockGetEvent.mockImplementation(id => { + return Promise.resolve(id === 'event3' ? event3 : event); + }); + mockArchiveEvent.mockResolvedValue(event); + } + + beforeEach(async () => { + reset(); + }); + + beforeAll(async () => { + await rimraf(`temp_${process.env.JEST_WORKER_ID}/clone-event/`); + }); + + afterAll(async () => { + await rimraf(`temp_${process.env.JEST_WORKER_ID}/clone-event/`); + }); + + function generateState(directory: string, logName: string): CloneHubState { + const argv: Arguments = { + ...yargArgs, + ...config, + logFile: new FileLog(), + acceptSnapshotLimits: true, + mapFile: 'mapping.json', + + dir: directory, + + dstHubId: 'hub2-id', + dstClientId: 'acc2-id', + dstSecret: 'acc2-secret', + revertLog: Promise.resolve(new FileLog()) + }; + + return { + argv: argv, + from: { + clientId: argv.clientId as string, + clientSecret: argv.clientSecret as string, + hubId: argv.hubId as string, + ...yargArgs + }, + to: { + clientId: argv.dstClientId as string, + clientSecret: argv.dstSecret as string, + hubId: argv.dstHubId as string, + ...yargArgs + }, + path: directory, + logFile: new FileLog(join(directory, logName + '.log')) + }; + } + + it('should have the id "event"', () => { + const step = new EventCloneStep(); + expect(step.getId()).toEqual(CloneHubStepId.Event); + }); + + it('should have the name "Clone Content Events"', () => { + const step = new EventCloneStep(); + expect(step.getName()).toEqual('Clone Events'); + }); + + it('should call export on the source, backup and import to the destination', async () => { + const state = generateState(`temp_${process.env.JEST_WORKER_ID}/clone-event/run/`, 'run'); + + (eventImport.handler as jest.Mock).mockResolvedValue(true); + (eventExport.handler as jest.Mock).mockResolvedValue(true); + + const step = new EventCloneStep(); + const result = await step.run(state); + // Backup + expect(eventExport.handler).toHaveBeenNthCalledWith(1, { + dir: join(state.path, 'oldEvent'), + force: true, + snapshots: false, + logFile: state.logFile, + ...state.to + }); + + // Export + expect(eventExport.handler).toHaveBeenNthCalledWith(2, { + dir: join(state.path, 'event'), + force: true, + snapshots: false, + logFile: state.logFile, + ...state.from + }); + + expect(eventImport.handler).toHaveBeenCalledWith({ + dir: join(state.path, 'event'), + originalIds: false, + schedule: true, + acceptSnapshotLimits: true, + mapFile: 'mapping.json', + catchup: false, + logFile: state.logFile, + ...state.to + }); + + expect(result).toBeTruthy(); + }); + + it('should fail the step when the export, backup or import fails', async () => { + const state = generateState(`temp_${process.env.JEST_WORKER_ID}/clone-event/run/`, 'run'); + + (eventExport.handler as jest.Mock).mockRejectedValue(false); + + const step = new EventCloneStep(); + const backupFail = await step.run(state); + + expect(backupFail).toBeFalsy(); + expect(eventExport.handler).toHaveBeenCalledTimes(1); + expect(eventImport.handler).not.toHaveBeenCalled(); + + reset(); + + (eventExport.handler as jest.Mock).mockResolvedValueOnce(true); + (eventExport.handler as jest.Mock).mockRejectedValueOnce(false); + + const exportFail = await step.run(state); + + expect(exportFail).toBeFalsy(); + expect(eventExport.handler).toHaveBeenCalledTimes(2); + expect(eventImport.handler).not.toHaveBeenCalled(); + + reset(); + + (eventExport.handler as jest.Mock).mockResolvedValue(true); + (eventImport.handler as jest.Mock).mockRejectedValue(false); + + const importFail = await step.run(state); + + expect(importFail).toBeFalsy(); + expect(eventExport.handler).toHaveBeenCalledTimes(2); + expect(eventImport.handler).toHaveBeenCalled(); + }); + + it('should attempt to archive events with the CREATE action on revert, skipping archived events', async () => { + const fakeLog = new FileLog(); + fakeLog.switchGroup('Clone Events'); + fakeLog.addAction('EVENT-CREATE', 'event'); + fakeLog.addAction('EVENT-CREATE', 'event3'); // is archived + + const state = generateState(`temp_${process.env.JEST_WORKER_ID}/clone-event/revert-create/`, 'revert-create'); + + await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/clone-event/revert-create/oldEvent`); + + state.revertLog = fakeLog; + + const step = new EventCloneStep(); + await step.revert(state); + + expect(mockArchiveEvent).toHaveBeenCalledTimes(1); + expect(mockFailArchiveEvent).toHaveBeenCalledTimes(1); + expect(state.logFile.getData('ARCHIVE').length).toEqual(1); + expect(eventImport.handler).not.toHaveBeenCalled(); + }); + + it('should pass events with the UPDATE action to the event import command on revert, in the oldEvent folder', async () => { + const state = generateState(`temp_${process.env.JEST_WORKER_ID}/clone-event/revert-update/`, 'revert-update'); + + const fakeLog = new FileLog(); + fakeLog.switchGroup('Clone Events'); + fakeLog.addAction('EVENT-CREATE', 'event'); + fakeLog.addAction('EVENT-UPDATE', 'event2 0 1'); + + await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/clone-event/revert-update/oldEvent`); + + state.revertLog = fakeLog; + + const step = new EventCloneStep(); + const result = await step.revert(state); + + expect(mockArchiveEvent).toHaveBeenCalledTimes(1); + expect(eventImport.handler).toHaveBeenCalledWith({ + dir: join(state.path, 'oldEvent'), + originalIds: true, + schedule: true, + acceptSnapshotLimits: true, + mapFile: 'mapping.json', + catchup: false, + logFile: state.logFile, + ...state.to + }); + + expect(result).toBeTruthy(); + }); + + it('should return false when importing events for revert fails', async () => { + const state = generateState(`temp_${process.env.JEST_WORKER_ID}/clone-event/revert-update/`, 'revert-update'); + + const fakeLog = new FileLog(); + fakeLog.switchGroup('Clone Events'); + fakeLog.addAction('EVENT-CREATE', 'event'); + fakeLog.addAction('EVENT-UPDATE', 'event2 0 1'); + + await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/clone-event/revert-update/oldEvent`); + + state.revertLog = fakeLog; + (eventImport.handler as jest.Mock).mockRejectedValue(false); + + const step = new EventCloneStep(); + const result = await step.revert(state); + + expect(mockArchiveEvent).toHaveBeenCalledTimes(1); + expect(result).toBeFalsy(); + }); +}); diff --git a/src/commands/hub/steps/event-clone-step.ts b/src/commands/hub/steps/event-clone-step.ts new file mode 100644 index 00000000..b23332b7 --- /dev/null +++ b/src/commands/hub/steps/event-clone-step.ts @@ -0,0 +1,112 @@ +import { CloneHubStep, CloneHubStepId } from '../model/clone-hub-step'; +import { CloneHubState } from '../model/clone-hub-state'; +import { join } from 'path'; + +import { handler as exportEvent } from '../../event/export'; +import { handler as importEvent } from '../../event/import'; +import { FileLog } from '../../../common/file-log'; +import { existsSync } from 'fs'; +import dynamicContentClientFactory from '../../../services/dynamic-content-client-factory'; + +export class EventCloneStep implements CloneHubStep { + getId(): CloneHubStepId { + return CloneHubStepId.Event; + } + + getName(): string { + return 'Clone Events'; + } + + isLimited = true; + + async run(state: CloneHubState): Promise { + try { + state.logFile.appendLine(`Exporting existing events from destination.`); + await exportEvent({ + dir: join(state.path, 'oldEvent'), + force: true, + snapshots: false, + logFile: state.logFile, + ...state.to + }); + } catch (e) { + state.logFile.appendLine(`ERROR: Could not export existing events. \n${e}`); + return false; + } + + try { + state.logFile.appendLine(`Exporting events from source.`); + await exportEvent({ + dir: join(state.path, 'event'), + force: true, + snapshots: false, + logFile: state.logFile, + ...state.from + }); + } catch (e) { + state.logFile.appendLine(`ERROR: Could not export events. \n${e}`); + return false; + } + + try { + await importEvent({ + dir: join(state.path, 'event'), + logFile: state.logFile, + mapFile: state.argv.mapFile, + originalIds: false, + schedule: true, + acceptSnapshotLimits: true, + catchup: false, + ...state.to + }); + } catch (e) { + state.logFile.appendLine(`ERROR: Could not import events. \n${e}`); + return false; + } + + return true; + } + + async revert(state: CloneHubState): Promise { + const client = dynamicContentClientFactory(state.to); + + const toArchive = (state.revertLog as FileLog).getData('EVENT-CREATE', this.getName()); + const toUpdate = (state.revertLog as FileLog).getData('EVENT-UPDATE', this.getName()); + + for (let i = 0; i < toArchive.length; i++) { + try { + const event = await client.events.get(toArchive[i]); + await event.related.archive(); + state.logFile.addAction('ARCHIVE', toArchive[i]); + } catch (e) { + state.logFile.appendLine(`Couldn't archive event ${toArchive[i]}. Continuing...`); + } + } + + // Update using the oldEvent folder. + if (toUpdate.length > 0 && existsSync(join(state.path, 'oldEvent'))) { + try { + await importEvent( + { + dir: join(state.path, 'oldEvent'), + logFile: state.logFile, + mapFile: state.argv.mapFile, + originalIds: true, + schedule: true, + acceptSnapshotLimits: true, + catchup: false, + ...state.to + } + /*, + toUpdate.map(item => item.split(' ')[0]) + */ + ); + } catch (e) { + state.logFile.appendLine(`ERROR: Could not import old events. \n${e}`); + return false; + } + } + + return true; + } +} diff --git a/src/commands/hub/steps/extension-clone-step.spec.ts b/src/commands/hub/steps/extension-clone-step.spec.ts index 476041fb..59fb6c47 100644 --- a/src/commands/hub/steps/extension-clone-step.spec.ts +++ b/src/commands/hub/steps/extension-clone-step.spec.ts @@ -56,6 +56,7 @@ describe('extension clone step', () => { ...yargArgs, ...config, logFile: new FileLog(), + acceptSnapshotLimits: false, dir: directory, @@ -118,7 +119,7 @@ describe('extension clone step', () => { ...state.from }); - expect(extensionImport.handler).toBeCalledWith({ + expect(extensionImport.handler).toHaveBeenCalledWith({ dir: join(state.path, 'extension'), logFile: state.logFile, ...state.to @@ -136,8 +137,8 @@ describe('extension clone step', () => { const backupFail = await step.run(state); expect(backupFail).toBeFalsy(); - expect(extensionExport.handler).toBeCalledTimes(1); - expect(extensionImport.handler).not.toBeCalled(); + expect(extensionExport.handler).toHaveBeenCalledTimes(1); + expect(extensionImport.handler).not.toHaveBeenCalled(); reset(); @@ -147,8 +148,8 @@ describe('extension clone step', () => { const exportFail = await step.run(state); expect(exportFail).toBeFalsy(); - expect(extensionExport.handler).toBeCalledTimes(2); - expect(extensionImport.handler).not.toBeCalled(); + expect(extensionExport.handler).toHaveBeenCalledTimes(2); + expect(extensionImport.handler).not.toHaveBeenCalled(); reset(); @@ -158,8 +159,8 @@ describe('extension clone step', () => { const importFail = await step.run(state); expect(importFail).toBeFalsy(); - expect(extensionExport.handler).toBeCalledTimes(2); - expect(extensionImport.handler).toBeCalled(); + expect(extensionExport.handler).toHaveBeenCalledTimes(2); + expect(extensionImport.handler).toHaveBeenCalled(); }); it('should pass extensions with the UPDATE action to the extension import command on revert, in the oldExtension folder', async () => { @@ -177,7 +178,7 @@ describe('extension clone step', () => { const step = new ExtensionCloneStep(); const result = await step.revert(state); - expect(extensionImport.handler).toBeCalledWith( + expect(extensionImport.handler).toHaveBeenCalledWith( { dir: join(state.path, 'oldExtension'), logFile: state.logFile, diff --git a/src/commands/hub/steps/index-clone-step.spec.ts b/src/commands/hub/steps/index-clone-step.spec.ts index 649dbbcd..0a3b4fbf 100644 --- a/src/commands/hub/steps/index-clone-step.spec.ts +++ b/src/commands/hub/steps/index-clone-step.spec.ts @@ -56,6 +56,7 @@ describe('index clone step', () => { ...yargArgs, ...config, logFile: new FileLog(), + acceptSnapshotLimits: false, dir: directory, @@ -118,7 +119,7 @@ describe('index clone step', () => { ...state.from }); - expect(indexImport.handler).toBeCalledWith({ + expect(indexImport.handler).toHaveBeenCalledWith({ dir: join(state.path, 'index'), logFile: state.logFile, webhooks: true, @@ -137,8 +138,8 @@ describe('index clone step', () => { const backupFail = await step.run(state); expect(backupFail).toBeFalsy(); - expect(indexExport.handler).toBeCalledTimes(1); - expect(indexImport.handler).not.toBeCalled(); + expect(indexExport.handler).toHaveBeenCalledTimes(1); + expect(indexImport.handler).not.toHaveBeenCalled(); reset(); @@ -148,8 +149,8 @@ describe('index clone step', () => { const exportFail = await step.run(state); expect(exportFail).toBeFalsy(); - expect(indexExport.handler).toBeCalledTimes(2); - expect(indexImport.handler).not.toBeCalled(); + expect(indexExport.handler).toHaveBeenCalledTimes(2); + expect(indexImport.handler).not.toHaveBeenCalled(); reset(); @@ -159,8 +160,8 @@ describe('index clone step', () => { const importFail = await step.run(state); expect(importFail).toBeFalsy(); - expect(indexExport.handler).toBeCalledTimes(2); - expect(indexImport.handler).toBeCalled(); + expect(indexExport.handler).toHaveBeenCalledTimes(2); + expect(indexImport.handler).toHaveBeenCalled(); }); it('should pass indexes with the UPDATE action to the index import command on revert, in the oldIndex folder', async () => { @@ -178,7 +179,7 @@ describe('index clone step', () => { const step = new IndexCloneStep(); const result = await step.revert(state); - expect(indexImport.handler).toBeCalledWith( + expect(indexImport.handler).toHaveBeenCalledWith( { dir: join(state.path, 'oldIndex'), logFile: state.logFile, diff --git a/src/commands/hub/steps/schema-clone-step.spec.ts b/src/commands/hub/steps/schema-clone-step.spec.ts index aeced297..39c7754e 100644 --- a/src/commands/hub/steps/schema-clone-step.spec.ts +++ b/src/commands/hub/steps/schema-clone-step.spec.ts @@ -66,6 +66,7 @@ describe('schema clone step', () => { ...yargArgs, ...config, logFile: new FileLog(), + acceptSnapshotLimits: false, dir: directory, @@ -120,7 +121,7 @@ describe('schema clone step', () => { ...state.from }); - expect(schemaImport.handler).toBeCalledWith({ + expect(schemaImport.handler).toHaveBeenCalledWith({ dir: join(state.path, 'schema'), logFile: state.logFile, ...state.to diff --git a/src/commands/hub/steps/settings-clone-step.spec.ts b/src/commands/hub/steps/settings-clone-step.spec.ts index d56549e5..2bc85c37 100644 --- a/src/commands/hub/steps/settings-clone-step.spec.ts +++ b/src/commands/hub/steps/settings-clone-step.spec.ts @@ -43,6 +43,7 @@ describe('settings clone step', () => { ...yargArgs, ...config, logFile: new FileLog(), + acceptSnapshotLimits: false, dir: directory, diff --git a/src/commands/hub/steps/type-clone-step.spec.ts b/src/commands/hub/steps/type-clone-step.spec.ts index 96f38107..c21b8562 100644 --- a/src/commands/hub/steps/type-clone-step.spec.ts +++ b/src/commands/hub/steps/type-clone-step.spec.ts @@ -66,6 +66,7 @@ describe('type clone step', () => { ...yargArgs, ...config, logFile: new FileLog(), + acceptSnapshotLimits: false, dir: directory, @@ -128,7 +129,7 @@ describe('type clone step', () => { ...state.from }); - expect(typeImport.handler).toBeCalledWith({ + expect(typeImport.handler).toHaveBeenCalledWith({ dir: join(state.path, 'type'), sync: true, logFile: state.logFile, @@ -147,8 +148,8 @@ describe('type clone step', () => { const backupFail = await step.run(state); expect(backupFail).toBeFalsy(); - expect(typeExport.handler).toBeCalledTimes(1); - expect(typeImport.handler).not.toBeCalled(); + expect(typeExport.handler).toHaveBeenCalledTimes(1); + expect(typeImport.handler).not.toHaveBeenCalled(); reset(); @@ -158,8 +159,8 @@ describe('type clone step', () => { const exportFail = await step.run(state); expect(exportFail).toBeFalsy(); - expect(typeExport.handler).toBeCalledTimes(2); - expect(typeImport.handler).not.toBeCalled(); + expect(typeExport.handler).toHaveBeenCalledTimes(2); + expect(typeImport.handler).not.toHaveBeenCalled(); reset(); @@ -169,8 +170,8 @@ describe('type clone step', () => { const importFail = await step.run(state); expect(importFail).toBeFalsy(); - expect(typeExport.handler).toBeCalledTimes(2); - expect(typeImport.handler).toBeCalled(); + expect(typeExport.handler).toHaveBeenCalledTimes(2); + expect(typeImport.handler).toHaveBeenCalled(); }); it('should attempt to archive types with the CREATE action on revert, skipping archived types', async () => { @@ -192,7 +193,7 @@ describe('type clone step', () => { await step.revert(state); expect(mockContent.metrics.typesArchived).toEqual(1); - expect(typeImport.handler).not.toBeCalled(); + expect(typeImport.handler).not.toHaveBeenCalled(); }); it('should pass types with the UPDATE action to the type import command on revert, in the oldType folder', async () => { @@ -211,7 +212,7 @@ describe('type clone step', () => { const result = await step.revert(state); expect(mockContent.metrics.typesArchived).toEqual(1); - expect(typeImport.handler).toBeCalledWith( + expect(typeImport.handler).toHaveBeenCalledWith( { dir: join(state.path, 'oldType'), sync: true, diff --git a/src/commands/job.spec.ts b/src/commands/job.spec.ts new file mode 100644 index 00000000..e6484c3e --- /dev/null +++ b/src/commands/job.spec.ts @@ -0,0 +1,12 @@ +import Yargs from 'yargs/yargs'; +import { builder } from './job'; +import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; + +describe('job command', () => { + it('should build', () => { + const argv = Yargs(process.argv.slice(2)); + const spyCommandDir = jest.spyOn(argv, 'commandDir').mockReturnValue(argv); + builder(argv); + expect(spyCommandDir).toHaveBeenCalledWith('job', YargsCommandBuilderOptions); + }); +}); diff --git a/src/commands/job.ts b/src/commands/job.ts new file mode 100644 index 00000000..e33565b8 --- /dev/null +++ b/src/commands/job.ts @@ -0,0 +1,20 @@ +import { Argv } from 'yargs'; +import { readConfig } from '../cli'; +import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import { configureCommandOptions } from './configure'; + +export const command = 'job'; + +export const desc = 'Job'; + +export const builder = (yargs: Argv): Argv => + yargs + .commandDir('job', YargsCommandBuilderOptions) + .options(configureCommandOptions) + .config('config', readConfig) + .demandCommand() + .help(); + +export const handler = (): void => { + /* do nothing */ +}; diff --git a/src/commands/job/get.spec.ts b/src/commands/job/get.spec.ts new file mode 100644 index 00000000..f1dca9c7 --- /dev/null +++ b/src/commands/job/get.spec.ts @@ -0,0 +1,69 @@ +import Yargs from 'yargs/yargs'; +import { builder, command, handler } from './get'; +import DataPresenter, { RenderingOptions } from '../../view/data-presenter'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { Hub, Job } from 'dc-management-sdk-js'; +import { singleItemTableOptions } from '../../common/table/table.consts'; + +jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../view/data-presenter'); + +describe('job get command', () => { + it('should command should defined', function () { + expect(command).toEqual('get '); + }); + + describe('builder', () => { + it('should configure command arguments', function () { + const argv = Yargs(process.argv.slice(2)); + const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); + const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); + + builder(argv); + + expect(spyPositional).toHaveBeenCalledWith('id', { + describe: 'Job ID', + type: 'string' + }); + expect(spyOptions).toHaveBeenCalledWith(RenderingOptions); + }); + }); + + describe('handler', () => { + const yargArgs = { + $0: 'test', + _: ['test'], + json: true + }; + const config = { + clientId: 'client-id', + clientSecret: 'client-secret', + hubId: '67d1c1c7642fa239dbe15164' + }; + + it('should get a job by id', async () => { + const mockDataPresenter = DataPresenter as jest.Mock; + const mockGetHub = jest.fn(); + const mockGetJob = jest.fn(); + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub.mockResolvedValue({ + ...new Hub({ id: '67d1c1c7642fa239dbe15164' }), + related: { jobs: { get: mockGetJob.mockResolvedValue(new Job({ id: '68e5289f0aba3024bde050f9' })) } } + }) + } + }); + const argv = { ...yargArgs, id: '68e5289f0aba3024bde050f9', ...config }; + + await handler(argv); + + expect(mockGetHub).toHaveBeenCalledWith('67d1c1c7642fa239dbe15164'); + expect(mockGetJob).toHaveBeenCalledWith('68e5289f0aba3024bde050f9'); + expect(mockDataPresenter).toHaveBeenCalledWith({ id: '68e5289f0aba3024bde050f9' }); + expect(mockDataPresenter.mock.instances[0].render).toHaveBeenCalledWith({ + json: argv.json, + tableUserConfig: singleItemTableOptions + }); + }); + }); +}); diff --git a/src/commands/job/get.ts b/src/commands/job/get.ts new file mode 100644 index 00000000..8c36d81f --- /dev/null +++ b/src/commands/job/get.ts @@ -0,0 +1,35 @@ +import { Arguments, Argv } from 'yargs'; +import DataPresenter, { RenderingArguments, RenderingOptions } from '../../view/data-presenter'; +import { ConfigurationParameters } from '../configure'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { singleItemTableOptions } from '../../common/table/table.consts'; + +export const command = 'get '; + +export const desc = 'Get a Job by ID'; + +export const builder = (yargs: Argv): void => { + yargs + .positional('id', { + describe: 'Job ID', + type: 'string' + }) + .options(RenderingOptions); +}; + +export interface BuilderOptions { + id: string; +} + +export const handler = async ( + argv: Arguments +): Promise => { + const client = dynamicContentClientFactory(argv); + const hub = await client.hubs.get(argv.hubId); + const job = await hub.related.jobs.get(argv.id); + + new DataPresenter(job.toJSON()).render({ + json: argv.json, + tableUserConfig: singleItemTableOptions + }); +}; diff --git a/src/commands/linked-content-repository.ts b/src/commands/linked-content-repository.ts new file mode 100644 index 00000000..d64c9427 --- /dev/null +++ b/src/commands/linked-content-repository.ts @@ -0,0 +1,20 @@ +import { Argv } from 'yargs'; +import { readConfig } from '../cli'; +import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import { configureCommandOptions } from './configure'; + +export const command = 'linked-content-repository'; + +export const desc = 'Linked Content Repository'; + +export const builder = (yargs: Argv): Argv => + yargs + .commandDir('linked-content-repository', YargsCommandBuilderOptions) + .options(configureCommandOptions) + .config('config', readConfig) + .demandCommand() + .help(); + +export const handler = (): void => { + /* do nothing */ +}; diff --git a/src/commands/linked-content-repository/create.spec.ts b/src/commands/linked-content-repository/create.spec.ts new file mode 100644 index 00000000..41d0742a --- /dev/null +++ b/src/commands/linked-content-repository/create.spec.ts @@ -0,0 +1,75 @@ +import { LinkedContentRepository } from 'dc-management-sdk-js'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { handler } from './create'; +import DataPresenter from '../../view/data-presenter'; +import { singleItemTableOptions } from '../../common/table/table.consts'; +import { jsonResolver } from '../../common/json-resolver/json-resolver'; + +jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../view/data-presenter'); +jest.mock('../../common/json-resolver/json-resolver'); + +describe('linked-content-repository', () => { + const mockDataPresenter = DataPresenter as jest.Mock; + + afterEach((): void => { + jest.restoreAllMocks(); + }); + + it('should create a linked content respository', async () => { + const yargArgs = { + $0: 'test', + _: ['test'], + json: true + }; + const config = { + patToken: 'patToken', + hubId: 'hub-id' + }; + const linkedContentRepositoryPayload = { + originHubId: '67a4c79111e8f0513ce243ac', + hubIds: ['67a4c79111e8f0513ce243ac', '68932ed38f35681e4d3eac61'], + originHubLabel: 'Development Hub A', + destinationHubLabel: 'Development Hub B', + bidirectional: false, + relationships: [ + { + originRepositoryId: '67a4c7ad11e8f0513ce243ad', + originRepositoryLabel: 'Repo A', + dstRepositoryId: '68932f2d8f35681e4d3eac62', + dstRepositoryLabel: 'Repo B' + } + ] + }; + + const mockCreate = jest.fn().mockResolvedValue(new LinkedContentRepository(linkedContentRepositoryPayload)); + + const mockGetHub = jest.fn().mockResolvedValue({ + related: { + linkedContentRepositories: { + create: mockCreate + } + } + }); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub + } + }); + + (jsonResolver as jest.Mock).mockReturnValue(JSON.stringify(linkedContentRepositoryPayload)); + + const argv = { ...yargArgs, ...config, file: './path/to/file.json' }; + await handler(argv); + + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(mockCreate).toHaveBeenCalledWith(linkedContentRepositoryPayload); + + expect(mockDataPresenter).toHaveBeenCalledWith(linkedContentRepositoryPayload); + expect(mockDataPresenter.mock.instances[0].render).toHaveBeenCalledWith({ + json: argv.json, + tableUserConfig: singleItemTableOptions + }); + }); +}); diff --git a/src/commands/linked-content-repository/create.ts b/src/commands/linked-content-repository/create.ts new file mode 100644 index 00000000..4b7827aa --- /dev/null +++ b/src/commands/linked-content-repository/create.ts @@ -0,0 +1,44 @@ +import { Arguments, Argv } from 'yargs'; +import { ConfigurationParameters } from '../configure'; +import DataPresenter, { RenderingArguments, RenderingOptions } from '../../view/data-presenter'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { jsonResolver } from '../../common/json-resolver/json-resolver'; +import { LinkedContentRepository } from 'dc-management-sdk-js'; +import { singleItemTableOptions } from '../../common/table/table.consts'; + +export const command = 'create'; + +export const desc = 'Create Linked Content Repository'; + +export const builder = (yargs: Argv): void => { + yargs.options({ + file: { + type: 'string', + demandOption: true, + description: 'Linked Content Repository json file location', + requiresArg: true + }, + ...RenderingOptions + }); +}; + +export interface BuilderOptions { + file: string; +} + +export const handler = async ( + argv: Arguments +): Promise => { + const { file } = argv; + const client = dynamicContentClientFactory(argv); + const json = await jsonResolver(file); + const hub = await client.hubs.get(argv.hubId); + const linkedContentRepository = await hub.related.linkedContentRepositories.create( + new LinkedContentRepository(JSON.parse(json)) + ); + + new DataPresenter(linkedContentRepository.toJSON()).render({ + json: argv.json, + tableUserConfig: singleItemTableOptions + }); +}; diff --git a/src/commands/linked-content-repository/delete.spec.ts b/src/commands/linked-content-repository/delete.spec.ts new file mode 100644 index 00000000..9c1aff0c --- /dev/null +++ b/src/commands/linked-content-repository/delete.spec.ts @@ -0,0 +1,75 @@ +import { LinkedContentRepository } from 'dc-management-sdk-js'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { handler } from './delete'; +import DataPresenter from '../../view/data-presenter'; +import { singleItemTableOptions } from '../../common/table/table.consts'; +import { jsonResolver } from '../../common/json-resolver/json-resolver'; + +jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../view/data-presenter'); +jest.mock('../../common/json-resolver/json-resolver'); + +describe('linked-content-repository', () => { + const mockDataPresenter = DataPresenter as jest.Mock; + + afterEach((): void => { + jest.restoreAllMocks(); + }); + + it('should delete a linked content respository', async () => { + const yargArgs = { + $0: 'test', + _: ['test'], + json: true + }; + const config = { + patToken: 'patToken', + hubId: 'hub-id' + }; + const linkedContentRepositoryPayload = { + originHubId: '67a4c79111e8f0513ce243ac', + hubIds: ['67a4c79111e8f0513ce243ac', '68932ed38f35681e4d3eac61'], + originHubLabel: 'Development Hub A', + destinationHubLabel: 'Development Hub B', + bidirectional: false, + relationships: [ + { + originRepositoryId: '67a4c7ad11e8f0513ce243ad', + originRepositoryLabel: 'Repo A', + dstRepositoryId: '68932f2d8f35681e4d3eac62', + dstRepositoryLabel: 'Repo B' + } + ] + }; + const linkedContentRepositoryResponse = { ...linkedContentRepositoryPayload, relationships: [] }; + const mockDelete = jest.fn().mockResolvedValue(new LinkedContentRepository(linkedContentRepositoryResponse)); + + const mockGetHub = jest.fn().mockResolvedValue({ + related: { + linkedContentRepositories: { + delete: mockDelete + } + } + }); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub + } + }); + + (jsonResolver as jest.Mock).mockReturnValue(JSON.stringify(linkedContentRepositoryPayload)); + + const argv = { ...yargArgs, ...config, file: './path/to/file.json' }; + await handler(argv); + + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(mockDelete).toHaveBeenCalledWith(linkedContentRepositoryPayload); + + expect(mockDataPresenter).toHaveBeenCalledWith({ ...linkedContentRepositoryPayload, relationships: [] }); + expect(mockDataPresenter.mock.instances[0].render).toHaveBeenCalledWith({ + json: argv.json, + tableUserConfig: singleItemTableOptions + }); + }); +}); diff --git a/src/commands/linked-content-repository/delete.ts b/src/commands/linked-content-repository/delete.ts new file mode 100644 index 00000000..f8f11aec --- /dev/null +++ b/src/commands/linked-content-repository/delete.ts @@ -0,0 +1,44 @@ +import { Arguments, Argv } from 'yargs'; +import { ConfigurationParameters } from '../configure'; +import DataPresenter, { RenderingArguments, RenderingOptions } from '../../view/data-presenter'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { jsonResolver } from '../../common/json-resolver/json-resolver'; +import { LinkedContentRepository } from 'dc-management-sdk-js'; +import { singleItemTableOptions } from '../../common/table/table.consts'; + +export const command = 'delete'; + +export const desc = 'Delete Linked Content Repository'; + +export const builder = (yargs: Argv): void => { + yargs.options({ + file: { + type: 'string', + demandOption: true, + description: 'Linked Content Repository json file location', + requiresArg: true + }, + ...RenderingOptions + }); +}; + +export interface BuilderOptions { + file: string; +} + +export const handler = async ( + argv: Arguments +): Promise => { + const { file } = argv; + const client = dynamicContentClientFactory(argv); + const json = await jsonResolver(file); + const hub = await client.hubs.get(argv.hubId); + const linkedContentRepository = await hub.related.linkedContentRepositories.delete( + new LinkedContentRepository(JSON.parse(json)) + ); + + new DataPresenter(linkedContentRepository.toJSON()).render({ + json: argv.json, + tableUserConfig: singleItemTableOptions + }); +}; diff --git a/src/commands/linked-content-repository/list.spec.ts b/src/commands/linked-content-repository/list.spec.ts new file mode 100644 index 00000000..0d2b8865 --- /dev/null +++ b/src/commands/linked-content-repository/list.spec.ts @@ -0,0 +1,100 @@ +import { LinkedContentRepository } from 'dc-management-sdk-js'; +import MockPage from '../../common/dc-management-sdk-js/mock-page'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { handler, itemMapFn } from './list'; +import { DEFAULT_SIZE } from '../../common/dc-management-sdk-js/paginator'; +import DataPresenter from '../../view/data-presenter'; + +jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../view/data-presenter'); + +describe('linked-content-repository', () => { + const mockDataPresenter = DataPresenter as jest.Mock; + + afterEach((): void => { + jest.restoreAllMocks(); + }); + + it('should list linked content respositories', async () => { + const yargArgs = { + $0: 'test', + _: ['test'], + json: true + }; + const config = { + patToken: 'patToken', + hubId: 'hub-id' + }; + const pagingOptions = { sort: 'createdDate,desc' }; + const linkedContentRepositoryPayload = { + originHubId: '67a4c79111e8f0513ce243ac', + hubIds: ['67a4c79111e8f0513ce243ac', '68932ed38f35681e4d3eac61'], + originHubLabel: 'Development Hub A', + destinationHubLabel: 'Development Hub B', + bidirectional: false, + relationships: [ + { + originRepositoryId: '67a4c7ad11e8f0513ce243ad', + originRepositoryLabel: 'Repo A', + dstRepositoryId: '68932f2d8f35681e4d3eac62', + dstRepositoryLabel: 'Repo B' + } + ] + }; + const linkedContentRepositoryResponse = [new LinkedContentRepository(linkedContentRepositoryPayload)]; + + const listResponse = new MockPage(LinkedContentRepository, linkedContentRepositoryResponse); + const mockList = jest.fn().mockResolvedValue(listResponse); + + const mockGetHub = jest.fn().mockResolvedValue({ + related: { + linkedContentRepositories: { + list: mockList + } + } + }); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub + } + }); + + const argv = { ...yargArgs, ...config, ...pagingOptions }; + await handler(argv); + + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(mockList).toHaveBeenCalledWith({ size: DEFAULT_SIZE, ...pagingOptions }); + + expect(mockDataPresenter).toHaveBeenCalledWith([linkedContentRepositoryPayload]); + expect(mockDataPresenter.mock.instances[0].render).toHaveBeenCalledWith({ json: argv.json, itemMapFn }); + }); + + describe('itemMapFn', function () { + it('should render response view', function () { + const result = itemMapFn( + new LinkedContentRepository({ + originHubId: '67a4c79111e8f0513ce243ac', + hubIds: ['67a4c79111e8f0513ce243ac', '68932ed38f35681e4d3eac61'], + originHubLabel: 'Development Hub A', + destinationHubLabel: 'Development Hub B', + bidirectional: false, + relationships: [ + { + originRepositoryId: '67a4c7ad11e8f0513ce243ad', + originRepositoryLabel: 'Repo A', + dstRepositoryId: '68932f2d8f35681e4d3eac62', + dstRepositoryLabel: 'Repo B' + } + ] + }) + ); + expect(result).toEqual({ + bidirectional: false, + hubIds: ['67a4c79111e8f0513ce243ac', '68932ed38f35681e4d3eac61'], + originHubId: '67a4c79111e8f0513ce243ac', + originHubLabel: 'Development Hub A' + }); + }); + }); +}); diff --git a/src/commands/linked-content-repository/list.ts b/src/commands/linked-content-repository/list.ts new file mode 100644 index 00000000..c7253cb9 --- /dev/null +++ b/src/commands/linked-content-repository/list.ts @@ -0,0 +1,37 @@ +import { Arguments } from 'yargs'; +import paginator from '../../common/dc-management-sdk-js/paginator'; +import { extractSortable, PagingParameters, SortingOptions } from '../../common/yargs/sorting-options'; +import { CommandOptions } from '../../interfaces/command-options.interface'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import DataPresenter, { RenderingArguments, RenderingOptions } from '../../view/data-presenter'; +import { ConfigurationParameters } from '../configure'; +import { LinkedContentRepository } from 'dc-management-sdk-js'; + +export const command = 'list'; + +export const desc = 'List Linked Content Repositories'; + +export const builder: CommandOptions = { + ...SortingOptions, + ...RenderingOptions +}; + +export const itemMapFn = ({ originHubId, originHubLabel, hubIds, bidirectional }: LinkedContentRepository): object => ({ + originHubId, + originHubLabel, + hubIds, + bidirectional +}); + +export const handler = async ( + argv: Arguments +): Promise => { + const client = dynamicContentClientFactory(argv); + const hub = await client.hubs.get(argv.hubId); + const contentRepositoryList = await paginator(hub.related.linkedContentRepositories.list, extractSortable(argv)); + + new DataPresenter(contentRepositoryList.map(value => value.toJSON())).render({ + json: argv.json, + itemMapFn: itemMapFn + }); +}; diff --git a/src/commands/linked-content-repository/update.spec.ts b/src/commands/linked-content-repository/update.spec.ts new file mode 100644 index 00000000..d68ae8c1 --- /dev/null +++ b/src/commands/linked-content-repository/update.spec.ts @@ -0,0 +1,75 @@ +import { LinkedContentRepository } from 'dc-management-sdk-js'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { handler } from './update'; +import DataPresenter from '../../view/data-presenter'; +import { singleItemTableOptions } from '../../common/table/table.consts'; +import { jsonResolver } from '../../common/json-resolver/json-resolver'; + +jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../view/data-presenter'); +jest.mock('../../common/json-resolver/json-resolver'); + +describe('linked-content-repository', () => { + const mockDataPresenter = DataPresenter as jest.Mock; + + afterEach((): void => { + jest.restoreAllMocks(); + }); + + it('should update a linked content respository', async () => { + const yargArgs = { + $0: 'test', + _: ['test'], + json: true + }; + const config = { + patToken: 'patToken', + hubId: 'hub-id' + }; + const linkedContentRepositoryPayload = { + originHubId: '67a4c79111e8f0513ce243ac', + hubIds: ['67a4c79111e8f0513ce243ac', '68932ed38f35681e4d3eac61'], + originHubLabel: 'Development Hub A', + destinationHubLabel: 'Development Hub B', + bidirectional: false, + relationships: [ + { + originRepositoryId: '67a4c7ad11e8f0513ce243ad', + originRepositoryLabel: 'Repo A', + dstRepositoryId: '68932f2d8f35681e4d3eac62', + dstRepositoryLabel: 'Repo B' + } + ] + }; + + const mockUpdate = jest.fn().mockResolvedValue(new LinkedContentRepository(linkedContentRepositoryPayload)); + + const mockGetHub = jest.fn().mockResolvedValue({ + related: { + linkedContentRepositories: { + update: mockUpdate + } + } + }); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub + } + }); + + (jsonResolver as jest.Mock).mockReturnValue(JSON.stringify(linkedContentRepositoryPayload)); + + const argv = { ...yargArgs, ...config, file: './path/to/file.json' }; + await handler(argv); + + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(mockUpdate).toHaveBeenCalledWith(linkedContentRepositoryPayload); + + expect(mockDataPresenter).toHaveBeenCalledWith(linkedContentRepositoryPayload); + expect(mockDataPresenter.mock.instances[0].render).toHaveBeenCalledWith({ + json: argv.json, + tableUserConfig: singleItemTableOptions + }); + }); +}); diff --git a/src/commands/linked-content-repository/update.ts b/src/commands/linked-content-repository/update.ts new file mode 100644 index 00000000..a2980263 --- /dev/null +++ b/src/commands/linked-content-repository/update.ts @@ -0,0 +1,44 @@ +import { Arguments, Argv } from 'yargs'; +import { ConfigurationParameters } from '../configure'; +import DataPresenter, { RenderingArguments, RenderingOptions } from '../../view/data-presenter'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { jsonResolver } from '../../common/json-resolver/json-resolver'; +import { LinkedContentRepository } from 'dc-management-sdk-js'; +import { singleItemTableOptions } from '../../common/table/table.consts'; + +export const command = 'update'; + +export const desc = 'Update Linked Content Repository'; + +export const builder = (yargs: Argv): void => { + yargs.options({ + file: { + type: 'string', + demandOption: true, + description: 'Linked Content Repository json file location', + requiresArg: true + }, + ...RenderingOptions + }); +}; + +export interface BuilderOptions { + file: string; +} + +export const handler = async ( + argv: Arguments +): Promise => { + const { file } = argv; + const client = dynamicContentClientFactory(argv); + const json = await jsonResolver(file); + const hub = await client.hubs.get(argv.hubId); + const linkedContentRepository = await hub.related.linkedContentRepositories.update( + new LinkedContentRepository(JSON.parse(json)) + ); + + new DataPresenter(linkedContentRepository.toJSON()).render({ + json: argv.json, + tableUserConfig: singleItemTableOptions + }); +}; diff --git a/src/commands/search-index.ts b/src/commands/search-index.ts index ff53211d..664df65d 100644 --- a/src/commands/search-index.ts +++ b/src/commands/search-index.ts @@ -1,5 +1,7 @@ import { Argv } from 'yargs'; +import { readConfig } from '../cli'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import { configureCommandOptions } from './configure'; export const command = 'search-index'; @@ -8,6 +10,8 @@ export const desc = 'Search Index'; export const builder = (yargs: Argv): Argv => yargs .commandDir('search-index', YargsCommandBuilderOptions) + .options(configureCommandOptions) + .config('config', readConfig) .demandCommand() .help(); diff --git a/src/commands/search-index/__snapshots__/import.spec.ts.snap b/src/commands/search-index/__snapshots__/import.spec.ts.snap index 4b226cf4..2499de56 100644 --- a/src/commands/search-index/__snapshots__/import.spec.ts.snap +++ b/src/commands/search-index/__snapshots__/import.spec.ts.snap @@ -1,30 +1,16 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`search-index import command doCreate should throw an error when enrichIndex fails 1`] = ` -"Error creating index index-name: +exports[`search-index import command doCreate should throw an error when enrichIndex fails 1`] = `"Error creating index index-name: The update-index action is not available, ensure you have permission to perform this action."`; -The update-index action is not available, ensure you have permission to perform this action." -`; - -exports[`search-index import command doCreate should throw an error when index create fails 1`] = ` -"Error creating index index-name: - -Error: Error creating index" -`; - -exports[`search-index import command doCreate should throw an error when index create fails if a string error is returned by the sdk 1`] = ` -"Error creating index index-name: - -The create-index action is not available, ensure you have permission to perform this action." -`; +exports[`search-index import command doCreate should throw an error when index create fails 1`] = `"Error creating index index-name: Error: Error creating index"`; -exports[`search-index import command doUpdate should throw an error when unable to get index during update 1`] = `"Error updating index matched-name: Error retrieving index"`; +exports[`search-index import command doCreate should throw an error when index create fails if a string error is returned by the sdk 1`] = `"Error creating index index-name: The create-index action is not available, ensure you have permission to perform this action."`; -exports[`search-index import command doUpdate should throw an error when unable to update index during update 1`] = `"Error updating index not-matched-name: Error saving index"`; +exports[`search-index import command doUpdate should throw an error when unable to get index during update 1`] = `"Error updating index matched-name: Error: Error retrieving index"`; -exports[`search-index import command doUpdate should throw an error when unable to update index during update if a string error is returned by sdk 1`] = `"Error updating index not-matched-name: undefined"`; +exports[`search-index import command doUpdate should throw an error when unable to update index during update 1`] = `"Error updating index not-matched-name: Error: Error saving index"`; -exports[`search-index import command handler tests should throw an error when no content found in import directory 1`] = `"No indexes found in my-empty-dir"`; +exports[`search-index import command doUpdate should throw an error when unable to update index during update if a string error is returned by sdk 1`] = `"Error updating index not-matched-name: The update action is not available, ensure you have permission to perform this action."`; exports[`search-index import command validateNoDuplicateIndexNames should throw and error when there are duplicate uris 1`] = ` "Indexes must have unique name values. Duplicate values found:- diff --git a/src/commands/search-index/export.spec.ts b/src/commands/search-index/export.spec.ts index 2130597e..84f3f86a 100644 --- a/src/commands/search-index/export.spec.ts +++ b/src/commands/search-index/export.spec.ts @@ -138,7 +138,13 @@ describe('search-index export command', (): void => { expect( webhookEquals( new Webhook(exampleWebhook), - new Webhook({ ...exampleWebhook, headers: [{ key: 'key', value: 'value' }, { key: 'key', value: 'value2' }] }) + new Webhook({ + ...exampleWebhook, + headers: [ + { key: 'key', value: 'value' }, + { key: 'key', value: 'value2' } + ] + }) ) ).toBeFalsy(); }); @@ -1213,12 +1219,14 @@ describe('search-index export command', (): void => { let mockList: jest.Mock; beforeEach(() => { + jest.resetAllMocks(); (loadJsonFromDirectory as jest.Mock).mockReturnValue([]); const listResponse = new MockPage(SearchIndex, indexesToExport); mockList = jest.fn().mockResolvedValue(listResponse); mockGetHub = jest.fn().mockResolvedValue({ + _links: { 'algolia-search-indexes': {} }, related: { searchIndexes: { list: mockList @@ -1234,7 +1242,7 @@ describe('search-index export command', (): void => { jest.spyOn(exportModule, 'processIndexes').mockResolvedValue(); }); - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('search-index', 'export', process.platform); @@ -1294,5 +1302,31 @@ describe('search-index export command', (): void => { false ); }); + + it('should exit early if algolia-search-indexes link is missing', async (): Promise => { + const argv = { ...yargArgs, ...config, dir: 'my-dir', logFile: new FileLog() }; + + jest.spyOn(exportModule, 'enrichIndex'); + jest.spyOn(exportModule, 'filterIndexesById'); + + const listMock = jest.fn(); + + mockGetHub.mockReturnValue({ + related: { + searchIndexes: { + list: listMock + } + } + }); + + await handler(argv); + + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(listMock).not.toHaveBeenCalled(); + expect(loadJsonFromDirectory).not.toHaveBeenCalledWith(); + expect(validateNoDuplicateIndexNames).not.toHaveBeenCalled(); + expect(exportModule.filterIndexesById).not.toHaveBeenCalled(); + expect(exportModule.processIndexes).not.toHaveBeenCalled(); + }); }); }); diff --git a/src/commands/search-index/export.ts b/src/commands/search-index/export.ts index 7ad9fc2a..a7ac5564 100644 --- a/src/commands/search-index/export.ts +++ b/src/commands/search-index/export.ts @@ -150,11 +150,44 @@ export class EnrichedSearchIndex extends SearchIndex { assignedContentTypes: EnrichedAssignedContentType[]; replicas: EnrichedReplica[]; + constructor(data?: unknown) { + super(data); + + if (this.settings && !(this.settings instanceof SearchIndexSettings)) { + this.settings = new SearchIndexSettings(this.settings); + } + + if (this.keys && !(this.keys instanceof SearchIndexKey)) { + this.keys = new SearchIndexKey(this.keys); + } + + if (this.assignedContentTypes) { + this.assignedContentTypes = this.assignedContentTypes.map(x => + x instanceof EnrichedAssignedContentType ? x : new EnrichedAssignedContentType(x) + ); + } + + if (this.replicas) { + this.replicas = this.replicas.map(x => (x instanceof EnrichedReplica ? x : new EnrichedReplica(x))); + } + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any public toJSON(): any { const result = super.toJSON(); - result.assignedContentTypes = result.assignedContentTypes.map((type: AssignedContentType) => type.toJSON()); + if (result.settings) { + result.settings = result.settings.toJSON(); + } + if (result.keys) { + result.keys = result.keys.toJSON(); + } + if (result.assignedContentTypes) { + result.assignedContentTypes = result.assignedContentTypes.map((type: AssignedContentType) => type.toJSON()); + } + if (result.replicas) { + result.replicas = result.replicas.map((replica: EnrichedReplica) => replica.toJSON()); + } return result; } } @@ -437,10 +470,17 @@ export const handler = async (argv: Arguments(dir, EnrichedSearchIndex); validateNoDuplicateIndexNames(previouslyExportedIndexes); const allStoredIndexes = await paginator(searchIndexList(hub)); + const { storedIndexes, allReplicas } = separateReplicas(allStoredIndexes); const idArray: string[] = id ? (Array.isArray(id) ? id : [id]) : []; diff --git a/src/commands/search-index/import.spec.ts b/src/commands/search-index/import.spec.ts index ca937d69..aa1a59ef 100644 --- a/src/commands/search-index/import.spec.ts +++ b/src/commands/search-index/import.spec.ts @@ -177,7 +177,7 @@ describe('search-index import command', (): void => { ] `); expect(mockCreate).toHaveBeenCalledWith(expect.objectContaining({ ...indexBase, assignedContentTypes })); - expect(importModule.enrichIndex).toHaveBeenCalledWith(newIndex, index, webhooks); + expect(importModule.enrichIndex).toHaveBeenCalledWith(mockHub, newIndex, index, webhooks); expect(result).toEqual(newIndex); }); @@ -237,7 +237,7 @@ describe('search-index import command', (): void => { ).rejects.toThrowErrorMatchingSnapshot(); expect(mockCreate).toHaveBeenCalledWith(expect.objectContaining({ ...indexBase, assignedContentTypes })); - expect(importModule.enrichIndex).toHaveBeenCalledWith(newIndex, index, webhooks); + expect(importModule.enrichIndex).toHaveBeenCalledWith(mockHub, newIndex, index, webhooks); expect(log.getData('CREATE')).toEqual([]); }); }); @@ -251,7 +251,10 @@ describe('search-index import command', (): void => { } it('should fetch settings, content types for comparison with the index to be enriched', async () => { + const mockHub = new Hub(); + const index = new SearchIndex({ + id: 'id-1', name: 'index-1', label: 'index-1' }); @@ -266,17 +269,26 @@ describe('search-index import command', (): void => { index.related.assignedContentTypes.list = jest.fn().mockResolvedValue(new MockPage(AssignedContentType, [])); index.related.assignedContentTypes.create = jest.fn(); - await enrichIndex(index, enrichedIndex, undefined); + mockHub.related.searchIndexes.get = jest.fn().mockResolvedValue(index); + + await enrichIndex(mockHub, index, enrichedIndex, undefined); expect(enrichedIndex.settings.replicas).toEqual([]); expect(index.related.settings.get).toHaveBeenCalled(); - expect(index.related.settings.update).toHaveBeenCalledWith(enrichedIndex.settings, false); + expect(index.related.settings.update).toHaveBeenCalledWith(enrichedIndex.settings, false, { + waitUntilApplied: false + }); expect(index.related.assignedContentTypes.list).toHaveBeenCalled(); expect(index.related.assignedContentTypes.create).not.toHaveBeenCalled(); + + expect(mockHub.related.searchIndexes.get).toHaveBeenCalledWith('id-1'); }); it("should update settings with a union of both source and destination replicas, then update each replica's settings", async () => { + const mockHub = new Hub(); + const index = new SearchIndex({ + id: 'id-1', name: 'index-1', label: 'index-1' }); @@ -314,12 +326,16 @@ describe('search-index import command', (): void => { index.related.assignedContentTypes.list = jest.fn().mockResolvedValue(new MockPage(AssignedContentType, [])); index.related.assignedContentTypes.create = jest.fn(); - await enrichIndex(index, enrichedIndex, undefined); + mockHub.related.searchIndexes.get = jest.fn().mockResolvedValue(index); + + await enrichIndex(mockHub, index, enrichedIndex, undefined); expect(enrichedIndex.settings.replicas).toEqual(expect.arrayContaining(['replica-1', 'replica-2', 'replica-3'])); expect(enrichedIndex.settings.replicas.length).toEqual(3); expect(index.related.settings.get).toHaveBeenCalled(); - expect(index.related.settings.update).toHaveBeenCalledWith(enrichedIndex.settings, false); + expect(index.related.settings.update).toHaveBeenCalledWith(enrichedIndex.settings, false, { + waitUntilApplied: ['replicas'] + }); expect(index.related.replicas.list).toHaveBeenCalled(); for (let i = 0; i < 2; i++) { @@ -329,10 +345,80 @@ describe('search-index import command', (): void => { expect(index.related.assignedContentTypes.list).toHaveBeenCalled(); expect(index.related.assignedContentTypes.create).not.toHaveBeenCalled(); + + expect(mockHub.related.searchIndexes.get).toHaveBeenCalledWith('id-1'); + }); + + it("should report a failure if its not possible to successfully update a replica's settings", async () => { + const mockHub = new Hub(); + + const index = new SearchIndex({ + id: 'id-1', + name: 'index-1', + label: 'index-1' + }); + + const enrichedIndex = new EnrichedSearchIndex({ + settings: { + replicas: ['replica-1', 'replica-2'] + }, + assignedContentTypes: [], + replicas: [ + new EnrichedReplica({ + name: 'replica-1', + settings: new SearchIndexSettings({ setting: '1' }) + }), + new EnrichedReplica({ + name: 'replica-2', + settings: new SearchIndexSettings({ setting: '2' }) + }) + ] + }); + + const indexNames = ['replica-1', 'replica-2', 'replica-3']; + const replicas = indexNames.map(name => { + const index = new SearchIndex({ name }); + index.related.update = jest.fn().mockResolvedValue(index); + index.related.settings.update = jest.fn().mockImplementation(() => Promise.reject(new Error('mocked error'))); + return index; + }); + + index.related.settings.get = jest.fn().mockResolvedValue(new SearchIndexSettings({ replicas: ['replica-3'] })); + index.related.settings.update = jest.fn().mockResolvedValue(new SearchIndexSettings()); + index.related.replicas.list = jest.fn().mockResolvedValue(new MockPage(SearchIndex, replicas)); + index.related.assignedContentTypes.list = jest.fn().mockResolvedValue(new MockPage(AssignedContentType, [])); + index.related.assignedContentTypes.create = jest.fn(); + + mockHub.related.searchIndexes.get = jest.fn().mockResolvedValue(index); + + await expect(enrichIndex(mockHub, index, enrichedIndex, undefined)).rejects.toThrowErrorMatchingInlineSnapshot( + `"mocked error"` + ); + + expect(enrichedIndex.settings.replicas).toEqual(expect.arrayContaining(['replica-1', 'replica-2', 'replica-3'])); + expect(enrichedIndex.settings.replicas.length).toEqual(3); + expect(index.related.settings.get).toHaveBeenCalled(); + expect(index.related.settings.update).toHaveBeenCalledWith(enrichedIndex.settings, false, { + waitUntilApplied: ['replicas'] + }); + expect(index.related.replicas.list).toHaveBeenCalled(); + + for (let i = 0; i < 2; i++) { + expect((replicas[i].related.update as jest.Mock).mock.calls[0][0].name).toEqual(replicas[i].name); + expect(replicas[i].related.settings.update).toHaveBeenCalledWith(enrichedIndex.replicas[i].settings, false); + } + + expect(index.related.assignedContentTypes.list).not.toHaveBeenCalled(); + expect(index.related.assignedContentTypes.create).not.toHaveBeenCalled(); + + expect(mockHub.related.searchIndexes.get).toHaveBeenCalledWith('id-1'); }); it('should assign any content types that are not yet assigned on the destination index, removing any that are no longer present', async () => { + const mockHub = new Hub(); + const index = new SearchIndex({ + id: 'id-1', name: 'index-1', label: 'index-1' }); @@ -365,7 +451,9 @@ describe('search-index import command', (): void => { return type; }); - await enrichIndex(index, enrichedIndex, undefined); + mockHub.related.searchIndexes.get = jest.fn().mockResolvedValue(index); + + await enrichIndex(mockHub, index, enrichedIndex, undefined); expect(created).toEqual([enrichedIndex.assignedContentTypes[0]]); @@ -375,12 +463,19 @@ describe('search-index import command', (): void => { expect(enrichedIndex.settings.replicas).toEqual([]); expect(index.related.settings.get).toHaveBeenCalled(); - expect(index.related.settings.update).toHaveBeenCalledWith(enrichedIndex.settings, false); + expect(index.related.settings.update).toHaveBeenCalledWith(enrichedIndex.settings, false, { + waitUntilApplied: false + }); expect(index.related.assignedContentTypes.list).toHaveBeenCalled(); + + expect(mockHub.related.searchIndexes.get).toHaveBeenCalledWith('id-1'); }); it('should update webhooks for the destination index when they are available', async () => { + const mockHub = new Hub(); + const index = new SearchIndex({ + id: 'id-1', name: 'index-1', label: 'index-1' }); @@ -411,7 +506,9 @@ describe('search-index import command', (): void => { index.related.assignedContentTypes.list = jest.fn().mockResolvedValue(new MockPage(AssignedContentType, [type])); index.related.assignedContentTypes.create = jest.fn(); - await enrichIndex(index, enrichedIndex, enrichedWebhooks); + mockHub.related.searchIndexes.get = jest.fn().mockResolvedValue(index); + + await enrichIndex(mockHub, index, enrichedIndex, enrichedWebhooks); expect(type.related.unassign).not.toHaveBeenCalled(); expect(index.related.assignedContentTypes.create).not.toHaveBeenCalled(); @@ -436,8 +533,13 @@ describe('search-index import command', (): void => { expect(enrichedIndex.settings.replicas).toEqual([]); expect(index.related.settings.get).toHaveBeenCalled(); - expect(index.related.settings.update).toHaveBeenCalledWith(enrichedIndex.settings, false); + expect(enrichedIndex.settings).toBeInstanceOf(SearchIndexSettings); + expect(index.related.settings.update).toHaveBeenCalledWith(enrichedIndex.settings, false, { + waitUntilApplied: false + }); expect(index.related.assignedContentTypes.list).toHaveBeenCalled(); + + expect(mockHub.related.searchIndexes.get).toHaveBeenCalledWith('id-1'); }); }); @@ -487,7 +589,7 @@ describe('search-index import command', (): void => { `); expect(hub.related.searchIndexes.get).toHaveBeenCalledWith('stored-id'); expect(exportModule.enrichIndex).toHaveBeenCalledWith(expect.any(Map), replicas, storedIndex); - expect(importModule.enrichIndex).toHaveBeenCalledWith(updatedIndex, mutatedIndex, webhooks); + expect(importModule.enrichIndex).toHaveBeenCalledWith(hub, updatedIndex, mutatedIndex, webhooks); expect(result).toEqual({ index: updatedIndex, updateStatus: UpdateStatus.UPDATED }); expect(mockUpdate.mock.calls[0][0].toJSON()).toEqual(expectedIndex.toJSON()); }); @@ -817,7 +919,7 @@ describe('search-index import command', (): void => { }); }); - describe('validateNoDuplicateIndexNames', function() { + describe('validateNoDuplicateIndexNames', function () { it('should not throw an error when there are no duplicates', () => { const indexesToProcess = { 'file-1': new EnrichedSearchIndex({ @@ -851,11 +953,19 @@ describe('search-index import command', (): void => { }); }); - describe('rewriteIndexNames', function() { + describe('rewriteIndexNames', function () { it("should rewrite index names to contain the given hub's name", () => { const indexesToProcess = { 'file-1': new EnrichedSearchIndex({ - name: 'oldHub.index-name-1' + name: 'oldHub.index-name-1', + replicas: [ + new EnrichedReplica({ + name: 'oldHub.index-name-1_sort-example' + }) + ], + settings: { + replicas: ['oldHub.index-name-1_sort-example'] + } }), 'file-2': new EnrichedSearchIndex({ name: 'index-name-2' @@ -868,10 +978,12 @@ describe('search-index import command', (): void => { expect(indexesToProcess['file-1'].name).toEqual('newHub.index-name-1'); expect(indexesToProcess['file-2'].name).toEqual('newHub.index-name-2'); + expect(indexesToProcess['file-1'].replicas[0].name).toEqual('newHub.index-name-1_sort-example'); + expect(indexesToProcess['file-1'].settings.replicas[0]).toEqual('newHub.index-name-1_sort-example'); }); }); - describe('filterIndexesById', function() { + describe('filterIndexesById', function () { it('should delete indexes without a matching id', () => { const indexesToProcess = { 'file-1': new EnrichedSearchIndex({ @@ -952,7 +1064,7 @@ describe('search-index import command', (): void => { }); }); - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('search-index', 'import', process.platform); @@ -1072,12 +1184,22 @@ describe('search-index import command', (): void => { ); }); - it('should throw an error when no content found in import directory', async (): Promise => { + it('should exit early when no content found in import directory', async (): Promise => { const argv = { ...yargArgs, ...config, dir: 'my-empty-dir', logFile: new FileLog() }; (loadJsonFromDirectory as jest.Mock).mockReturnValue([]); - await expect(handler(argv)).rejects.toThrowErrorMatchingSnapshot(); + await handler(argv); + + expect(argv.logFile.closed).toBeTruthy(); + expect(argv.logFile.accessGroup).toMatchInlineSnapshot(` +Array [ + Object { + "comment": true, + "data": "No search indexes found in my-empty-dir", + }, +] +`); }); }); }); diff --git a/src/commands/search-index/import.ts b/src/commands/search-index/import.ts index 12dbca03..067b73ff 100644 --- a/src/commands/search-index/import.ts +++ b/src/commands/search-index/import.ts @@ -83,20 +83,43 @@ export const validateNoDuplicateIndexNames = (importedIndexes: { } }; +const rewriteIndexName = (hub: Hub, index: SearchIndex): void => { + const name = index.name as string; + const firstDot = name.indexOf('.'); + + if (firstDot == -1) { + index.name = `${hub.name}.${name}`; + } else { + index.name = `${hub.name}${name.substring(firstDot)}`; + } +}; + export const rewriteIndexNames = ( hub: Hub, importedIndexes: { [filename: string]: EnrichedSearchIndex; } ): void | never => { + const toRewrite: SearchIndex[] = [...Object.values(importedIndexes)]; for (const index of Object.values(importedIndexes)) { - const name = index.name as string; - const firstDot = name.indexOf('.'); - - if (firstDot == -1) { - index.name = `${hub.name}.${name}`; - } else { - index.name = `${hub.name}${name.substring(firstDot)}`; + rewriteIndexName(hub, index); + + if (index.replicas) { + for (const replica of index.replicas) { + const name = replica.name; + rewriteIndexName(hub, replica); + + const sReplicas: string[] = index.settings.replicas; + + if (sReplicas) { + for (let i = 0; i < sReplicas.length; i++) { + if (sReplicas[i] === name) { + sReplicas[i] = replica.name as string; + } + } + } + } + toRewrite.push(...index.replicas); } } }; @@ -139,6 +162,7 @@ export const updateWebhookIfDifferent = async (webhook: Webhook, newWebhook: Web }; export const enrichIndex = async ( + hub: Hub, index: SearchIndex, enrichedIndex: EnrichedSearchIndex, webhooks: Map | undefined @@ -153,24 +177,32 @@ export const enrichIndex = async ( }); } enrichedIndex.settings.replicas = Array.from(replicas); + const hasReplicas = replicas.size; // Update the search index settings. - await index.related.settings.update(enrichedIndex.settings, false); + await index.related.settings.update(enrichedIndex.settings, false, { + waitUntilApplied: hasReplicas ? ['replicas'] : false + }); + + // Updating the settings might have changed the available hal links, so refetch it. + index = await hub.related.searchIndexes.get(index.id as string); - if (replicas.size) { + if (hasReplicas) { // Replica settings must also be updated. The replicas may have changed, so fetch them again. - const replicas = await paginator(replicaList(index)); + const listOfReplicas = await paginator(replicaList(index)); - for (const importReplica of enrichedIndex.replicas) { - let replica = replicas.find(replica => replica.name === importReplica.name); + await Promise.all( + enrichedIndex.replicas.map(async importReplica => { + let replica = listOfReplicas.find(replica => replica.name === importReplica.name); - if (replica) { - replica = await replica.related.update(new SearchIndex(getIndexProperties(importReplica))); + if (replica) { + replica = await replica.related.update(new SearchIndex(getIndexProperties(importReplica))); - replica.related.settings.update(importReplica.settings, false); - } - } + return replica.related.settings.update(importReplica.settings, false); + } + }) + ); } const types = await paginator(index.related.assignedContentTypes.list); @@ -224,13 +256,13 @@ export const doCreate = async ( const createdIndex = await hub.related.searchIndexes.create(toCreate); - await enrichIndex(createdIndex, index, webhooks); + await enrichIndex(hub, createdIndex, index, webhooks); log.addAction('CREATE', `${createdIndex.id}`); return createdIndex; } catch (err) { - throw new Error(`Error creating index ${index.name}:\n\n${err}`); + throw new Error(`Error creating index ${index.name}: ${err}`); } }; @@ -256,13 +288,13 @@ export const doUpdate = async ( const updatedIndex = await retrievedIndex.related.update(retrievedIndex); - await enrichIndex(updatedIndex, index, webhooks); + await enrichIndex(hub, updatedIndex, index, webhooks); log.addAction('UPDATE', `${retrievedIndex.id}`); return { index: updatedIndex, updateStatus: UpdateStatus.UPDATED }; } catch (err) { - throw new Error(`Error updating index ${index.name}: ${err.message}`); + throw new Error(`Error updating index ${index.name}: ${err}`); } }; @@ -326,7 +358,9 @@ export const handler = async ( const log = logFile.open(); const indexes = loadJsonFromDirectory(dir, EnrichedSearchIndex); if (Object.keys(indexes).length === 0) { - throw new Error(`No indexes found in ${dir}`); + log.appendLine(`No search indexes found in ${dir}`); + await log.close(); + return; } validateNoDuplicateIndexNames(indexes); diff --git a/src/commands/search-index/webhook-rewriter.spec.ts b/src/commands/search-index/webhook-rewriter.spec.ts index 57b60b9a..cc05b997 100644 --- a/src/commands/search-index/webhook-rewriter.spec.ts +++ b/src/commands/search-index/webhook-rewriter.spec.ts @@ -1,6 +1,6 @@ import { rewriteDeliveryContentItem } from './webhook-rewriter'; -describe('webhook-rewriter tests', function() { +describe('webhook-rewriter tests', function () { beforeEach(() => { jest.resetAllMocks(); }); diff --git a/src/commands/settings.spec.ts b/src/commands/settings.spec.ts index 7cef99ab..a3679528 100644 --- a/src/commands/settings.spec.ts +++ b/src/commands/settings.spec.ts @@ -1,12 +1,17 @@ import { builder } from './settings'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; import Yargs from 'yargs/yargs'; +import { configureCommandOptions } from './configure'; -describe('settings command', function() { +describe('settings command', function () { it('should include the commands in the settings dir', () => { const argv = Yargs(process.argv.slice(2)); const spyCommandDir = jest.spyOn(argv, 'commandDir').mockReturnValue(argv); + const spyOptions = jest.spyOn(argv, 'options').mockReturnThis(); + const spyConfig = jest.spyOn(argv, 'config').mockReturnThis(); builder(argv); expect(spyCommandDir).toHaveBeenCalledWith('settings', YargsCommandBuilderOptions); + expect(spyOptions).toHaveBeenCalledWith(configureCommandOptions); + expect(spyConfig).toHaveBeenCalledWith('config', expect.any(Function)); }); }); diff --git a/src/commands/settings.ts b/src/commands/settings.ts index c695784a..05b1ebc2 100644 --- a/src/commands/settings.ts +++ b/src/commands/settings.ts @@ -1,5 +1,7 @@ import { Argv } from 'yargs'; +import { readConfig } from '../cli'; import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import { configureCommandOptions } from './configure'; export const command = 'settings'; @@ -8,5 +10,7 @@ export const desc = 'Settings'; export const builder = (yargs: Argv): Argv => yargs .commandDir('settings', YargsCommandBuilderOptions) + .options(configureCommandOptions) + .config('config', readConfig) .demandCommand() .help(); diff --git a/src/commands/settings/export.spec.ts b/src/commands/settings/export.spec.ts index 923300d1..998f9358 100644 --- a/src/commands/settings/export.spec.ts +++ b/src/commands/settings/export.spec.ts @@ -56,7 +56,7 @@ describe('settings export command', (): void => { }); }); - it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function() { + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { LOG_FILENAME(); expect(getDefaultLogPath).toHaveBeenCalledWith('settings', 'export', process.platform); diff --git a/src/commands/settings/export.ts b/src/commands/settings/export.ts index cc42ae97..f7c585f6 100644 --- a/src/commands/settings/export.ts +++ b/src/commands/settings/export.ts @@ -67,7 +67,8 @@ export const processSettings = async ( settings: { devices: settings.devices, applications: settings.applications, - localization: settings.localization + localization: settings.localization, + contentItems: settings.contentItems }, workflowStates: workflowStates }); diff --git a/src/commands/settings/import.spec.ts b/src/commands/settings/import.spec.ts index 9a755100..b364e2fa 100644 --- a/src/commands/settings/import.spec.ts +++ b/src/commands/settings/import.spec.ts @@ -52,12 +52,10 @@ describe('settings import command', (): void => { }, _links: { self: { - href: - 'https://api.amplience.net/v2/content/hubs/5b32377e4cedfd01c45036d8/workflow-states/5f57a008c9e77c00018c0c29' + href: 'https://api.amplience.net/v2/content/hubs/5b32377e4cedfd01c45036d8/workflow-states/5f57a008c9e77c00018c0c29' }, update: { - href: - 'https://api.amplience.net/v2/content/hubs/5b32377e4cedfd01c45036d8/workflow-states/5f57a008c9e77c00018c0c29' + href: 'https://api.amplience.net/v2/content/hubs/5b32377e4cedfd01c45036d8/workflow-states/5f57a008c9e77c00018c0c29' } } }) @@ -88,12 +86,10 @@ describe('settings import command', (): void => { }, _links: { self: { - href: - 'https://api.amplience.net/v2/content/hubs/5b32377e4cedfd01c45036d8/workflow-states/5f57a008c9e77c00018c0c29' + href: 'https://api.amplience.net/v2/content/hubs/5b32377e4cedfd01c45036d8/workflow-states/5f57a008c9e77c00018c0c29' }, update: { - href: - 'https://api.amplience.net/v2/content/hubs/5b32377e4cedfd01c45036d8/workflow-states/5f57a008c9e77c00018c0c29' + href: 'https://api.amplience.net/v2/content/hubs/5b32377e4cedfd01c45036d8/workflow-states/5f57a008c9e77c00018c0c29' } } }) @@ -124,12 +120,10 @@ describe('settings import command', (): void => { }, _links: { self: { - href: - 'https://api.amplience.net/v2/content/hubs/5b32377e4cedfd01c45036d8/workflow-states/5f57a008c9e77c00018c0c29' + href: 'https://api.amplience.net/v2/content/hubs/5b32377e4cedfd01c45036d8/workflow-states/5f57a008c9e77c00018c0c29' }, update: { - href: - 'https://api.amplience.net/v2/content/hubs/5b32377e4cedfd01c45036d8/workflow-states/5f57a008c9e77c00018c0c29' + href: 'https://api.amplience.net/v2/content/hubs/5b32377e4cedfd01c45036d8/workflow-states/5f57a008c9e77c00018c0c29' } } }) @@ -319,6 +313,12 @@ describe('settings import command', (): void => { type: 'string' }); + expect(spyOptions).toHaveBeenCalledWith('allowDelete', { + type: 'boolean', + boolean: true, + describe: 'Allows removal of settings that are not in the imported json when possible, such as previews.' + }); + expect(spyOptions).toHaveBeenCalledWith('mapFile', { type: 'string', requiresArg: false, @@ -446,7 +446,11 @@ describe('settings import command', (): void => { await rimraf('./mapSettings.json'); await rimraf('./settings-5db1727bcff47e0001ce5fd2.json'); await promisify(writeFile)('./mapSettings.json', JSON.stringify(settingsMappingFile)); - await promisify(writeFile)('./settings-5db1727bcff47e0001ce5fd2.json', JSON.stringify(settingsExported)); + + const newSettingsExported = JSON.parse(JSON.stringify(settingsExported)); + newSettingsExported.settings.applications[0].name = 'replacementAdditional'; + + await promisify(writeFile)('./settings-5db1727bcff47e0001ce5fd2.json', JSON.stringify(newSettingsExported)); await handler({ ...argv, @@ -459,6 +463,7 @@ describe('settings import command', (): void => { expect(mockGetHub).toHaveBeenCalled(); expect(mockUpdateSettings).toHaveBeenCalledTimes(1); + expect(mockUpdateSettings.mock.calls[0][2].applications.length).toEqual(2); expect(mockCreateState).toHaveBeenCalledTimes(1); expect(fileExists).toBeTruthy(); @@ -487,6 +492,38 @@ describe('settings import command', (): void => { await promisify(unlink)('./mapSettings2.json'); }); + it('should process settings from a local directory, allowDelete removes existing previews', async () => { + await rimraf('./mapSettings.json'); + await rimraf('./settings-5db1727bcff47e0001ce5fd2.json'); + await promisify(writeFile)('./mapSettings.json', JSON.stringify(settingsMappingFile)); + + const newSettingsExported = JSON.parse(JSON.stringify(settingsExported)); + newSettingsExported.settings.applications[0].name = 'replacementPreview'; + + await promisify(writeFile)('./settings-5db1727bcff47e0001ce5fd2.json', JSON.stringify(newSettingsExported)); + + await handler({ + ...argv, + mapFile: './mapSettings.json', + logFile: createLog('./log.json'), + allowDelete: true, + force: true + }); + + const fileExists = await promisify(exists)('./log.json'); + + expect(mockGetHub).toHaveBeenCalled(); + expect(mockUpdateSettings).toHaveBeenCalledTimes(1); + expect(mockUpdateSettings.mock.calls[0][2].applications[0].name).toEqual('replacementPreview'); + expect(mockUpdateSettings.mock.calls[0][2].applications.length).toEqual(1); + expect(mockCreateState).toHaveBeenCalledTimes(1); + expect(fileExists).toBeTruthy(); + + await promisify(unlink)('./settings-5db1727bcff47e0001ce5fd2.json'); + await promisify(unlink)('./mapSettings.json'); + await promisify(unlink)('./log.json'); + }); + it('no map file', async () => { await rimraf('./settings-5db1727bcff47e0001ce5fd2.json'); await promisify(writeFile)('./settings-5db1727bcff47e0001ce5fd2.json', JSON.stringify(settingsExported)); diff --git a/src/commands/settings/import.ts b/src/commands/settings/import.ts index b1450929..bdcf419c 100644 --- a/src/commands/settings/import.ts +++ b/src/commands/settings/import.ts @@ -48,6 +48,11 @@ export const builder = (yargs: Argv): void => { describe: 'Source file path containing Settings definition', type: 'string' }) + .option('allowDelete', { + type: 'boolean', + boolean: true, + describe: 'Allows removal of settings that are not in the imported json when possible, such as previews.' + }) .option('mapFile', { type: 'string', requiresArg: false, @@ -102,7 +107,12 @@ export const handler = async ( } if (hub.settings && hub.settings.applications) { - uniqueApplications = uniqBy([...hub.settings.applications, ...settings.applications], 'name'); + if (argv.allowDelete) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + uniqueApplications = [...settings.applications] as any[]; + } else { + uniqueApplications = uniqBy([...settings.applications, ...hub.settings.applications], 'name'); + } } await hub.related.settings.update( @@ -111,7 +121,8 @@ export const handler = async ( applications: uniqueApplications, localization: { locales: uniqueLocales - } + }, + contentItems: settings.contentItems }) ); diff --git a/src/commands/webhook.ts b/src/commands/webhook.ts new file mode 100644 index 00000000..e397573e --- /dev/null +++ b/src/commands/webhook.ts @@ -0,0 +1,18 @@ +import { Argv } from 'yargs'; +import { readConfig } from '../cli'; +import YargsCommandBuilderOptions from '../common/yargs/yargs-command-builder-options'; +import { configureCommandOptions } from './configure'; + +export const command = 'webhook'; + +export const desc = 'Webhook'; + +export const builder = (yargs: Argv): Argv => + yargs + .commandDir('webhook', YargsCommandBuilderOptions) + .options(configureCommandOptions) + .config('config', readConfig) + .demandCommand() + .help(); + +export const handler = (): void => {}; diff --git a/src/commands/webhook/delete.spec.ts b/src/commands/webhook/delete.spec.ts new file mode 100644 index 00000000..eb9f9381 --- /dev/null +++ b/src/commands/webhook/delete.spec.ts @@ -0,0 +1,139 @@ +import * as deleteModule from './delete'; +import Yargs from 'yargs/yargs'; +import { builder, coerceLog, LOG_FILENAME, command, handler } from './delete'; +import { getDefaultLogPath } from '../../common/log-helpers'; +import { Webhook } from 'dc-management-sdk-js'; +import MockPage from '../../common/dc-management-sdk-js/mock-page'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { FileLog } from '../../common/file-log'; +import * as questionHelpers from '../../common/question-helpers'; + +jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../common/log-helpers'); +jest.mock('../../common/question-helpers'); + +describe('delete webhooks', () => { + it('should implement an export command', () => { + expect(command).toEqual('delete [id]'); + }); + + describe('builder tests', () => { + it('should configure yargs', () => { + const argv = Yargs(process.argv.slice(2)); + const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); + const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); + + builder(argv); + + expect(spyPositional).toHaveBeenCalledWith('id', { + describe: + 'The ID of the webhook to be deleted. If id is not provided, this command will delete ALL webhooks in the hub.', + type: 'string' + }); + expect(spyOption).toHaveBeenCalledWith('f', { + type: 'boolean', + boolean: true, + describe: 'If present, there will be no confirmation prompt before deleting the found webhooks.' + }); + expect(spyOption).toHaveBeenCalledWith('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: coerceLog + }); + }); + }); + + describe('handler tests', () => { + const yargArgs = { + $0: 'test', + _: ['test'] + }; + + const config = { + clientId: 'client-id', + clientSecret: 'client-id', + hubId: 'hub-id' + }; + + const webhooksToDelete: Webhook[] = [ + new Webhook({ + id: 'webhook-id-1', + label: 'webhook-label-1' + }), + new Webhook({ + id: 'webhook-id-2', + label: 'webhook-label-2' + }) + ]; + + let mockGetHub: jest.Mock; + let mockList: jest.Mock; + let mockGet: jest.Mock; + + beforeEach((): void => { + const listResponse = new MockPage(Webhook, webhooksToDelete); + mockList = jest.fn().mockResolvedValue(listResponse); + mockGet = jest.fn().mockResolvedValue(webhooksToDelete[1]); + + mockGetHub = jest.fn().mockResolvedValue({ + related: { + webhooks: { + list: mockList, + get: mockGet + } + } + }); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub + } + }); + + jest.spyOn(deleteModule, 'processWebhooks').mockResolvedValue({ failedWebhooks: [] }); + }); + + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { + LOG_FILENAME(); + expect(getDefaultLogPath).toHaveBeenCalledWith('webhook', 'delete', process.platform); + }); + + it('should delete all webhooks in a hub', async (): Promise => { + const argv = { ...yargArgs, ...config, logFile: new FileLog() }; + + jest.spyOn(deleteModule, 'handler'); + + (questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(true); + + await handler(argv); + + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(mockList).toHaveBeenCalledTimes(1); + expect(mockList).toHaveBeenCalledWith({ size: 100 }); + + expect(deleteModule.processWebhooks).toHaveBeenCalledWith(webhooksToDelete, argv.logFile); + }); + + it('should delete a webhook by id', async (): Promise => { + const id: string[] | undefined = ['webhook-id-2']; + const argv = { + ...yargArgs, + ...config, + id, + logFile: new FileLog() + }; + + jest.spyOn(deleteModule, 'handler'); + + (questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(true); + + await handler(argv); + + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(mockGet).toHaveBeenCalledTimes(1); + + expect(deleteModule.processWebhooks).toHaveBeenCalledWith([webhooksToDelete[1]], argv.logFile); + }); + }); +}); diff --git a/src/commands/webhook/delete.ts b/src/commands/webhook/delete.ts new file mode 100644 index 00000000..86569bba --- /dev/null +++ b/src/commands/webhook/delete.ts @@ -0,0 +1,115 @@ +import { Arguments, Argv } from 'yargs'; +import { FileLog } from '../../common/file-log'; +import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { ConfigurationParameters } from '../configure'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { nothingExportedExit as nothingToDeleteExit } from '../../services/export.service'; +import { Webhook } from 'dc-management-sdk-js'; +import { asyncQuestion } from '../../common/question-helpers'; +import { progressBar } from '../../common/progress-bar/progress-bar'; +import { DeleteWebhookBuilderOptions } from '../../interfaces/delete-webhook-builder-options'; +import { getWebhooksByIds } from '../../common/webhooks/get-webhooks-by-ids'; +import { getAllWebhooks } from '../../common/webhooks/get-all-webhook'; + +export const command = 'delete [id]'; + +export const desc = 'Delete Webhook'; + +export const LOG_FILENAME = (platform: string = process.platform): string => + getDefaultLogPath('webhook', 'delete', platform); + +export const coerceLog = (logFile: string): FileLog => createLog(logFile, 'Webhook Delete Log'); + +export const builder = (yargs: Argv): void => { + yargs + .positional('id', { + type: 'string', + describe: + 'The ID of the webhook to be deleted. If id is not provided, this command will delete ALL webhooks in the hub.' + }) + .alias('f', 'force') + .option('f', { + type: 'boolean', + boolean: true, + describe: 'If present, there will be no confirmation prompt before deleting the found webhooks.' + }) + .option('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: coerceLog + }); +}; + +export const processWebhooks = async ( + webhooksToDelete: Webhook[], + log: FileLog +): Promise<{ failedWebhooks: Webhook[] }> => { + const failedWebhooks: Webhook[] = []; + + const progress = progressBar(webhooksToDelete.length, 0, { + title: `Deleting ${webhooksToDelete.length} webhook/s.` + }); + + for (const webhook of webhooksToDelete) { + try { + await webhook.related.delete(); + log.addComment(`Successfully deleted "${webhook.label}"`); + progress.increment(); + } catch (e) { + failedWebhooks.push(webhook); + log.addComment(`Failed to delete ${webhook.label}: ${e.toString()}`); + progress.increment(); + } + } + + progress.stop(); + + return { failedWebhooks }; +}; + +export const handler = async ( + argv: Arguments +): Promise => { + const { id, logFile, force } = argv; + const log = logFile.open(); + const client = dynamicContentClientFactory(argv); + const allWebhooks = !id; + const hub = await client.hubs.get(argv.hubId); + let ids: string[] = []; + + if (id) { + ids = Array.isArray(id) ? id : [id]; + } + + const webhooksToDelete = ids.length > 0 ? await getWebhooksByIds(hub, ids) : await getAllWebhooks(hub); + + if (webhooksToDelete.length === 0) { + nothingToDeleteExit(log, 'No webhooks to delete from this hub, exiting.'); + return; + } + + if (!force) { + const baseMessage = 'This action cannot be undone. Are you sure you want to continue? (Y/n)\n'; + const yes = await asyncQuestion( + allWebhooks + ? `Providing no ID/s will permanently delete ALL webhooks! ${baseMessage}` + : `${webhooksToDelete.length} webhook/s will be permanently deleted. ${baseMessage}` + ); + if (!yes) { + return; + } + } + + log.addComment(`Deleting ${webhooksToDelete.length} webhook/s.`); + + const { failedWebhooks } = await processWebhooks(webhooksToDelete, log); + + const failedWebhooksMessage = failedWebhooks.length + ? `with ${failedWebhooks.length} failed webhooks - check logs for details` + : ``; + + log.appendLine(`Webhooks delete complete ${failedWebhooksMessage}`); + + await log.close(); +}; diff --git a/src/commands/webhook/export.spec.ts b/src/commands/webhook/export.spec.ts new file mode 100644 index 00000000..db2f4aed --- /dev/null +++ b/src/commands/webhook/export.spec.ts @@ -0,0 +1,164 @@ +import Yargs from 'yargs/yargs'; +import * as exportWebhooksModule from './export'; +import { builder, command, handler, LOG_FILENAME } from './export'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import readline from 'readline'; +import rmdir from 'rimraf'; +import { FileLog } from '../../common/file-log'; +import { Webhook } from 'dc-management-sdk-js'; +import MockPage from '../../common/dc-management-sdk-js/mock-page'; +import { existsSync } from 'fs'; + +jest.mock('readline'); +jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../common/log-helpers'); + +function rimraf(dir: string): Promise { + return new Promise((resolve): void => { + rmdir(dir, resolve); + }); +} + +describe('webhook export command', () => { + afterEach((): void => { + jest.restoreAllMocks(); + }); + + it('should command should defined', function () { + expect(command).toEqual('export '); + }); + + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { + LOG_FILENAME(); + + expect(getDefaultLogPath).toHaveBeenCalledWith('webhook', 'export', process.platform); + }); + + describe('builder tests', function () { + it('should configure yargs', function () { + const argv = Yargs(process.argv.slice(2)); + const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); + const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); + + builder(argv); + + expect(spyPositional).toHaveBeenCalledWith('id', { + type: 'string', + describe: + 'The id of a the webhook to be exported. If id is not provided, this command will export ALL webhooks in the hub.' + }); + + expect(spyPositional).toHaveBeenCalledWith('dir', { + describe: 'Output directory for the exported webhooks', + type: 'string', + requiresArg: true + }); + + expect(spyOption).toHaveBeenCalledWith('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: createLog + }); + }); + }); + + describe('handler tests', function () { + const yargArgs = { + $0: 'test', + _: ['test'], + json: true + }; + const config = { + clientId: 'client-id', + clientSecret: 'client-id', + hubId: 'hub-id', + logFile: new FileLog() + }; + + const webhooksToExport: Webhook[] = [ + new Webhook({ + id: '1', + label: 'WH1', + events: ['dynamic-content.content-item.updated'], + active: true, + handlers: ['https://test.this/webhook'], + secret: 'xxxx', + method: 'POST' + }), + new Webhook({ + id: '2', + label: 'WH2', + events: ['dynamic-content.content-item.updated'], + active: true, + handlers: ['https://test.this/webhook'], + secret: 'xxxx', + method: 'POST' + }) + ]; + + beforeAll(async () => { + await rimraf(`temp_${process.env.JEST_WORKER_ID}/export/`); + }); + + let mockGetHub: jest.Mock; + let mockList: jest.Mock; + + beforeEach((): void => { + const listResponse = new MockPage(Webhook, webhooksToExport); + mockList = jest.fn().mockResolvedValue(listResponse); + + mockGetHub = jest.fn().mockResolvedValue({ + related: { + webhooks: { + list: mockList + } + } + }); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: mockGetHub + } + }); + }); + + it('should export all webhooks to specified directory', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['y']); + + const id: string[] | undefined = undefined; + + const argv = { + ...yargArgs, + ...config, + id, + logFile: new FileLog(), + dir: `temp_${process.env.JEST_WORKER_ID}/export/` + }; + + jest.spyOn(exportWebhooksModule, 'handler'); + await handler(argv); + + expect(mockGetHub).toHaveBeenCalledWith('hub-id'); + expect(mockList).toHaveBeenCalledTimes(1); + expect(mockList).toHaveBeenCalledWith({ size: 100 }); + + const spy = jest.spyOn(exportWebhooksModule, 'exportWebhooks'); + await exportWebhooksModule.exportWebhooks(webhooksToExport, argv.dir, argv.logFile); + + expect(spy).toHaveBeenCalledWith(webhooksToExport, argv.dir, argv.logFile); + + webhooksToExport.forEach(webhook => { + const path = `temp_${process.env.JEST_WORKER_ID}/export/exported_webhooks/${webhook.label}.json`; + + expect(existsSync(path)).toBe(true); + }); + + await rimraf(`temp_${process.env.JEST_WORKER_ID}/export/exported_webhooks/`); + + spy.mockRestore(); + }); + }); +}); diff --git a/src/commands/webhook/export.ts b/src/commands/webhook/export.ts new file mode 100644 index 00000000..781d6918 --- /dev/null +++ b/src/commands/webhook/export.ts @@ -0,0 +1,125 @@ +import { Arguments, Argv } from 'yargs'; +import { ConfigurationParameters } from '../configure'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { nothingExportedExit, uniqueFilenamePath, writeJsonToFile } from '../../services/export.service'; +import { Webhook } from 'dc-management-sdk-js'; +import { FileLog } from '../../common/file-log'; +import { join } from 'path'; +import sanitize from 'sanitize-filename'; +import { ensureDirectoryExists } from '../../common/import/directory-utils'; +import { progressBar } from '../../common/progress-bar/progress-bar'; +import { confirmAllContent } from '../../common/content-item/confirm-all-content'; +import { getWebhooksByIds } from '../../common/webhooks/get-webhooks-by-ids'; +import { getAllWebhooks } from '../../common/webhooks/get-all-webhook'; +import { ExportWebhookBuilderOptions } from '../../interfaces/export-webhook-builder-options'; + +export const command = 'export '; + +export const desc = 'Export Webhooks'; + +export const LOG_FILENAME = (platform: string = process.platform): string => + getDefaultLogPath('webhook', 'export', platform); + +export const builder = (yargs: Argv): void => { + yargs + .positional('id', { + type: 'string', + describe: + 'The id of a the webhook to be exported. If id is not provided, this command will export ALL webhooks in the hub.' + }) + .positional('dir', { + describe: 'Output directory for the exported webhooks', + type: 'string', + requiresArg: true + }) + .option('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: createLog + }) + .alias('f', 'force') + .option('f', { + type: 'boolean', + boolean: true, + describe: 'If present, there will be no confirmation prompt before exporting the webhooks.' + }) + .alias('s', 'silent') + .option('s', { + type: 'boolean', + boolean: true, + describe: 'If present, no log file will be produced.' + }); +}; + +export const exportWebhooks = async (webhooks: Webhook[], dir: string, log: FileLog): Promise => { + const progress = progressBar(webhooks.length, 0, { + title: `Exporting ${webhooks.length} webhooks.` + }); + + const filenames: string[] = []; + + for (let i = 0; i < webhooks.length; i++) { + const webhook = webhooks[i]; + + try { + let resolvedPath: string; + resolvedPath = 'exported_webhooks'; + + const directory = join(dir, resolvedPath); + resolvedPath = uniqueFilenamePath(directory, `${sanitize(webhook.label as string)}`, 'json', filenames); + filenames.push(resolvedPath); + + await ensureDirectoryExists(directory); + + writeJsonToFile(resolvedPath, webhook); + log.addComment(`Successfully exported "${webhook.label}"`); + progress.increment(); + } catch (e) { + log.addComment(`Failed to export ${webhook.label}: ${e.toString()}`); + progress.increment(); + } + } + + progress.stop(); +}; + +export const handler = async ( + argv: Arguments +): Promise => { + const { id, logFile, dir, force, silent } = argv; + const log = logFile.open(); + const client = dynamicContentClientFactory(argv); + const allWebhooks = !id; + const hub = await client.hubs.get(argv.hubId); + let ids: string[] = []; + + if (id) { + ids = Array.isArray(id) ? id : [id]; + } + + const webhooksToExport = ids.length > 0 ? await getWebhooksByIds(hub, ids) : await getAllWebhooks(hub); + + if (!webhooksToExport.length) { + nothingExportedExit(log, 'No webhooks to export from this hub, exiting.'); + return; + } + + log.appendLine(`Found ${webhooksToExport.length} webhooks to export`); + + if (!force) { + const yes = await confirmAllContent('export', 'webhooks', allWebhooks, false); + if (!yes) { + return; + } + } + + log.appendLine(`Exporting ${webhooksToExport.length} webhooks.`); + + await exportWebhooks(webhooksToExport, dir, log); + + log.appendLine(`Finished successfully exporting ${webhooksToExport.length} webhooks`); + + await log.close(!silent); +}; diff --git a/src/commands/webhook/import.spec.ts b/src/commands/webhook/import.spec.ts new file mode 100644 index 00000000..9aaca261 --- /dev/null +++ b/src/commands/webhook/import.spec.ts @@ -0,0 +1,231 @@ +import { builder, command, getDefaultMappingPath, handler, LOG_FILENAME } from './import'; +import * as importModule from './import'; +import { Hub, Webhook } from 'dc-management-sdk-js'; +import Yargs from 'yargs/yargs'; +import rmdir from 'rimraf'; +import { FileLog } from '../../common/file-log'; +import { ContentMapping } from '../../common/content-mapping'; +import { mockValues } from './webhook-test-helpers'; +import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { ensureDirectoryExists } from '../../common/import/directory-utils'; +import { exportWebhooks } from './export'; +import readline from 'readline'; + +jest.mock('../../services/dynamic-content-client-factory'); +jest.mock('../../services/import.service'); +jest.mock('readline'); + +jest.mock('../../common/log-helpers', () => ({ + ...jest.requireActual('../../common/log-helpers'), + getDefaultLogPath: jest.fn() +})); + +function rimraf(dir: string): Promise { + return new Promise((resolve): void => { + rmdir(dir, resolve); + }); +} + +describe('webhook import command', () => { + afterEach((): void => { + jest.restoreAllMocks(); + }); + + it('should command should defined', function () { + expect(command).toEqual('import '); + }); + + it('should use getDefaultLogPath for LOG_FILENAME with process.platform as default', function () { + LOG_FILENAME(); + + expect(getDefaultLogPath).toHaveBeenCalledWith('webhook', 'import', process.platform); + }); + + it('should generate a default mapping path containing the given name', function () { + expect(getDefaultMappingPath('hub-1').indexOf('hub-1')).not.toEqual(-1); + }); + + describe('builder tests', function () { + it('should configure yargs', function () { + const argv = Yargs(process.argv.slice(2)); + const spyPositional = jest.spyOn(argv, 'positional').mockReturnThis(); + const spyOption = jest.spyOn(argv, 'option').mockReturnThis(); + + builder(argv); + + expect(spyPositional).toHaveBeenCalledWith('dir', { + describe: 'Directory containing webhooks to import.', + type: 'string', + requiresArg: true + }); + + expect(spyOption).toHaveBeenCalledWith('mapFile', { + type: 'string', + describe: + 'Mapping file to use when updating webhooks that already exists. Updated with any new mappings that are generated. If not present, will be created.' + }); + + expect(spyOption).toHaveBeenCalledWith('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: createLog + }); + + expect(spyOption).toHaveBeenCalledWith('f', { + type: 'boolean', + boolean: true, + describe: 'Overwrite webhooks.' + }); + + expect(spyOption).toHaveBeenCalledWith('s', { + type: 'boolean', + boolean: true, + describe: 'If present, no log file will be produced.' + }); + }); + }); + + describe('handler tests', function () { + beforeAll(async () => { + await rimraf(`temp_${process.env.JEST_WORKER_ID}/importWebhook/`); + }); + + afterAll(async () => { + await rimraf(`temp_${process.env.JEST_WORKER_ID}/importWebhook/`); + }); + + it('should call importWebhooks with the loaded webhook, then save the mapping', async function () { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['y']); + + const { getHubMock } = mockValues({}); + const logFile = new FileLog(); + + const yargArgs = { + $0: 'test', + _: ['test'], + json: true + }; + const config = { + clientId: 'client-id', + clientSecret: 'client-id', + hubId: 'hub-1', + logFile + }; + + const webhookObj = { + id: '1', + label: 'WH1', + events: ['dynamic-content.content-item.updated'], + active: true, + handlers: ['https://test.this/webhook'], + method: 'POST' + }; + + const webhooks = [new Webhook(webhookObj)]; + + await exportWebhooks(webhooks, `temp_${process.env.JEST_WORKER_ID}/importWebhook/`, logFile); + + const importWebhooks = jest.spyOn(importModule, 'importWebhooks').mockResolvedValue(); + const trySaveMapping = jest.spyOn(importModule, 'trySaveMapping').mockResolvedValue(); + + const getDefaultMappingPathSpy = jest.spyOn(importModule, 'getDefaultMappingPath'); + const mappingPath = importModule.getDefaultMappingPath('hub-1'); + + const argv = { + ...yargArgs, + ...config, + dir: `temp_${process.env.JEST_WORKER_ID}/importWebhook/exported_webhooks` + }; + + await handler(argv); + + expect(getHubMock).toHaveBeenCalledWith('hub-1'); + + expect(importWebhooks).toHaveBeenCalledWith( + expect.any(Hub), + expect.arrayContaining([expect.objectContaining(webhookObj)]), + expect.any(ContentMapping), + logFile + ); + + expect(getDefaultMappingPathSpy).toHaveBeenCalledWith('hub-1'); + + expect(trySaveMapping).toHaveBeenCalledWith( + expect.stringContaining('hub-1.json'), + expect.any(ContentMapping), + logFile + ); + expect(logFile.closed).toBeTruthy(); + + rimraf(mappingPath); + }); + + it('should load an existing mapping file', async function () { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (readline as any).setResponses(['y']); + + const { getHubMock } = mockValues({}); + const logFile = new FileLog(); + + const yargArgs = { + $0: 'test', + _: ['test'], + json: true + }; + const config = { + clientId: 'client-id', + clientSecret: 'client-id', + hubId: 'hub-1', + logFile + }; + + const webhookObj = { + id: '1', + label: 'WH1', + events: ['dynamic-content.content-item.updated'], + active: true, + handlers: ['https://test.this/webhook'], + method: 'POST' + }; + + const webhooks = [new Webhook(webhookObj)]; + + await exportWebhooks(webhooks, `temp_${process.env.JEST_WORKER_ID}/importWebhook/`, logFile); + + const argv = { + ...yargArgs, + ...config, + logFile, + mapFile: `temp_${process.env.JEST_WORKER_ID}/importWebhook/hub-1(existing-mapping).json`, + dir: `temp_${process.env.JEST_WORKER_ID}/importWebhook/exported_webhooks` + }; + + const importWebhooks = jest.spyOn(importModule, 'importWebhooks').mockResolvedValue(); + const trySaveMapping = jest.spyOn(importModule, 'trySaveMapping').mockResolvedValue(); + + const getDefaultMappingPathSpy = jest.spyOn(importModule, 'getDefaultMappingPath'); + + await ensureDirectoryExists(`temp_${process.env.JEST_WORKER_ID}/importWebhook/`); + + const existingMapping = new ContentMapping(); + await existingMapping.save(argv.mapFile); + + await handler(argv); + + expect(getHubMock).toHaveBeenCalledWith('hub-1'); + + expect(importWebhooks).toHaveBeenCalledWith( + expect.any(Hub), + expect.arrayContaining([expect.objectContaining(webhookObj)]), + expect.any(ContentMapping), + logFile + ); + + expect(getDefaultMappingPathSpy).not.toHaveBeenCalled(); + expect(trySaveMapping).toHaveBeenCalledWith(argv.mapFile, expect.any(ContentMapping), logFile); + expect(logFile.closed).toBeTruthy(); + }); + }); +}); diff --git a/src/commands/webhook/import.ts b/src/commands/webhook/import.ts new file mode 100644 index 00000000..11cdeda5 --- /dev/null +++ b/src/commands/webhook/import.ts @@ -0,0 +1,267 @@ +import { Arguments, Argv } from 'yargs'; +import { ConfigurationParameters } from '../configure'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import { FileLog } from '../../common/file-log'; +import { join, extname } from 'path'; +import { readdir, readFile } from 'graceful-fs'; +import { promisify } from 'util'; +import { Hub, Webhook } from 'dc-management-sdk-js'; +import { ContentMapping } from '../../common/content-mapping'; +import { createLog, getDefaultLogPath } from '../../common/log-helpers'; +import { asyncQuestion } from '../../common/question-helpers'; +import { progressBar } from '../../common/progress-bar/progress-bar'; +import PublishOptions from '../../common/publish/publish-options'; +import { ImportWebhookBuilderOptions } from '../../interfaces/import-webhook-builder-options'; + +export function getDefaultMappingPath(name: string, platform: string = process.platform): string { + return join( + process.env[platform == 'win32' ? 'USERPROFILE' : 'HOME'] || __dirname, + '.amplience', + `imports/`, + `${name}.json` + ); +} + +export const command = 'import '; + +export const desc = 'Import Webhooks'; + +export const LOG_FILENAME = (platform: string = process.platform): string => + getDefaultLogPath('webhook', 'import', platform); + +export const builder = (yargs: Argv): void => { + yargs + .positional('dir', { + describe: 'Directory containing webhooks to import.', + type: 'string', + requiresArg: true + }) + .option('mapFile', { + type: 'string', + describe: + 'Mapping file to use when updating webhooks that already exists. Updated with any new mappings that are generated. If not present, will be created.' + }) + .option('logFile', { + type: 'string', + default: LOG_FILENAME, + describe: 'Path to a log file to write to.', + coerce: createLog + }) + .alias('f', 'force') + .option('f', { + type: 'boolean', + boolean: true, + describe: 'Overwrite webhooks.' + }) + .alias('s', 'silent') + .option('s', { + type: 'boolean', + boolean: true, + describe: 'If present, no log file will be produced.' + }); +}; + +interface WebhookImportResult { + webhook: Webhook; + state: 'UPDATED' | 'CREATED'; +} + +export const createOrUpdateWebhook = async ( + hub: Hub, + item: Webhook, + existing: string | Webhook | null +): Promise => { + let oldItem: Webhook | null = null; + if (typeof existing === 'string') { + oldItem = await hub.related.webhooks.get(existing); + } else { + oldItem = existing; + } + + let result: WebhookImportResult; + + if (oldItem == null) { + result = { webhook: await hub.related.webhooks.create(item), state: 'CREATED' }; + } else { + result = { webhook: await oldItem.related.update(item), state: 'UPDATED' }; + } + + return result; +}; + +export const trySaveMapping = async ( + mapFile: string | undefined, + mapping: ContentMapping, + log: FileLog +): Promise => { + if (mapFile != null) { + try { + await mapping.save(mapFile); + } catch (e) { + log.appendLine(`Failed to save the mapping. ${e.toString()}`); + } + } +}; + +export const prepareWebhooksForImport = async ( + hub: Hub, + webhookFiles: string[], + mapping: ContentMapping, + log: FileLog, + argv: Arguments +): Promise => { + const { force } = argv; + + let webhooks: Webhook[] = []; + + for (const webhookFile of webhookFiles) { + log.appendLine(`Reading webhook data in '${webhookFile}' for hub '${hub.label}'...`); + + if (extname(webhookFile) !== '.json') { + return null; + } + + let webhookJSON; + + try { + const webhookText = await promisify(readFile)(webhookFile, { + encoding: 'utf8' + }); + + webhookJSON = JSON.parse(webhookText); + } catch (e) { + log.appendLine(`Couldn't read webhook at '${webhookFile}': ${e.toString()}`); + return null; + } + + const webhook = new Webhook({ + ...(webhookJSON.id && { id: webhookJSON.id }), + ...(webhookJSON.label && { label: webhookJSON.label }), + ...(webhookJSON.events && { events: webhookJSON.events }), + ...(webhookJSON.active && { active: webhookJSON.active }), + ...(webhookJSON.handlers && { handlers: webhookJSON.handlers }), + ...(webhookJSON.notifications && { notifications: webhookJSON.notifications }), + ...(webhookJSON.headers && { headers: webhookJSON.headers }), + ...(webhookJSON.filters && { filters: webhookJSON.filters }), + ...(webhookJSON.customPayload && { customPayload: webhookJSON.customPayload }), + ...(webhookJSON.method && { method: webhookJSON.method }) + }); + + if (webhook?.headers) { + webhook.headers = webhook.headers.filter(header => { + return !header.secret; + }); + } + + if (webhook?.customPayload?.value) { + webhook.customPayload.value = webhook.customPayload.value + .replace(/account="([^"]*)"/g, `account="${hub.name}"`) + .replace( + /stagingEnvironment="([^"]*)"/g, + `stagingEnvironment="${hub.settings?.virtualStagingEnvironment?.hostname}"` + ); + } + + webhooks.push(new Webhook(webhook)); + } + + const alreadyExists = webhooks.filter(item => mapping.getWebhook(item.id) != null); + if (alreadyExists.length > 0) { + const updateExisting = + force || + (await asyncQuestion( + `${alreadyExists.length} of the webhooks being imported already exist in the mapping. Would you like to update these webhooks instead of skipping them? (y/n) `, + log + )); + + if (!updateExisting) { + webhooks = webhooks.filter(item => mapping.getWebhook(item.id) == null); + } + } + + return webhooks; +}; + +export const importWebhooks = async ( + hub: Hub, + webhooks: Webhook[], + mapping: ContentMapping, + log: FileLog +): Promise => { + const importProgress = progressBar(webhooks.length, 0, { + title: 'Importing webhooks' + }); + + for (const webhookToImport of webhooks) { + const originalId = webhookToImport.id; + webhookToImport.id = mapping.getWebhook(webhookToImport.id as string) || ''; + + if (!webhookToImport.id) { + delete webhookToImport.id; + } + + try { + const { webhook, state } = await createOrUpdateWebhook( + hub, + webhookToImport, + mapping.getWebhook(originalId as string) || null + ); + + log.addComment(`${state} ${webhook.label}.`); + log.addAction(state, (webhook.id || 'unknown') + (state === 'UPDATED' ? ` ${webhook.label}` : '')); + + mapping.registerWebhook(originalId as string, webhook.id as string); + + importProgress.increment(); + } catch (e) { + importProgress.stop(); + log.error(`Failed creating ${webhookToImport.label}:`, e); + throw Error(`Importing webhook failed. Error: ${e.toString()}`); + } + } + + importProgress.stop(); +}; + +export const handler = async ( + argv: Arguments +): Promise => { + const { dir, logFile, force, silent, mapFile: mapFileArg } = argv; + const client = dynamicContentClientFactory(argv); + const log = logFile.open(); + const hub: Hub = await client.hubs.get(argv.hubId); + const importTitle = `hub-${hub.id}`; + const mapping = new ContentMapping(); + const mapFile = mapFileArg ? mapFileArg : getDefaultMappingPath(importTitle); + + if (await mapping.load(mapFile)) { + log.appendLine(`Existing mapping loaded from '${mapFile}', changes will be saved back to it.`); + } else { + log.appendLine(`Creating new mapping file at '${mapFile}'.`); + } + + const baseDirContents = await promisify(readdir)(dir); + + const webhookFiles = baseDirContents.map(wh => { + return `${dir}/${wh}`; + }); + + const webhooks = await prepareWebhooksForImport(hub, webhookFiles, mapping, log, argv); + + if (webhooks !== null) { + const proceedImport = + force || + (await asyncQuestion(`${webhooks.length} webhook/s will be imported, do you wish to continue? (y/n) `, log)); + if (!proceedImport) { + return; + } + + await importWebhooks(hub, webhooks, mapping, log); + } else { + log.appendLine('No webhooks found to import.'); + } + + trySaveMapping(mapFile, mapping, log); + + await log.close(!silent); +}; diff --git a/src/commands/webhook/webhook-test-helpers.ts b/src/commands/webhook/webhook-test-helpers.ts new file mode 100644 index 00000000..de9db462 --- /dev/null +++ b/src/commands/webhook/webhook-test-helpers.ts @@ -0,0 +1,103 @@ +import { Hub, Webhook } from 'dc-management-sdk-js'; +import MockPage from '../../common/dc-management-sdk-js/mock-page'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; + +export const mockValues = ({ + getHubError = false, + getWebhookError = false, + listWebhookError = false +}): { + mockGet: () => void; + getHubMock: () => void; + mockWebhooksList: () => void; + mockWebhookUpdate: () => void; + mockWebhookCreate: () => void; +} => { + const mockGet = jest.fn(); + const getHubMock = jest.fn(); + const mockWebhooksList = jest.fn(); + const mockWebhookUpdate = jest.fn(); + const mockWebhookCreate = jest.fn(); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + hubs: { + get: getHubMock + }, + webhooks: { + get: mockGet + } + }); + + const hub = new Hub({ + name: '1', + id: '1', + _links: { + webhooks: { + href: 'https://api.amplience.net/v2/content/webhooks', + templated: true + } + } + }); + + getHubMock.mockResolvedValue(hub); + + hub.related.webhooks.list = mockWebhooksList; + hub.related.webhooks.create = mockWebhookCreate; + + const webhooks = [ + new Webhook({ + id: '1', + label: 'WH1', + events: ['dynamic-content.content-item.updated'], + active: true, + handlers: ['https://test.this/webhook'], + secret: 'xxxx', + method: 'POST' + }), + new Webhook({ + id: '2', + label: 'WH2', + events: ['dynamic-content.content-item.updated'], + active: true, + handlers: ['https://test.this/webhook'], + secret: 'xxxx', + method: 'POST' + }) + ]; + + mockWebhooksList.mockResolvedValue(new MockPage(Webhook, webhooks)); + + const webhook = new Webhook({ + id: '1', + label: 'WH1', + events: ['dynamic-content.content-item.updated'], + active: true, + handlers: ['https://test.this/webhook'], + secret: 'xxxx', + method: 'POST' + }); + + mockGet.mockResolvedValue(webhook); + + webhook.related.update = mockWebhookUpdate; + + if (getHubError) { + getHubMock.mockRejectedValue(new Error('Error')); + } + + if (getWebhookError) { + mockGet.mockRejectedValue(new Error('Error')); + } + + if (listWebhookError) { + mockWebhooksList.mockRejectedValue(new Error('Error')); + } + + return { + mockGet, + getHubMock, + mockWebhooksList, + mockWebhookUpdate, + mockWebhookCreate + }; +}; diff --git a/src/common/archive/archive-options.ts b/src/common/archive/archive-options.ts index 06aa0496..35736fa8 100644 --- a/src/common/archive/archive-options.ts +++ b/src/common/archive/archive-options.ts @@ -7,9 +7,9 @@ export default interface ArchiveOptions { repoId?: string | string[]; folderId?: string | string[]; facet?: string; - logFile: FileLog; force?: boolean; silent?: boolean; ignoreError?: boolean; + ignoreSchemaValidation?: boolean; } diff --git a/src/common/archive/content-item-unarchive-options.ts b/src/common/archive/content-item-unarchive-options.ts new file mode 100644 index 00000000..f42f9ef4 --- /dev/null +++ b/src/common/archive/content-item-unarchive-options.ts @@ -0,0 +1,15 @@ +import { FileLog } from '../file-log'; + +export default interface ContentItemUnarchiveOptions { + id?: string; + schemaId?: string | string[]; + repoId?: string | string[]; + folderId?: string | string[]; + revertLog?: string; + facet?: string; + logFile: FileLog; + force?: boolean; + silent?: boolean; + ignoreError?: boolean; + ignoreSchemaValidation?: boolean; +} diff --git a/src/common/archive/unarchive-options.ts b/src/common/archive/unarchive-options.ts index a0b87206..187e795e 100644 --- a/src/common/archive/unarchive-options.ts +++ b/src/common/archive/unarchive-options.ts @@ -4,11 +4,10 @@ export default interface UnarchiveOptions { repoId?: string | string[]; folderId?: string | string[]; revertLog?: string; - facet?: string; - logFile?: string; force?: boolean; silent?: boolean; ignoreError?: boolean; + ignoreSchemaValidation?: boolean; } diff --git a/src/common/burstable-queue/burstable-queue.spec.ts b/src/common/burstable-queue/burstable-queue.spec.ts new file mode 100644 index 00000000..6802cdf8 --- /dev/null +++ b/src/common/burstable-queue/burstable-queue.spec.ts @@ -0,0 +1,159 @@ +import { BurstableQueue } from './burstable-queue'; +import { setTimeout } from 'node:timers/promises'; + +describe('burstable-queue', () => { + it('should schedule task and execute them with an initial burst', async () => { + const interval = 500; + const timeoutInterval = interval + 10; + const burstableQueue = new BurstableQueue({ + concurrency: 1, + minTime: 0, + burstIntervalCap: 4, + sustainedIntervalCap: 1, + interval + }); + const tasks = [...Array.from({ length: 8 }).keys()]; + const completeTasks: number[] = []; + + for (const task of tasks) { + burstableQueue.add(async () => { + await setTimeout(50); + completeTasks.push(task); + }); + } + + expect(burstableQueue.size()).toEqual(8); + expect(completeTasks).toHaveLength(0); + await setTimeout(timeoutInterval); + expect(burstableQueue.size()).toEqual(4); + expect(completeTasks).toHaveLength(4); + await setTimeout(timeoutInterval); + expect(burstableQueue.size()).toEqual(3); + expect(completeTasks).toHaveLength(5); + await setTimeout(timeoutInterval); + expect(burstableQueue.size()).toEqual(2); + expect(completeTasks).toHaveLength(6); + await setTimeout(timeoutInterval); + expect(burstableQueue.size()).toEqual(1); + expect(completeTasks).toHaveLength(7); + await setTimeout(timeoutInterval); + expect(burstableQueue.size()).toEqual(0); + expect(completeTasks).toHaveLength(8); + }); + + describe('add', () => { + it('should add a task to the queue', () => { + const burstableQueue = new BurstableQueue({}); + burstableQueue.add(async () => { + await setTimeout(50); + }); + expect(burstableQueue.size()).toEqual(1); + }); + }); + + describe('onIdle', () => { + it('should wait until the the queue is idle (queue is empty and all tasks executed)', async () => { + const burstableQueue = new BurstableQueue({ + concurrency: 1, + minTime: 0, + burstIntervalCap: 4, + sustainedIntervalCap: 1, + interval: 400 + }); + const tasks = [...Array.from({ length: 8 }).keys()]; + const completeTasks: number[] = []; + + for (const task of tasks) { + burstableQueue.add(async () => { + await setTimeout(50); + completeTasks.push(task); + }); + } + + await burstableQueue.onIdle(); + + expect(burstableQueue.size()).toEqual(0); + expect(completeTasks).toHaveLength(8); + }); + }); + describe('size()', () => { + it('should return the size of the queue (queued and executing) - all queued', () => { + const burstableQueue = new BurstableQueue({ + concurrency: 1, + minTime: 0, + burstIntervalCap: 4, + sustainedIntervalCap: 1, + interval: 400 + }); + const tasks = [...Array.from({ length: 8 }).keys()]; + + tasks.forEach(() => { + burstableQueue.add(async () => { + await setTimeout(50); + }); + }); + + expect(burstableQueue.size()).toEqual(8); + }); + it('should return the size of the queue (queued and executing) - queue task in flight', async () => { + const burstableQueue = new BurstableQueue({ + concurrency: 1, + minTime: 0, + burstIntervalCap: 4, + sustainedIntervalCap: 1, + interval: 400 + }); + const tasks = [...Array.from({ length: 8 }).keys()]; + + tasks.forEach(() => { + burstableQueue.add(async () => { + await setTimeout(1); + }); + }); + + expect(burstableQueue.size()).toEqual(8); + await setTimeout(410); + expect(burstableQueue.size()).toEqual(4); + }); + }); + describe('pending()', () => { + it('should return the number of pending queue items (queued, not executing)', () => { + const burstableQueue = new BurstableQueue({ + concurrency: 1, + minTime: 0, + burstIntervalCap: 4, + sustainedIntervalCap: 1, + interval: 400 + }); + const tasks = [...Array.from({ length: 8 }).keys()]; + + tasks.forEach(() => { + burstableQueue.add(async () => { + await setTimeout(50); + }); + }); + + expect(burstableQueue.pending()).toEqual(8); + }); + it('should return the number of pending queue items (queued, not executing) - queue task in flight', async () => { + const burstableQueue = new BurstableQueue({ + concurrency: 1, + minTime: 0, + burstIntervalCap: 4, + sustainedIntervalCap: 1, + interval: 400 + }); + const tasks = [...Array.from({ length: 8 }).keys()]; + + tasks.forEach(() => { + burstableQueue.add(async () => { + await setTimeout(1); + }); + }); + + expect(burstableQueue.pending()).toEqual(8); + await setTimeout(410); + expect(burstableQueue.pending()).toEqual(4); + }); + }); +}); diff --git a/src/common/burstable-queue/burstable-queue.ts b/src/common/burstable-queue/burstable-queue.ts new file mode 100644 index 00000000..45ab3566 --- /dev/null +++ b/src/common/burstable-queue/burstable-queue.ts @@ -0,0 +1,55 @@ +import Bottleneck from 'bottleneck'; + +export const CONCURRENCY = 4; +export const MIN_TIME = 800; +export const INITIAL_RESERVOIR = 70; +export const RESERVOIR_REFRESH_AMOUNT = 30; +export const RESERVOIR_INCREASE_INTERVAL = 60_000; + +export interface BurstableQueueOptions { + concurrency?: number; + minTime?: number; + burstIntervalCap?: number; + sustainedIntervalCap?: number; + interval?: number; +} + +export class BurstableQueue { + private queue; + + constructor(options: BurstableQueueOptions) { + this.queue = new Bottleneck({ + maxConcurrent: options.concurrency || CONCURRENCY, + minTime: options.minTime ?? MIN_TIME, + reservoir: options.burstIntervalCap || INITIAL_RESERVOIR, // initial value + reservoirRefreshAmount: options.sustainedIntervalCap || RESERVOIR_REFRESH_AMOUNT, + reservoirRefreshInterval: options.interval || RESERVOIR_INCREASE_INTERVAL + }); + } + + size(): number { + const { RECEIVED, QUEUED, RUNNING, EXECUTING } = this.queue.counts(); + return RECEIVED + QUEUED + RUNNING + EXECUTING; + } + + pending(): number { + const { RECEIVED, QUEUED } = this.queue.counts(); + return RECEIVED + QUEUED; + } + + async onIdle(): Promise { + if (this.size() === 0) { + return; + } + + return new Promise(resolve => { + this.queue.on('idle', () => { + resolve(); + }); + }); + } + + async add(fn: () => Promise): Promise { + return this.queue.schedule(fn); + } +} diff --git a/src/common/ch-api/ContentHub.mocks.ts b/src/common/ch-api/ContentHub.mocks.ts index cc9b5a06..0c1c7e2e 100644 --- a/src/common/ch-api/ContentHub.mocks.ts +++ b/src/common/ch-api/ContentHub.mocks.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/camelcase */ -/* eslint-disable @typescript-eslint/no-unused-vars */ import { AxiosRequestConfig } from 'axios'; import { ContentHub, ContentHubConfig } from './ContentHub'; import { ApiClient } from './api/services/ApiClient'; diff --git a/src/common/ch-api/ContentHub.spec.ts b/src/common/ch-api/ContentHub.spec.ts index b3ff0ee1..d88f1e63 100644 --- a/src/common/ch-api/ContentHub.spec.ts +++ b/src/common/ch-api/ContentHub.spec.ts @@ -5,7 +5,6 @@ describe('ContentHub tests', () => { it('should use the http client given to the constructor', async () => { const httpClient = new AxiosHttpClient({}); - // eslint-disable-next-line @typescript-eslint/camelcase const ch = new ContentHub({ client_id: '', client_secret: '' }, undefined, httpClient); // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/src/common/ch-api/api/services/ApiClient.ts b/src/common/ch-api/api/services/ApiClient.ts index dd07f420..b4911618 100644 --- a/src/common/ch-api/api/services/ApiClient.ts +++ b/src/common/ch-api/api/services/ApiClient.ts @@ -40,7 +40,11 @@ export interface ApiParameters { export class DefaultApiClient implements ApiClient { endpoints: ApiEndpoints; - constructor(private baseUrl: string, private httpClient: HttpClient, private tokenProvider: AccessTokenProvider) { + constructor( + private baseUrl: string, + private httpClient: HttpClient, + private tokenProvider: AccessTokenProvider + ) { this.endpoints = new ApiEndpoints(this); } @@ -52,7 +56,7 @@ export class DefaultApiClient implements ApiClient { method: HttpMethod.GET, url: path }); - return (response.data as any) as T; + return response.data as any as T; } public async fetchResource( @@ -101,11 +105,10 @@ export class DefaultApiClient implements ApiClient { response.data = this.transformDamResponse(response.data); return response; } else { - throw new HttpError( - `Request failed with status code ${response.status}: ${JSON.stringify(response.data)}`, - fullRequest, - response - ); + const message = response.status + ? `Request failed with status code ${response.status}: ${JSON.stringify(response.data)}` + : `Error: No response from server - check your network connection.`; + throw new HttpError(message, fullRequest, response); } }); } diff --git a/src/common/ch-api/http/AxiosHttpClient.spec.ts b/src/common/ch-api/http/AxiosHttpClient.spec.ts index cf862021..78f78cb2 100644 --- a/src/common/ch-api/http/AxiosHttpClient.spec.ts +++ b/src/common/ch-api/http/AxiosHttpClient.spec.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/camelcase */ import { AxiosHttpClient } from './AxiosHttpClient'; import { HttpMethod } from './HttpRequest'; @@ -104,4 +103,82 @@ describe('AxiosHttpClient tests', () => { expect(response.status).toEqual(200); }); + + test('client should retry then succeed when first error has 5xx status', async () => { + const client = new AxiosHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').replyOnce(500).onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(2); + }); + + test('client should retry then succeed when first error has 429 status', async () => { + const client = new AxiosHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').replyOnce(429).onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(2); + }); + + test('client should retry then succeed when first error is a network error', async () => { + const client = new AxiosHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').networkErrorOnce().onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(2); + }); + + test('client should retry then fail after 3 retries', async () => { + const client = new AxiosHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').reply(500); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(500); + expect(mock.history.get.length).toBe(4); + }); }); diff --git a/src/common/ch-api/http/AxiosHttpClient.ts b/src/common/ch-api/http/AxiosHttpClient.ts index 303a616f..6171fbc8 100644 --- a/src/common/ch-api/http/AxiosHttpClient.ts +++ b/src/common/ch-api/http/AxiosHttpClient.ts @@ -1,8 +1,16 @@ -import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'; +import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios'; import { HttpClient } from './HttpClient'; import { HttpRequest } from './HttpRequest'; import { HttpResponse } from './HttpResponse'; +import axiosRetry, { isNetworkOrIdempotentRequestError } from 'axios-retry'; + +const DEFAULT_RETRY_CONFIG = { + retries: 3, + retryDelay: axiosRetry.exponentialDelay, + retryCondition: async (error: AxiosError) => + isNetworkOrIdempotentRequestError(error) || Boolean(error && error.response && error.response.status === 429) +}; /** * @hidden @@ -12,6 +20,7 @@ export class AxiosHttpClient implements HttpClient { constructor(private config: AxiosRequestConfig) { this.client = axios.create(config); + axiosRetry(this.client, DEFAULT_RETRY_CONFIG); } public request(config: HttpRequest): Promise { diff --git a/src/common/ch-api/http/HttpError.ts b/src/common/ch-api/http/HttpError.ts index 685c0565..f141cec8 100644 --- a/src/common/ch-api/http/HttpError.ts +++ b/src/common/ch-api/http/HttpError.ts @@ -2,7 +2,11 @@ import { HttpRequest } from './HttpRequest'; import { HttpResponse } from './HttpResponse'; export class HttpError extends Error { - constructor(message: string, public readonly request?: HttpRequest, public readonly response?: HttpResponse) { + constructor( + message: string, + public readonly request?: HttpRequest, + public readonly response?: HttpResponse + ) { super(message); Object.setPrototypeOf(this, new.target.prototype); } diff --git a/src/common/ch-api/oauth2/models/OAuth2ClientCredentials.ts b/src/common/ch-api/oauth2/models/OAuth2ClientCredentials.ts index 23ad6652..024a5341 100644 --- a/src/common/ch-api/oauth2/models/OAuth2ClientCredentials.ts +++ b/src/common/ch-api/oauth2/models/OAuth2ClientCredentials.ts @@ -5,10 +5,10 @@ export interface OAuth2ClientCredentials { /** * Client id */ - client_id: string; + client_id?: string; /** * Client secret */ - client_secret: string; + client_secret?: string; } diff --git a/src/common/ch-api/oauth2/services/OAuth2Client.spec.ts b/src/common/ch-api/oauth2/services/OAuth2Client.spec.ts index b92b5300..a31dbca3 100644 --- a/src/common/ch-api/oauth2/services/OAuth2Client.spec.ts +++ b/src/common/ch-api/oauth2/services/OAuth2Client.spec.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/camelcase */ import { AxiosHttpClient } from '../../http/AxiosHttpClient'; import { OAuth2Client } from './OAuth2Client'; diff --git a/src/common/ch-api/oauth2/services/OAuth2Client.ts b/src/common/ch-api/oauth2/services/OAuth2Client.ts index 16772d15..94e32e26 100644 --- a/src/common/ch-api/oauth2/services/OAuth2Client.ts +++ b/src/common/ch-api/oauth2/services/OAuth2Client.ts @@ -43,24 +43,24 @@ export class OAuth2Client implements AccessTokenProvider { return this.token; } - const payload = - 'grant_type=client_credentials' + - '&client_id=' + - encodeURIComponent(this.clientCredentials.client_id) + - '&client_secret=' + - encodeURIComponent(this.clientCredentials.client_secret); + if (this.clientCredentials.client_id && this.clientCredentials.client_secret) { + const payload = + 'grant_type=client_credentials' + + '&client_id=' + + encodeURIComponent(this.clientCredentials.client_id) + + '&client_secret=' + + encodeURIComponent(this.clientCredentials.client_secret); - const request = this.httpClient.request({ - data: payload, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - }, - method: HttpMethod.POST, - url: combineURLs(this.authUrl, '/oauth/token') - }); + const request = this.httpClient.request({ + data: payload, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + method: HttpMethod.POST, + url: combineURLs(this.authUrl, '/oauth/token') + }); - this.inFlight = request.then( - (response): AccessToken => { + this.inFlight = request.then((response): AccessToken => { if (typeof response.data !== 'object') { throw new Error('Unexpected response format from /oauth/token endpoint'); } @@ -72,13 +72,15 @@ export class OAuth2Client implements AccessTokenProvider { throw new Error(`Authorization failed (${response.status}): ${responseText}`); } - this.token = (response.data as unknown) as AccessToken; + this.token = response.data as unknown as AccessToken; this.tokenExpires = Date.now() + this.token.expires_in * 1000; this.inFlight = undefined; return this.token; - } - ) as Promise; + }) as Promise; - return this.inFlight; + return this.inFlight; + } else { + throw new Error('Client credentials not set'); + } } } diff --git a/src/common/content-item/body.ts b/src/common/content-item/body.ts index f96be57a..6439f150 100644 --- a/src/common/content-item/body.ts +++ b/src/common/content-item/body.ts @@ -13,4 +13,5 @@ interface ContentMeta { name: string; schema: string; deliveryKey?: string; + deliveryKeys?: string; } diff --git a/src/common/archive/archive-helpers.ts b/src/common/content-item/confirm-all-content.ts similarity index 62% rename from src/common/archive/archive-helpers.ts rename to src/common/content-item/confirm-all-content.ts index 6ee558c5..d5b6c88b 100644 --- a/src/common/archive/archive-helpers.ts +++ b/src/common/content-item/confirm-all-content.ts @@ -1,6 +1,6 @@ import { asyncQuestion } from '../question-helpers'; -export async function confirmArchive( +export async function confirmAllContent( action: string, type: string, allContent: boolean, @@ -9,8 +9,8 @@ export async function confirmArchive( const question = allContent ? `Providing no ID or filter will ${action} ALL ${type}! Are you sure you want to do this? (y/n)\n` : missingContent - ? 'Warning: Some content specified on the log is missing. Are you sure you want to continue? (y/n)\n' - : `Are you sure you want to ${action} these ${type}? (y/n)\n`; + ? 'Warning: Some content specified on the log is missing. Are you sure you want to continue? (y/n)\n' + : `Are you sure you want to ${action} these ${type}? (y/n)\n`; return await asyncQuestion(question); } diff --git a/src/common/content-item/content-dependancy-tree.spec.ts b/src/common/content-item/content-dependancy-tree.spec.ts index 1d5410a4..f84fa61e 100644 --- a/src/common/content-item/content-dependancy-tree.spec.ts +++ b/src/common/content-item/content-dependancy-tree.spec.ts @@ -2,7 +2,7 @@ import { ContentDependancyTree, RepositoryContentItem, ItemContentDependancies } import { ContentMapping } from '../content-mapping'; import { ContentItem, Status, ContentRepository } from 'dc-management-sdk-js'; import { ItemTemplate } from '../dc-management-sdk-js/mock-content'; -import { dependsOn } from '../../commands/content-item/__mocks__/dependant-content-helper'; +import { dependsOn, hierarchyParent } from '../../commands/content-item/__mocks__/dependant-content-helper'; describe('content-dependancy-tree', () => { describe('content dependancy tree tests', () => { @@ -22,6 +22,7 @@ describe('content-dependancy-tree', () => { body: { ...template.body, _meta: { + ...(template.body && template.body._meta), schema: template.typeSchemaUri } }, @@ -54,7 +55,7 @@ describe('content-dependancy-tree', () => { { label: 'id4', body: dependsOn(['id1']), repoId: 'repo1', typeSchemaUri: 'http://type2.com' }, { label: 'id5', - body: dependsOn(['id1', 'id2'], [['exampleProp', 'id2']]), + body: dependsOn(['id1', 'id2'], undefined, [['exampleProp', 'id2']]), repoId: 'repo1', typeSchemaUri: 'http://type2.com' } @@ -73,6 +74,20 @@ describe('content-dependancy-tree', () => { ]); }; + const defaultAllRefTypes = (): RepositoryContentItem[] => { + return createItems([ + { label: 'id1', body: dependsOn([]), repoId: 'repo1', typeSchemaUri: 'http://type.com' }, + { label: 'id2', body: dependsOn(['id1']), repoId: 'repo1', typeSchemaUri: 'http://type.com' }, + { + label: 'id3', + body: dependsOn(['id1'], 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-reference'), + repoId: 'repo1', + typeSchemaUri: 'http://type2.com' + }, + { label: 'id4', body: hierarchyParent('id1'), repoId: 'repo1', typeSchemaUri: 'http://type2.com' } + ]); + }; + it('should create an empty tree given no content items', () => { const tree = new ContentDependancyTree([], new ContentMapping()); @@ -197,6 +212,35 @@ describe('content-dependancy-tree', () => { expectItemMatch(dependants2, items); }); + it('should traverse only link dependants of an item with traverseDependants when onlyLink is true', () => { + const items = defaultAllRefTypes(); + + const tree = new ContentDependancyTree(items, new ContentMapping()); + const dependants: ItemContentDependancies[] = []; + + // traverse dependants for id1, which is depended on by all content items, but only id2 is a link. + tree.traverseDependants( + tree.all[0], + item => { + dependants.push(item); + }, + true + ); + + expect(dependants.length).toEqual(2); + expectItemMatch(dependants, [items[0], items[1]]); + + const dependants2: ItemContentDependancies[] = []; + + // same, but allow links + tree.traverseDependants(tree.all[0], item => { + dependants2.push(item); + }); + + expect(dependants2.length).toEqual(4); + expectItemMatch(dependants2, items); + }); + it('should traverse all dependants of an item with traverseDependants ONCE, with circular dependancies', () => { const items = defaultCircularItems(); diff --git a/src/common/content-item/content-dependancy-tree.ts b/src/common/content-item/content-dependancy-tree.ts index 78150eb0..a22e061e 100644 --- a/src/common/content-item/content-dependancy-tree.ts +++ b/src/common/content-item/content-dependancy-tree.ts @@ -2,7 +2,7 @@ import { ContentItem, ContentRepository } from 'dc-management-sdk-js'; import { ContentMapping } from '../content-mapping'; import { Body } from './body'; -type DependancyContentTypeSchema = +export type DependancyContentTypeSchema = | 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-link' | 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-reference' | '_hierarchy'; // Used internally for parent dependancies. @@ -165,7 +165,8 @@ export class ContentDependancyTree { typeof body.id === 'string' ) { result.push({ dependancy: body as ContentDependancy, owner: item, parent, index }); - return; + // Return removed as customers have content links within content links so we must continue + // return; } allPropertyNames.forEach(propName => { @@ -336,20 +337,23 @@ export class ContentDependancyTree { public traverseDependants( item: ItemContentDependancies, action: (item: ItemContentDependancies) => void, - ignoreHier = false, + onlyLinks = false, traversed?: Set ): void { const traversedSet = traversed || new Set(); traversedSet.add(item); action(item); item.dependants.forEach(dependant => { - if (ignoreHier && dependant.dependancy._meta.schema == '_hierarchy') { + if ( + onlyLinks && + dependant.dependancy._meta.schema !== 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-link' + ) { return; } const resolved = dependant.resolved as ItemContentDependancies; if (!traversedSet.has(resolved)) { - this.traverseDependants(resolved, action, ignoreHier, traversedSet); + this.traverseDependants(resolved, action, onlyLinks, traversedSet); } }); } diff --git a/src/common/content-item/dedupe-content-items.spec.ts b/src/common/content-item/dedupe-content-items.spec.ts new file mode 100644 index 00000000..14020bbb --- /dev/null +++ b/src/common/content-item/dedupe-content-items.spec.ts @@ -0,0 +1,70 @@ +import { ContentItem } from 'dc-management-sdk-js'; + +import { dedupeContentItems } from './dedupe-content-items'; + +describe('dedupeContentItems', () => { + it('should return the same number of content items when only unique content items supplied', () => { + const contentItemA = new ContentItem({ + id: 'c5b659df-680e-4711-bfbe-111111111111', + label: 'Content item A', + body: { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/text' + }, + text: 'Content item A text' + } + }); + const contentItemB = new ContentItem({ + id: 'c5b659df-680e-4711-bfbe-222222222222', + label: 'Content item B', + body: { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/text' + }, + text: 'Content item B text' + } + }); + + expect(dedupeContentItems([contentItemA, contentItemB])).toEqual([contentItemA, contentItemB]); + }); + + it('should filter content items if they already existing in another content items immediate graph', () => { + const contentItemA = new ContentItem({ + id: 'c5b659df-680e-4711-bfbe-111111111111', + label: 'Content item A', + body: { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/text' + }, + text: 'Content item A text' + } + }); + const contentItemB = new ContentItem({ + id: 'c5b659df-680e-4711-bfbe-222222222222', + label: 'Content item B', + body: { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/text' + }, + text: 'Content item B text', + linkedText: { + _meta: { schema: 'http://bigcontent.io/cms/schema/v1/core#/definitions/content-link' }, + contentType: 'http://bigcontent.io/cms/schema/v1/text', + id: 'c5b659df-680e-4711-bfbe-333333333333' + } + } + }); + const contentItemC = new ContentItem({ + id: 'c5b659df-680e-4711-bfbe-333333333333', + label: 'Content item C', + body: { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/text' + }, + text: 'Content item C text' + } + }); + + expect(dedupeContentItems([contentItemA, contentItemB, contentItemC])).toEqual([contentItemA, contentItemB]); + }); +}); diff --git a/src/common/content-item/dedupe-content-items.ts b/src/common/content-item/dedupe-content-items.ts new file mode 100644 index 00000000..1988f05e --- /dev/null +++ b/src/common/content-item/dedupe-content-items.ts @@ -0,0 +1,27 @@ +import { ContentItem, ContentRepository } from 'dc-management-sdk-js'; +import { ContentMapping } from '../content-mapping'; +import { ContentDependancyTree } from './content-dependancy-tree'; + +export const dedupeContentItems = (contentItems: ContentItem[]) => { + const repoContentItems = contentItems.map(content => ({ repo: new ContentRepository(), content })); + const contentTree = new ContentDependancyTree(repoContentItems, new ContentMapping()); + const dedupedContentItems = contentTree.all + .filter(node => { + let isTopLevel = true; + + contentTree.traverseDependants( + node, + dependant => { + if (dependant != node && contentTree.all.findIndex(entry => entry === dependant) !== -1) { + isTopLevel = false; + } + }, + true + ); + + return isTopLevel; + }) + .map(node => node.owner.content); + + return dedupedContentItems; +}; diff --git a/src/common/content-item/get-content-items-by-ids.spec.ts b/src/common/content-item/get-content-items-by-ids.spec.ts new file mode 100644 index 00000000..147bed2c --- /dev/null +++ b/src/common/content-item/get-content-items-by-ids.spec.ts @@ -0,0 +1,51 @@ +import { ContentItem, DynamicContent } from 'dc-management-sdk-js'; + +import { getContentByIds } from './get-content-items-by-ids'; + +describe('getContentByIds', () => { + it('should get content items for the ids provided', async () => { + const contentItemA = new ContentItem({ + id: 'c5b659df-680e-4711-bfbe-111111111111', + label: 'Content item A', + body: { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/text' + }, + text: 'Content item A text' + } + }); + const contentItemB = new ContentItem({ + id: 'c5b659df-680e-4711-bfbe-222222222222', + label: 'Content item B', + body: { + _meta: { + schema: 'http://bigcontent.io/cms/schema/v1/text' + }, + text: 'Content item B text' + } + }); + const mockClient = { + contentItems: { + get: jest.fn().mockResolvedValueOnce(contentItemA).mockResolvedValueOnce(contentItemB) + } + } as unknown as DynamicContent; + + const ids = ['c5b659df-680e-4711-bfbe-111111111111', 'c5b659df-680e-4711-bfbe-222222222222']; + const result = await getContentByIds(mockClient, ids); + + expect(result).toEqual([contentItemA, contentItemB]); + }); + it('should ignore error if a supplied id is missing', async () => { + const mockClient = { + contentItems: { + get: jest.fn().mockRejectedValue(new Error('Authorization required.')) + } + } as unknown as DynamicContent; + + const ids = ['c5b659df-680e-4711-bfbe-111111111111']; + + const result = await getContentByIds(mockClient, ids); + + expect(result).toEqual([]); + }); +}); diff --git a/src/common/content-item/get-content-items-by-ids.ts b/src/common/content-item/get-content-items-by-ids.ts new file mode 100644 index 00000000..565a28d5 --- /dev/null +++ b/src/common/content-item/get-content-items-by-ids.ts @@ -0,0 +1,15 @@ +import { ContentItem, DynamicContent } from 'dc-management-sdk-js'; + +export const getContentByIds = async (client: DynamicContent, ids: string[]): Promise => { + const contentItems: ContentItem[] = []; + + for (const id of ids) { + try { + contentItems.push(await client.contentItems.get(id)); + } catch (e) { + // Silently fail missing content items + } + } + + return contentItems; +}; diff --git a/src/common/content-mapping.ts b/src/common/content-mapping.ts index bd5c1058..b834c725 100644 --- a/src/common/content-mapping.ts +++ b/src/common/content-mapping.ts @@ -5,18 +5,24 @@ import { promisify } from 'util'; export class ContentMapping { contentItems: Map; workflowStates: Map; + events: Map; + editions: Map; + slots: Map; + snapshots: Map; + webhooks: Map; constructor() { this.contentItems = new Map(); this.workflowStates = new Map(); + this.events = new Map(); + this.editions = new Map(); + this.slots = new Map(); + this.snapshots = new Map(); + this.webhooks = new Map(); } getContentItem(id: string | undefined): string | undefined { - if (id === undefined) { - return undefined; - } - - return this.contentItems.get(id); + return id === undefined ? undefined : this.contentItems.get(id); } registerContentItem(fromId: string, toId: string): void { @@ -35,10 +41,55 @@ export class ContentMapping { this.workflowStates.set(fromId, toId); } + getEvent(id: string | undefined): string | undefined { + return id === undefined ? undefined : this.events.get(id); + } + + registerEvent(fromId: string, toId: string): void { + this.events.set(fromId, toId); + } + + getEdition(id: string | undefined): string | undefined { + return id === undefined ? undefined : this.editions.get(id); + } + + registerEdition(fromId: string, toId: string): void { + this.editions.set(fromId, toId); + } + + getSlot(id: string | undefined): string | undefined { + return id === undefined ? undefined : this.slots.get(id); + } + + registerSlot(fromId: string, toId: string): void { + this.slots.set(fromId, toId); + } + + getSnapshot(id: string | undefined): string | undefined { + return id === undefined ? undefined : this.snapshots.get(id); + } + + registerSnapshot(fromId: string, toId: string): void { + this.snapshots.set(fromId, toId); + } + + getWebhook(id: string | undefined): string | undefined { + return id === undefined ? undefined : this.webhooks.get(id); + } + + registerWebhook(fromId: string, toId: string): void { + this.webhooks.set(fromId, toId); + } + async save(filename: string): Promise { const obj: SerializedContentMapping = { contentItems: Array.from(this.contentItems), - workflowStates: Array.from(this.workflowStates) + workflowStates: Array.from(this.workflowStates), + events: Array.from(this.events), + editions: Array.from(this.editions), + slots: Array.from(this.slots), + snapshots: Array.from(this.snapshots), + webhooks: Array.from(this.webhooks) }; const text = JSON.stringify(obj); @@ -57,6 +108,11 @@ export class ContentMapping { this.contentItems = new Map(obj.contentItems); this.workflowStates = new Map(obj.workflowStates); + this.events = obj.events ? new Map(obj.events) : new Map(); + this.editions = obj.editions ? new Map(obj.editions) : new Map(); + this.slots = obj.slots ? new Map(obj.slots) : new Map(); + this.snapshots = obj.snapshots ? new Map(obj.snapshots) : new Map(); + this.webhooks = obj.webhooks ? new Map(obj.webhooks) : new Map(); return true; } catch (e) { return false; @@ -67,4 +123,9 @@ export class ContentMapping { interface SerializedContentMapping { contentItems: [string, string][]; workflowStates: [string, string][]; + events?: [string, string][]; + editions?: [string, string][]; + slots?: [string, string][]; + snapshots?: [string, string][]; + webhooks?: [string, string][]; } diff --git a/src/common/dc-management-sdk-js/event-schedule-error.ts b/src/common/dc-management-sdk-js/event-schedule-error.ts new file mode 100644 index 00000000..65d2f1ed --- /dev/null +++ b/src/common/dc-management-sdk-js/event-schedule-error.ts @@ -0,0 +1,18 @@ +import { HalResource } from 'dc-management-sdk-js'; + +export interface EditionScheduleOverlap { + editionId: string; + name: string; + start: string; +} + +export interface EditionScheduleError { + level: 'WARNING' | 'ERROR'; + code: string; + message: string; + overlaps?: EditionScheduleOverlap[]; +} + +export class EditionScheduleStatus extends HalResource { + public errors?: EditionScheduleError[]; +} diff --git a/src/common/dc-management-sdk-js/http-client/dc-http-client.spec.ts b/src/common/dc-management-sdk-js/http-client/dc-http-client.spec.ts new file mode 100644 index 00000000..956dda9a --- /dev/null +++ b/src/common/dc-management-sdk-js/http-client/dc-http-client.spec.ts @@ -0,0 +1,288 @@ +import MockAdapter from 'axios-mock-adapter'; +import { HttpMethod } from 'dc-management-sdk-js'; + +jest.setTimeout(60000); + +describe('DCHttpClient tests', () => { + beforeEach(async () => { + jest.resetModules(); + process.env.DC_CLI_DELAY_FACTOR = '100'; + }); + afterEach(() => { + process.env.DC_CLI_DELAY_FACTOR = ''; + }); + test('client should request content', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({ + baseURL: 'https://api.amplience.net' + }); + + const mock = new MockAdapter(client.client); + mock.onGet('https://api.amplience.net/resource').reply(200, 'pong'); + + const response = await client.request({ + method: HttpMethod.GET, + url: 'https://api.amplience.net/resource' + }); + + expect(response.data).toEqual('pong'); + }); + test('client should retry then succeed when first error has 5xx status', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').replyOnce(500).onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(2); + }); + + test('client should retry then succeed when first error has 400 status', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').replyOnce(400).onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(2); + }); + + test('client should retry then succeed when first error has 401 status', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').replyOnce(401).onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(2); + }); + + test('client should retry then succeed when first error has 403 status', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').replyOnce(403).onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(2); + }); + + test('client should retry then succeed when first error has 404 status', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').replyOnce(404).onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(2); + }); + + test('client should retry then succeed when first error has 429 status', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').replyOnce(429).onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(2); + }); + + test('client should retry then succeed when first error is a network error', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').networkErrorOnce().onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(2); + }); + + test('client should retry 3 times and succeed on the last', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').replyOnce(401); + mock.onGet('/assets').replyOnce(401); + mock.onGet('/assets').replyOnce(401); + mock.onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(4); + }); + + test('client should retry then fail after 3 retries', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').reply(429); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(429); + expect(mock.history.get.length).toBe(4); + }); + + test('client should retry after connection timeout', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({}); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').timeoutOnce(); + mock.onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(2); + }); + + test('client should retry after connection timeouts resetting the timout value each retry', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({ timeout: 1 }); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').timeoutOnce(); + mock.onGet('/assets').timeoutOnce(); + mock.onGet('/assets').replyOnce(200, { + id: '1234' + }); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe(200); + expect(mock.history.get.length).toBe(3); + }); + + test('client should log a relevant error code and message on client errors', async () => { + const { DCHttpClient } = await import('./dc-http-client'); + const client = new DCHttpClient({ timeout: 1 }); + const mock = new MockAdapter(client.client); + + mock.onGet('/assets').timeoutOnce(); + mock.onGet('/assets').timeoutOnce(); + mock.onGet('/assets').timeoutOnce(); + mock.onGet('/assets').timeoutOnce(); + + const response = await client.request({ + headers: { + 'Content-Type': 'application/json' + }, + method: HttpMethod.GET, + url: '/assets' + }); + + expect(response.status).toBe('ECONNABORTED'); + expect(response.data).toEqual({ message: 'timeout of 1ms exceeded' }); + + expect(mock.history.get.length).toBe(4); + }); +}); diff --git a/src/common/dc-management-sdk-js/http-client/dc-http-client.ts b/src/common/dc-management-sdk-js/http-client/dc-http-client.ts new file mode 100644 index 00000000..a53fadd4 --- /dev/null +++ b/src/common/dc-management-sdk-js/http-client/dc-http-client.ts @@ -0,0 +1,76 @@ +import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios'; +import axiosRetry, { IAxiosRetryConfig, isNetworkOrIdempotentRequestError, isRetryableError } from 'axios-retry'; +import { HttpClient, HttpRequest, HttpResponse } from 'dc-management-sdk-js'; + +const DcRetryErrorCodes = [400, 401, 403, 404, 429]; + +const isRetriableDCResponseError = (error: AxiosError) => { + return DcRetryErrorCodes.includes(Number(error?.response?.status)); +}; + +const isSafeDCRequestError = (error: AxiosError) => { + if (!error.config?.method) { + // Cannot determine if the request can be retried + return false; + } + + return isRetryableError(error) && SAFE_HTTP_METHODS.indexOf(error?.config?.method) !== -1; +}; + +const SAFE_HTTP_METHODS = ['get', 'head', 'options', 'patch', 'post', 'put', 'del']; + +const DELAY_FACTOR = Number(process.env.DC_CLI_DELAY_FACTOR) || 1400; +const DEFAULT_RETRY_CONFIG: IAxiosRetryConfig = { + retries: 3, + shouldResetTimeout: true, + retryDelay: (retryCount, error) => axiosRetry.exponentialDelay(retryCount, error, DELAY_FACTOR), + retryCondition: (error: AxiosError) => { + return ( + Boolean(error?.code) || + isSafeDCRequestError(error) || + isNetworkOrIdempotentRequestError(error) || + isRetriableDCResponseError(error) + ); + } +}; + +export class DCHttpClient implements HttpClient { + public client: AxiosInstance; + + constructor(private config: AxiosRequestConfig) { + this.client = axios.create(config); + axiosRetry(this.client, DEFAULT_RETRY_CONFIG); + } + + public async request(config: HttpRequest): Promise { + return this.client + .request({ + data: config.data, + headers: config.headers, + method: config.method, + url: config.url + }) + .then(response => { + return { + headers: response.headers, + data: response.data, + status: response.status + }; + }) + .catch(error => { + if (error?.response) { + return { + data: error.response.data, + status: error.response.status + }; + } + if (error?.code) { + return { + data: { message: error.message }, + status: error.code + }; + } + return error; + }); + } +} diff --git a/src/common/dc-management-sdk-js/mock-content.ts b/src/common/dc-management-sdk-js/mock-content.ts index 821d4836..0c20ef29 100644 --- a/src/common/dc-management-sdk-js/mock-content.ts +++ b/src/common/dc-management-sdk-js/mock-content.ts @@ -10,7 +10,10 @@ import { ContentTypeSchema, ContentRepositoryContentType, Status, - ContentTypeCachedSchema + ContentTypeCachedSchema, + FacetQuery, + Sortable, + Pageable } from 'dc-management-sdk-js'; import MockPage from './mock-page'; @@ -136,7 +139,7 @@ export class MockContent { return Promise.resolve(result); }); - contentService.mockReturnValue(({ + contentService.mockReturnValue({ hubs: { get: mockHubGet, list: mockHubList @@ -157,7 +160,7 @@ export class MockContent { contentItems: { get: mockItemGet } - } as any) as DynamicContent); + } as any as DynamicContent); } private getFolderName(path: string | undefined): string { @@ -177,7 +180,12 @@ export class MockContent { if (this.failRepoList) { throw new Error('Simulated Netowrk Failure.'); } - return Promise.resolve(new MockPage(ContentRepository, this.repos.map(repo => repo.repo))); + return Promise.resolve( + new MockPage( + ContentRepository, + this.repos.map(repo => repo.repo) + ) + ); }); const mockTypesList = jest .fn() @@ -187,6 +195,39 @@ export class MockContent { .mockImplementation(() => Promise.resolve(new MockPage(ContentTypeSchema, Array.from(this.typeSchemaById.values()))) ); + const mockItemFacet = jest + .fn() + .mockImplementation((facetQuery: FacetQuery, options: Pageable & Sortable & { query: string }) => { + if (this.failRepoActions == 'list') { + throw new Error('Simulated network failure.'); + } + + let filter = this.items; + + // Some really basic filtering by repo id, as content item export uses it. + const repoStartStr = 'contentRepositoryId:"'; + const repoStart = options.query.indexOf(repoStartStr); + if (repoStart !== -1) { + const repoEnd = options.query.indexOf('"', repoStart + repoStartStr.length); + + if (repoEnd !== -1) { + const repo = options.query.substring(repoStart + repoStartStr.length, repoEnd); + + filter = filter.filter(item => item.contentRepositoryId === repo); + } + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const query = options.query; + /* + if (options.status) { + filter = filter.filter(item => item.status === options.status); + } + */ + + return Promise.resolve(new MockPage(ContentItem, filter)); + }); + const mockTypeRegister = jest.fn().mockImplementation((type: ContentType) => { this.metrics.typesCreated++; type = new ContentType(type); @@ -199,6 +240,7 @@ export class MockContent { mockHub.related.contentTypeSchema.list = mockSchemaList; mockHub.related.contentTypes.list = mockTypesList; mockHub.related.contentTypes.register = mockTypeRegister; + mockHub.related.contentItems.facet = mockItemFacet; return mockHub; } @@ -238,16 +280,14 @@ export class MockContent { }); repo.related.contentItems.list = mockItemList; - const mockFolderList = jest - .fn() - .mockImplementation(() => - Promise.resolve( - new MockPage( - Folder, - this.folders.filter(folder => (folder as any).repoId === repoId && folder.id == folder.name) - ) + const mockFolderList = jest.fn().mockImplementation(() => + Promise.resolve( + new MockPage( + Folder, + this.folders.filter(folder => (folder as any).repoId === repoId && folder.id == folder.name) ) - ); + ) + ); repo.related.folders.list = mockFolderList; const mockItemCreate = jest.fn().mockImplementation((item: ContentItem) => { @@ -502,6 +542,7 @@ export class MockContent { label: template.label, status: template.status || Status.ACTIVE, id: template.id || '0', + contentRepositoryId: template.repoId, folderId: folderNullOrEmpty ? null : folderId, version: template.version, lastPublishedVersion: template.lastPublishedVersion, @@ -640,7 +681,12 @@ export class MockContent { if (this.failFolderActions === 'items') { throw new Error('Simulated network failure.'); } - return Promise.resolve(new MockPage(ContentItem, this.items.filter(item => item.folderId === id))); + return Promise.resolve( + new MockPage( + ContentItem, + this.items.filter(item => item.folderId === id) + ) + ); }); mockFolderSubfolder.mockImplementation(() => { diff --git a/src/common/dc-management-sdk-js/mock-page.ts b/src/common/dc-management-sdk-js/mock-page.ts index 6f996251..e59ba66a 100644 --- a/src/common/dc-management-sdk-js/mock-page.ts +++ b/src/common/dc-management-sdk-js/mock-page.ts @@ -4,7 +4,11 @@ import { HalResource, HalResourceConstructor, Page } from 'dc-management-sdk-js' * @hidden */ export default class MockPage extends Page { - constructor(resourceType: HalResourceConstructor, private readonly mockItems: T[], data = {}) { + constructor( + resourceType: HalResourceConstructor, + private readonly mockItems: T[], + data = {} + ) { super('mock-page', resourceType, data); } diff --git a/src/common/dc-management-sdk-js/paginate-with-progress.ts b/src/common/dc-management-sdk-js/paginate-with-progress.ts new file mode 100644 index 00000000..9409e276 --- /dev/null +++ b/src/common/dc-management-sdk-js/paginate-with-progress.ts @@ -0,0 +1,34 @@ +import { HalResource, Page, Pageable, Sortable } from 'dc-management-sdk-js'; +import { ResourceStatus } from './resource-status'; +import paginator from './paginator'; +import { createProgressBar } from '../progress-bar/progress-bar'; + +interface ProgressOptions { + title: string; +} + +export const paginateWithProgress = async ( + pagableFn: (options?: Pageable & Sortable & ResourceStatus) => Promise>, + options: Pageable & Sortable & ResourceStatus = {}, + progressOptions: ProgressOptions +) => { + const progress = createProgressBar({ title: progressOptions.title }); + const results = await paginator( + pagableFn, + { + ...options + }, + { + onPage: (page: Page) => { + if (!progress.isActive) { + progress.start(page.page?.totalElements || 0, 0); + } + progress.increment(page.getItems().length); + } + } + ); + + progress.stop(); + + return results; +}; diff --git a/src/common/dc-management-sdk-js/paginator-options.ts b/src/common/dc-management-sdk-js/paginator-options.ts new file mode 100644 index 00000000..4c0454f7 --- /dev/null +++ b/src/common/dc-management-sdk-js/paginator-options.ts @@ -0,0 +1,5 @@ +import { HalResource, Page } from 'dc-management-sdk-js'; + +export interface PaginatorOptions { + onPage?: (page: Page) => void; +} diff --git a/src/common/dc-management-sdk-js/paginator.spec.ts b/src/common/dc-management-sdk-js/paginator.spec.ts index 15cbec2a..c5239295 100644 --- a/src/common/dc-management-sdk-js/paginator.spec.ts +++ b/src/common/dc-management-sdk-js/paginator.spec.ts @@ -2,12 +2,12 @@ import paginator, { DEFAULT_SIZE } from './paginator'; import MockPage from './mock-page'; import { Hub } from 'dc-management-sdk-js'; -describe('paginator', function() { +describe('paginator', function () { afterEach(() => { jest.resetAllMocks(); }); const mockPagableFn = jest.fn(); - describe('1 page', function() { + describe('1 page', function () { const mockPage = new MockPage(Hub, [new Hub({ id: 'id' })], { page: { number: 0, @@ -17,7 +17,7 @@ describe('paginator', function() { } }); - it('should return invoke pageableFn once if there is only 1 page', async function() { + it('should return invoke pageableFn once if there is only 1 page', async function () { mockPagableFn.mockResolvedValueOnce(mockPage); const result = await paginator(mockPagableFn); @@ -25,7 +25,7 @@ describe('paginator', function() { expect(mockPagableFn).toHaveBeenCalledWith({ size: DEFAULT_SIZE }); }); - it('should return invoke pageableFn once if there is only 1 page passing the user options to each call', async function() { + it('should return invoke pageableFn once if there is only 1 page passing the user options to each call', async function () { mockPagableFn.mockResolvedValueOnce(mockPage); const options = { sort: 'createdDate,asc' @@ -37,7 +37,7 @@ describe('paginator', function() { }); }); - describe('multiple pages', function() { + describe('multiple pages', function () { const mockPagableFn = jest.fn(); const mockPage1 = new MockPage(Hub, [new Hub({ id: 'id' })], { page: { @@ -56,7 +56,7 @@ describe('paginator', function() { } }); - it('should return invoke pageableFn twice if there are 2 pages', async function() { + it('should return invoke pageableFn twice if there are 2 pages', async function () { mockPagableFn.mockResolvedValueOnce(mockPage1); mockPagableFn.mockResolvedValueOnce(mockPage2); @@ -67,7 +67,7 @@ describe('paginator', function() { expect(mockPagableFn).toHaveBeenCalledWith({ size: DEFAULT_SIZE }); }); - it('should return invoke pageableFn twice if there are 2 pages passing the user options to each call', async function() { + it('should return invoke pageableFn twice if there are 2 pages passing the user options to each call', async function () { mockPagableFn.mockResolvedValueOnce(mockPage1); mockPagableFn.mockResolvedValueOnce(mockPage2); @@ -80,5 +80,18 @@ describe('paginator', function() { expect(mockPagableFn).toHaveBeenCalledWith({ ...options, size: DEFAULT_SIZE }); expect(mockPagableFn).toHaveBeenCalledWith({ ...options, size: DEFAULT_SIZE }); }); + + it('should call provided `onPage` function for each page', async () => { + mockPagableFn.mockResolvedValueOnce(mockPage1); + mockPagableFn.mockResolvedValueOnce(mockPage2); + + const onPageMock = jest.fn(); + + const result = await paginator(mockPagableFn, {}, { onPage: onPageMock }); + + expect(result.length).toEqual(2); + + expect(onPageMock).toHaveBeenCalledTimes(2); + }); }); }); diff --git a/src/common/dc-management-sdk-js/paginator.ts b/src/common/dc-management-sdk-js/paginator.ts index 8cedb073..15dba44b 100644 --- a/src/common/dc-management-sdk-js/paginator.ts +++ b/src/common/dc-management-sdk-js/paginator.ts @@ -1,16 +1,18 @@ -import { HalResource, Page, Pageable, Sortable, Status } from 'dc-management-sdk-js'; +import { HalResource, Page, Pageable, Sortable } from 'dc-management-sdk-js'; +import { ResourceStatus } from './resource-status'; +import { PaginatorOptions } from './paginator-options'; export const DEFAULT_SIZE = 100; -interface ResourceStatus { - status?: Status; -} - const paginator = async ( pagableFn: (options?: Pageable & Sortable & ResourceStatus) => Promise>, - options: Pageable & Sortable & ResourceStatus = {} + options: Pageable & Sortable & ResourceStatus = {}, + paginatorOptions: PaginatorOptions = {} ): Promise => { const currentPage = await pagableFn({ ...options, size: DEFAULT_SIZE }); + if (paginatorOptions?.onPage) { + paginatorOptions.onPage(currentPage); + } if ( currentPage.page && currentPage.page.number !== undefined && @@ -19,7 +21,7 @@ const paginator = async ( ) { return [ ...currentPage.getItems(), - ...(await paginator(pagableFn, { ...options, page: currentPage.page.number + 1 })) + ...(await paginator(pagableFn, { ...options, page: currentPage.page.number + 1 }, { ...paginatorOptions })) ]; } return currentPage.getItems(); diff --git a/src/common/extension/extension-helpers.ts b/src/common/extension/extension-helpers.ts new file mode 100644 index 00000000..d021be3a --- /dev/null +++ b/src/common/extension/extension-helpers.ts @@ -0,0 +1,24 @@ +import { Extension } from 'dc-management-sdk-js'; + +export const filterExtensionsById = ( + listToFilter: Extension[], + extensionUriList: string[], + deleteExtensions: boolean = false +): Extension[] => { + if (extensionUriList.length === 0) { + return listToFilter; + } + + const unmatchedExtensionUriList: string[] = extensionUriList.filter( + id => !listToFilter.some(extension => extension.id === id) + ); + if (unmatchedExtensionUriList.length > 0) { + throw new Error( + `The following extension URI(s) could not be found: [${unmatchedExtensionUriList + .map(u => `'${u}'`) + .join(', ')}].\nNothing was ${!deleteExtensions ? 'exported' : 'deleted'}, exiting.` + ); + } + + return listToFilter.filter(extension => extensionUriList.some(id => extension.id === id)); +}; diff --git a/src/common/file-log.spec.ts b/src/common/file-log.spec.ts index 9f79b46e..79ce5e96 100644 --- a/src/common/file-log.spec.ts +++ b/src/common/file-log.spec.ts @@ -13,7 +13,7 @@ describe('file-log', () => { const writeSpy = jest.spyOn(log, 'writeToFile').mockImplementation(() => Promise.resolve(true)); await log.close(); - expect(writeSpy).toBeCalled(); + expect(writeSpy).toHaveBeenCalled(); }); it('should not create a log file when filename is null, and closed', async () => { @@ -22,7 +22,7 @@ describe('file-log', () => { const writeSpy = jest.spyOn(log, 'writeToFile').mockImplementation(() => Promise.resolve(true)); await log.close(); - expect(writeSpy).not.toBeCalled(); + expect(writeSpy).not.toHaveBeenCalled(); }); it('should embed the date in the filename', async () => { @@ -35,9 +35,11 @@ describe('file-log', () => { expect(await promisify(exists)(`temp_${process.env.JEST_WORKER_ID}/FileWithDate-1234.log`)).toBeTruthy(); expect( - (await promisify(readFile)(`temp_${process.env.JEST_WORKER_ID}/FileWithDate-1234.log`, { - encoding: 'utf-8' - })).split('temp')[0] + ( + await promisify(readFile)(`temp_${process.env.JEST_WORKER_ID}/FileWithDate-1234.log`, { + encoding: 'utf-8' + }) + ).split('temp')[0] ).toMatchInlineSnapshot('"// dc-cli test-ver - "'); await promisify(unlink)(`temp_${process.env.JEST_WORKER_ID}/FileWithDate-1234.log`); @@ -53,11 +55,11 @@ describe('file-log', () => { const writeSpy = jest.spyOn(log, 'writeToFile').mockImplementation(() => Promise.resolve(true)); await log.close(); - expect(writeSpy).not.toBeCalled(); // There is still a user, shouldn't save yet. + expect(writeSpy).not.toHaveBeenCalled(); // There is still a user, shouldn't save yet. await log.close(); - expect(writeSpy).toBeCalled(); + expect(writeSpy).toHaveBeenCalled(); }); it('should not save a log file if false is provided to the close method, and it is the last close', async () => { @@ -66,7 +68,7 @@ describe('file-log', () => { const writeSpy = jest.spyOn(log, 'writeToFile').mockImplementation(() => Promise.resolve(true)); await log.close(false); - expect(writeSpy).not.toBeCalled(); + expect(writeSpy).not.toHaveBeenCalled(); }); }); }); diff --git a/src/common/filter/facet.spec.ts b/src/common/filter/facet.spec.ts index debe58e2..ceb8d788 100644 --- a/src/common/filter/facet.spec.ts +++ b/src/common/filter/facet.spec.ts @@ -5,12 +5,13 @@ import { relativeDate, parseDateRange, DatePreset, - withOldFilters + withOldFilters, + tryGetArray } from './facet'; import { ContentItem } from 'dc-management-sdk-js'; describe('facet', () => { - describe('parseFilter tests', () => { + describe('parseFacet tests', () => { it('should parse an empty string as an empty facet', () => { expect(parseFacet('')).toEqual({}); }); @@ -89,13 +90,13 @@ describe('facet', () => { }); it('should throw when given a date range string that cannot be parsed', () => { - expect(() => parseDateRange(('Last 234 days' as unknown) as DatePreset)).toThrowErrorMatchingInlineSnapshot( + expect(() => parseDateRange('Last 234 days' as unknown as DatePreset)).toThrowErrorMatchingInlineSnapshot( `"Unexpected date range string: Last 234 days"` ); - expect(() => parseDateRange(('Not a date range' as unknown) as DatePreset)).toThrowErrorMatchingInlineSnapshot( + expect(() => parseDateRange('Not a date range' as unknown as DatePreset)).toThrowErrorMatchingInlineSnapshot( `"Unexpected date range string: Not a date range"` ); - expect(() => parseDateRange(('2' as unknown) as DatePreset)).toThrowErrorMatchingInlineSnapshot( + expect(() => parseDateRange('2' as unknown as DatePreset)).toThrowErrorMatchingInlineSnapshot( `"Unexpected date range string: 2"` ); }); @@ -109,7 +110,7 @@ describe('facet', () => { beforeAll(() => { const realDate = Date; - jest.spyOn(global, 'Date').mockImplementation(() => (new realDate(fakeDate) as unknown) as string); + jest.spyOn(global, 'Date').mockImplementation(() => new realDate(fakeDate)); }); afterAll(() => { @@ -167,6 +168,53 @@ describe('facet', () => { return new ContentItem({ body: { _meta: { schema } }, label }); }; + describe('tryGetArray tests', () => { + it('should return null if the facet is undefined', () => { + expect(tryGetArray(undefined, false)).toBeNull(); + }); + + it('should return the input wrapped in an array if not given a regex value', () => { + expect(tryGetArray('regular text', false)).toEqual(['regular text']); + expect(tryGetArray('\\!@£$%^&*(){}[]/', false)).toEqual(['\\!@£$%^&*(){}[]/']); + }); + + it('should return null if the provided regex is not in an exact match format, and exactMatch is true', () => { + expect(tryGetArray('/inexact/', true)).toBeNull(); + expect(tryGetArray('/(inexact)/', true)).toBeNull(); + expect(tryGetArray('/a/', true)).toBeNull(); + + expect(tryGetArray('/^test1$|test2/', true)).toBeNull(); + expect(tryGetArray('/^test1$|(test2)/', true)).toBeNull(); + }); + + it('should match expected regex patterns and extract arrays from them', () => { + expect(tryGetArray('/^exact$/', false)).toEqual(['exact']); + expect(tryGetArray('/(inexact1)/', false)).toEqual(['inexact1']); + expect(tryGetArray('/inexact2/', false)).toEqual(['inexact2']); + + expect(tryGetArray('/^item1$|^item2$|^item3$/', true)).toEqual(['item1', 'item2', 'item3']); + expect(tryGetArray('/(inex1)|(inex2)|(inex3)/', false)).toEqual(['inex1', 'inex2', 'inex3']); + expect(tryGetArray('/test1|test2|test3/', false)).toEqual(['test1', 'test2', 'test3']); + + expect(tryGetArray('/test1|^test2$|(test3)/', false)).toEqual(['test1', 'test2', 'test3']); + + expect(tryGetArray('/\\*escaped\\/specials\\[|two\\$test/', false)).toEqual(['*escaped/specials[', 'two$test']); + }); + + it('should return null if regex special characters are used without escapes', () => { + expect(tryGetArray('/regex*/', false)).toBeNull(); + expect(tryGetArray('/[]/', false)).toBeNull(); + expect(tryGetArray('/fine|not?fine/', false)).toBeNull(); + }); + + it('should split only on unescaped pipe character', () => { + expect(tryGetArray('/simple|split|regex/', false)).toEqual(['simple', 'split', 'regex']); + expect(tryGetArray('/sim\\|ple|spl\\|it|reg\\|ex/', false)).toEqual(['sim|ple', 'spl|it', 'reg|ex']); + expect(tryGetArray('/doubleEscape\\\\|split/', false)).toEqual(['doubleEscape\\', 'split']); + expect(tryGetArray('/tripleEscape\\\\\\|split/', false)).toEqual(['tripleEscape\\|split']); + }); + }); + describe('applyFilter tests', () => { const fakeDate = new Date('2021-04-15T12:00:00.000Z'); const fakeDateM1 = '2021-04-14T12:00:00.000Z'; @@ -174,9 +222,7 @@ describe('facet', () => { beforeAll(() => { const realDate = Date; - jest - .spyOn(global, 'Date') - .mockImplementation((date?: string) => (new realDate(date || fakeDate) as unknown) as string); + jest.spyOn(global, 'Date').mockImplementation(date => new realDate(date || fakeDate)); }); afterAll(() => { diff --git a/src/common/filter/facet.ts b/src/common/filter/facet.ts index 28cef7de..7268afde 100644 --- a/src/common/filter/facet.ts +++ b/src/common/filter/facet.ts @@ -1,12 +1,13 @@ -import { ContentItem } from 'dc-management-sdk-js'; +import { ContentItem, FacetedContentItem } from 'dc-management-sdk-js'; import { equalsOrRegex } from './filter'; +import { isRegexString, hasRegexSpecialCharacter, removeEscapes } from './regex'; interface FacetRange { start: string; end: string; } -interface Facet { +export interface Facet { locale?: string; name?: string; schema?: string; @@ -115,6 +116,60 @@ export function dateRangeMatch(dateString: string, range: DatePreset | FacetRang return date > lower && date <= higher; } +export function tryGetArray(facetValue: string | undefined, onlyExact: boolean): string[] | null { + if (facetValue == null) { + return null; + } + + if (isRegexString(facetValue)) { + const regex = facetValue.substr(1, facetValue.length - 2); + + const split = regex.split(/((?:[^\\]|^)(?:\\\\)*)\|/); + + // Since js doesn't support regex lookback, merge together the [^\\] capture with the rest of each item + for (let i = 0; i < split.length - 1; i++) { + split[i] = split[i] + split[i + 1]; + split.splice(i + 1, 1); + } + + const result: string[] = []; + + for (let item of split) { + // Three cases: + // Within ^$: exact match. The request we make to the facets endpoint may not be exact, but a followup filter can fix that. + // Within (): converted regex. + // None: user specified regex. + + if (item.length > 2) { + const start = item[0]; + const end = item[item.length - 1]; + if ((start === '^' && end === '$') || (start === '(' && end === ')')) { + if (onlyExact && start !== '^') { + return null; + } + item = item.substr(1, item.length - 2); + } else if (onlyExact) { + return null; + } + } else if (onlyExact) { + return null; + } + + if (!hasRegexSpecialCharacter(item)) { + item = removeEscapes(item); + } else { + return null; // Cannot be used. + } + + result.push(item); + } + + return result; + } + + return [facetValue]; +} + export function applyFacet(items: ContentItem[], facetOrString: Facet | string): ContentItem[] { let facet: Facet; if (typeof facetOrString === 'string') { @@ -126,7 +181,12 @@ export function applyFacet(items: ContentItem[], facetOrString: Facet | string): return items.filter(item => { if (facet.locale && (!item.locale || !equalsOrRegex(item.locale, facet.locale))) return false; if (facet.name && !equalsOrRegex(item.label, facet.name)) return false; - if (facet.schema && !equalsOrRegex(item.body._meta.schema, facet.schema)) return false; + if ( + facet.schema && + // eslint-disable-next-line @typescript-eslint/no-explicit-any + !equalsOrRegex((item as any as FacetedContentItem).schema || item.body._meta.schema, facet.schema) + ) + return false; if (facet.status && !equalsOrRegex(item.status, facet.status)) return false; // Date range checks. diff --git a/src/common/filter/fetch-content.spec.ts b/src/common/filter/fetch-content.spec.ts new file mode 100644 index 00000000..c6ffa991 --- /dev/null +++ b/src/common/filter/fetch-content.spec.ts @@ -0,0 +1,876 @@ +import { ContentItem, ContentRepository, Folder, Hub, Status } from 'dc-management-sdk-js'; +import * as facetContentModule from './fetch-content'; +import * as facetModule from './facet'; +import dynamicContentClientFactory from '../../services/dynamic-content-client-factory'; +import MockPage from '../dc-management-sdk-js/mock-page'; + +jest.mock('../../services/dynamic-content-client-factory'); + +const config = { + clientId: 'client-id', + clientSecret: 'client-id', + hubId: 'hub-id' +}; + +describe('fetch-content', () => { + describe('getTotalElements tests', () => { + it('should return totalElements if totally defined', async () => { + const page = new MockPage(ContentItem, [new ContentItem()]); + page.page = { totalElements: 13 }; + expect(facetContentModule.getTotalElements(page)).toEqual(13); + }); + + it('should return items count if page is not defined', async () => { + const page = new MockPage(ContentItem, [new ContentItem()]); + expect(facetContentModule.getTotalElements(page)).toEqual(1); + }); + + it('should return items count if totalElements is not defined', async () => { + const page = new MockPage(ContentItem, [new ContentItem()]); + page.page = {}; + expect(facetContentModule.getTotalElements(page)).toEqual(1); + }); + }); + + describe('shouldFacetEnriched tests', () => { + beforeEach((): void => { + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + contentItems: { + get: jest.fn() + } + }); + }); + + afterEach((): void => { + jest.restoreAllMocks(); + }); + + it('should return 0 if no results from facet request', async () => { + const client = await dynamicContentClientFactory(config); + jest.spyOn(facetContentModule, 'getItemCount').mockResolvedValue(0); + + const page = new MockPage(ContentItem, []); + page.page = { totalElements: 0 }; + + const hub = new Hub(); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(page); + + const query = { + fields: [], + returnEntities: true + }; + + expect( + await facetContentModule.shouldFacetEnriched( + client, + hub, + query, + 'name:"test"', + 'folderId', + 'repoId', + Status.ACTIVE + ) + ).toEqual(0); + + expect(facetContentModule.getItemCount).not.toHaveBeenCalled(); + expect(hub.related.contentItems.facet).toHaveBeenCalledWith(query, { query: 'name:"test"', size: 1 }); + }); + + it('should return true early if less than FacetAlwaysMaximum results from facet request', async () => { + const client = await dynamicContentClientFactory(config); + jest.spyOn(facetContentModule, 'getItemCount').mockResolvedValue(0); + + const page = new MockPage(ContentItem, [new ContentItem()]); + page.page = { totalElements: 1 }; + + const hub = new Hub(); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(page); + + const query = { + fields: [], + returnEntities: true + }; + + expect( + await facetContentModule.shouldFacetEnriched( + client, + hub, + query, + 'name:"test"', + 'folderId', + 'repoId', + Status.ACTIVE + ) + ).toBeTruthy(); + + expect(facetContentModule.getItemCount).not.toHaveBeenCalled(); + expect(hub.related.contentItems.facet).toHaveBeenCalledWith(query, { query: 'name:"test"', size: 1 }); + }); + + it('should return true if getItemCount returns FacetEnrichThreshold times more than the facet', async () => { + const client = await dynamicContentClientFactory(config); + jest + .spyOn(facetContentModule, 'getItemCount') + .mockResolvedValue((facetContentModule.facetAlwaysMaximum + 1) * facetContentModule.facetEnrichThreshold + 1); + + const page = new MockPage(ContentItem, [new ContentItem()]); + page.page = { totalElements: facetContentModule.facetAlwaysMaximum + 1 }; + + const hub = new Hub(); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(page); + + const query = { + fields: [], + returnEntities: true + }; + + expect( + await facetContentModule.shouldFacetEnriched( + client, + hub, + query, + 'name:"test"', + 'folderId', + 'repoId', + Status.ACTIVE + ) + ).toBeTruthy(); + + expect(facetContentModule.getItemCount).toHaveBeenCalledWith(client, hub, 'folderId', 'repoId', Status.ACTIVE); + expect(hub.related.contentItems.facet).toHaveBeenCalledWith(query, { query: 'name:"test"', size: 1 }); + }); + + it('should return false if getItemCount returns less than FacetEnrichThreshold times more than the facet', async () => { + const client = await dynamicContentClientFactory(config); + jest.spyOn(facetContentModule, 'getItemCount').mockResolvedValue(facetContentModule.facetAlwaysMaximum + 10); + + const page = new MockPage(ContentItem, [new ContentItem()]); + page.page = { totalElements: facetContentModule.facetAlwaysMaximum + 1 }; + + const hub = new Hub(); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(page); + + const query = { + fields: [], + returnEntities: true + }; + + expect( + await facetContentModule.shouldFacetEnriched( + client, + hub, + query, + 'name:"test"', + 'folderId', + 'repoId', + Status.ACTIVE + ) + ).toBeFalsy(); + + expect(facetContentModule.getItemCount).toHaveBeenCalledWith(client, hub, 'folderId', 'repoId', Status.ACTIVE); + expect(hub.related.contentItems.facet).toHaveBeenCalledWith(query, { query: 'name:"test"', size: 1 }); + }); + }); + + describe('tryFetchContent tests', () => { + const params = { + folderId: 'folder', + repoId: 'repo' + }; + + beforeEach((): void => { + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + contentItems: { + get: jest.fn() + } + }); + }); + + afterEach((): void => { + jest.restoreAllMocks(); + }); + + it('should return null if no fields can be used in a facet request (not including folder/repo/status)', async () => { + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(null); + + // None of these facets are able to be added to the query. (status is added only if others exist) + const facet = { + status: 'ACTIVE', + schema: '/inexact/', + locale: '/inexact/' + }; + + // params added only after other facets exist. + + expect(await facetContentModule.tryFetchContent(client, hub, facet, params)).toBeNull(); + + expect(client.contentItems.get).not.toHaveBeenCalled(); + expect(hub.related.contentItems.facet).not.toHaveBeenCalled(); + }); + + it('should add schema query to field if an exact match array can be extracted', async () => { + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + const item1 = new ContentItem({ label: 'item1' }); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(new MockPage(ContentItem, [item1])); + jest.spyOn(facetContentModule, 'shouldFacetEnriched').mockResolvedValue(true); + + const facet = { + status: 'ACTIVE', + schema: '/^http\\:\\/\\/schema1$|^http\\:\\/\\/schema2$/' + }; + + expect(await facetContentModule.tryFetchContent(client, hub, facet, params)).toEqual([item1]); + + expect(hub.related.contentItems.facet).toHaveBeenCalledWith( + { + fields: [ + { + facetAs: 'ENUM', + field: 'schema', + filter: { + type: 'IN', + values: ['http://schema1', 'http://schema2'] + } + } + ], + returnEntities: true + }, + { query: 'contentRepositoryId:"repo"folderId:"folder"status:"ACTIVE"', size: expect.any(Number) } + ); + expect(client.contentItems.get).not.toHaveBeenCalled(); + expect(facetContentModule.shouldFacetEnriched).not.toHaveBeenCalled(); + }); + + it('should add locale query to field if an exact match array can be extracted', async () => { + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + const item1 = new ContentItem({ label: 'item1' }); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(new MockPage(ContentItem, [item1])); + jest.spyOn(facetContentModule, 'shouldFacetEnriched').mockResolvedValue(true); + + const facet = { + status: 'ACTIVE', + locale: '/^en\\-GB$|^en\\-US$/' + }; + + expect(await facetContentModule.tryFetchContent(client, hub, facet, params)).toEqual([item1]); + + expect(hub.related.contentItems.facet).toHaveBeenCalledWith( + { + fields: [ + { + facetAs: 'ENUM', + field: 'locale', + filter: { + type: 'IN', + values: ['en-GB', 'en-US'] + } + } + ], + returnEntities: true + }, + { query: 'contentRepositoryId:"repo"folderId:"folder"status:"ACTIVE"', size: expect.any(Number) } + ); + expect(client.contentItems.get).not.toHaveBeenCalled(); + expect(facetContentModule.shouldFacetEnriched).not.toHaveBeenCalled(); + }); + + it('should add name to field if an array can be extracted with length one', async () => { + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + const item1 = new ContentItem({ label: 'item1' }); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(new MockPage(ContentItem, [item1])); + jest.spyOn(facetContentModule, 'shouldFacetEnriched').mockResolvedValue(true); + + const facet = { + status: 'ACTIVE', + name: '/name \\"partial\\" match/' + }; + + expect(await facetContentModule.tryFetchContent(client, hub, facet, params)).toEqual([item1]); + + expect(hub.related.contentItems.facet).toHaveBeenCalledWith( + { + fields: [], + returnEntities: true + }, + { + query: 'label:"name \\"partial\\" match"contentRepositoryId:"repo"folderId:"folder"status:"ACTIVE"', + size: expect.any(Number) + } + ); + expect(client.contentItems.get).not.toHaveBeenCalled(); + expect(facetContentModule.shouldFacetEnriched).not.toHaveBeenCalled(); + }); + + it('should not add name to field if an array can be extracted, but its length is greater than one', async () => { + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(null); + + const facet = { + status: 'ACTIVE', + name: '/multiple|names/' + }; + + expect(await facetContentModule.tryFetchContent(client, hub, facet, params)).toBeNull(); + + expect(client.contentItems.get).not.toHaveBeenCalled(); + expect(hub.related.contentItems.facet).not.toHaveBeenCalled(); + }); + + it('should add last modified date to field if present', async () => { + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + const item1 = new ContentItem({ label: 'item1' }); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(new MockPage(ContentItem, [item1])); + jest.spyOn(facetContentModule, 'shouldFacetEnriched').mockResolvedValue(true); + + const facet = { + status: 'ACTIVE', + lastModifiedDate: 'Last 7 days' as facetModule.DatePreset + }; + + expect(await facetContentModule.tryFetchContent(client, hub, facet, params)).toEqual([item1]); + + expect(hub.related.contentItems.facet).toHaveBeenCalledWith( + { + fields: [ + { + facetAs: 'DATE', + field: 'lastModifiedDate', + filter: { + type: 'DATE', + values: ['-7:DAYS,NOW'] + }, + range: { start: 'NOW', end: '-7:DAYS' } + } + ], + returnEntities: true + }, + { query: 'contentRepositoryId:"repo"folderId:"folder"status:"ACTIVE"', size: expect.any(Number) } + ); + expect(client.contentItems.get).not.toHaveBeenCalled(); + expect(facetContentModule.shouldFacetEnriched).not.toHaveBeenCalled(); + }); + + it('should prefer status from params to the one in the facet object', async () => { + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + const item1 = new ContentItem({ label: 'item1' }); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(new MockPage(ContentItem, [item1])); + jest.spyOn(facetContentModule, 'shouldFacetEnriched').mockResolvedValue(true); + + const facet = { + status: 'ACTIVE', + name: '/name/' + }; + + const modParams = { + ...params, + status: Status.ARCHIVED + }; + + expect(await facetContentModule.tryFetchContent(client, hub, facet, modParams)).toEqual([item1]); + + expect(hub.related.contentItems.facet).toHaveBeenCalledWith( + { + fields: [], + returnEntities: true + }, + { + query: 'label:"name"contentRepositoryId:"repo"folderId:"folder"status:"ARCHIVED"', + size: expect.any(Number) + } + ); + expect(client.contentItems.get).not.toHaveBeenCalled(); + expect(facetContentModule.shouldFacetEnriched).not.toHaveBeenCalled(); + }); + + it('should request full versions of items individually when enrichItems is true', async () => { + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + const item1 = new ContentItem({ label: 'item1', id: 'item1' }); + const item2 = new ContentItem({ label: 'item2', id: 'item2' }); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(new MockPage(ContentItem, [item1, item2])); + jest.spyOn(facetContentModule, 'shouldFacetEnriched').mockResolvedValue(true); + + const itemEnrich = new ContentItem({ label: 'itemEnrich' }); + (client.contentItems.get as jest.Mock).mockResolvedValue(itemEnrich); + + const facet = { + name: '/name/' + }; + + const modParams = { + enrichItems: true + }; + + expect(await facetContentModule.tryFetchContent(client, hub, facet, modParams)).toEqual([itemEnrich, itemEnrich]); + + const query = { + fields: [], + returnEntities: true + }; + + expect(hub.related.contentItems.facet).toHaveBeenCalledWith(query, { + query: 'label:"name"', + size: expect.any(Number) + }); + + expect(client.contentItems.get).toHaveBeenCalledTimes(2); + expect(client.contentItems.get).toHaveBeenNthCalledWith(1, 'item1'); + expect(client.contentItems.get).toHaveBeenNthCalledWith(2, 'item2'); + expect(facetContentModule.shouldFacetEnriched).toHaveBeenCalledWith( + client, + hub, + query, + 'label:"name"', + undefined, + undefined, + undefined + ); + }); + + it('should return empty early when enrichItems is true and shouldFacetEnriched returns 0', async () => { + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(new MockPage(ContentItem, [])); + jest.spyOn(facetContentModule, 'shouldFacetEnriched').mockResolvedValue(0); + + const facet = { + name: '/name/' + }; + + const modParams = { + enrichItems: true + }; + + expect(await facetContentModule.tryFetchContent(client, hub, facet, modParams)).toEqual([]); + + const query = { + fields: [], + returnEntities: true + }; + + expect(hub.related.contentItems.facet).not.toHaveBeenCalled(); + + expect(client.contentItems.get).not.toHaveBeenCalled(); + expect(facetContentModule.shouldFacetEnriched).toHaveBeenCalledWith( + client, + hub, + query, + 'label:"name"', + undefined, + undefined, + undefined + ); + }); + + it('should return null early when enrichItems is true and shouldFacetEnriched returns false', async () => { + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + hub.related.contentItems.facet = jest.fn().mockResolvedValue(new MockPage(ContentItem, [])); + jest.spyOn(facetContentModule, 'shouldFacetEnriched').mockResolvedValue(false); + + const facet = { + name: '/name/' + }; + + const modParams = { + enrichItems: true + }; + + expect(await facetContentModule.tryFetchContent(client, hub, facet, modParams)).toEqual(null); + + const query = { + fields: [], + returnEntities: true + }; + + expect(hub.related.contentItems.facet).not.toHaveBeenCalled(); + + expect(client.contentItems.get).not.toHaveBeenCalled(); + expect(facetContentModule.shouldFacetEnriched).toHaveBeenCalledWith( + client, + hub, + query, + 'label:"name"', + undefined, + undefined, + undefined + ); + }); + }); + + describe('getItemCount tests', () => { + it('should get item count in folder if folderId provided', async () => { + jest.spyOn(facetContentModule, 'tryFetchContent').mockResolvedValue(null); + + const item1 = new ContentItem({ label: 'item1' }); + + const folder1 = new Folder(); + const page = new MockPage(ContentItem, [item1]); + page.page = { totalElements: 4 }; + folder1.related.contentItems.list = jest.fn().mockResolvedValue(page); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + folders: { + get: jest.fn().mockResolvedValue(folder1) + } + }); + + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + + expect(await facetContentModule.getItemCount(client, hub, 'folder1', undefined, Status.ACTIVE)).toEqual(4); + + expect(client.folders.get).toHaveBeenCalledWith('folder1'); + expect(folder1.related.contentItems.list).toHaveBeenCalled(); + }); + + it('should get item count in repo if repoId provided', async () => { + jest.spyOn(facetContentModule, 'tryFetchContent').mockResolvedValue(null); + + const item1 = new ContentItem({ label: 'item1' }); + + const repo1 = new ContentRepository(); + const page = new MockPage(ContentItem, [item1]); + page.page = { totalElements: 10 }; + repo1.related.contentItems.list = jest.fn().mockResolvedValue(page); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + contentRepositories: { + get: jest.fn().mockResolvedValue(repo1) + } + }); + + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + + expect(await facetContentModule.getItemCount(client, hub, undefined, 'repo1', Status.ACTIVE)).toEqual(10); + + expect(client.contentRepositories.get).toHaveBeenCalledWith('repo1'); + expect(repo1.related.contentItems.list).toHaveBeenCalled(); + }); + + it('should get item count in hub if neither repoId or folderId provided', async () => { + jest.spyOn(facetContentModule, 'tryFetchContent').mockResolvedValue(null); + + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + + const item1 = new ContentItem({ label: 'item1' }); + const item2 = new ContentItem({ label: 'item2' }); + + const page1 = new MockPage(ContentItem, [item1]); + page1.page = { totalElements: 5 }; + + const page2 = new MockPage(ContentItem, [item2]); + page2.page = { totalElements: 7 }; + + const repo1 = new ContentRepository(); + repo1.related.contentItems.list = jest.fn().mockResolvedValue(page1); + + const repo2 = new ContentRepository(); + repo2.related.contentItems.list = jest.fn().mockResolvedValue(page2); + + hub.related.contentRepositories.list = jest + .fn() + .mockResolvedValue(new MockPage(ContentRepository, [repo1, repo2])); + + expect(await facetContentModule.getItemCount(client, hub, undefined, undefined, Status.ACTIVE)).toEqual(12); + + expect(hub.related.contentRepositories.list).toHaveBeenCalled(); + expect(repo1.related.contentItems.list).toHaveBeenCalled(); + expect(repo2.related.contentItems.list).toHaveBeenCalled(); + }); + }); + + describe('fetchContent tests', () => { + afterEach((): void => { + jest.restoreAllMocks(); + }); + + it('should fetch items directly from folder if tryFetchContent with folderId fails', async () => { + jest.spyOn(facetContentModule, 'tryFetchContent').mockResolvedValue(null); + + const item1 = new ContentItem({ label: 'item1' }); + + const folder1 = new Folder(); + folder1.related.contentItems.list = jest.fn().mockResolvedValue(new MockPage(ContentItem, [item1])); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + folders: { + get: jest.fn().mockResolvedValue(folder1) + } + }); + + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + const facet = { schema: 'http://amplience.com' }; + const params = { + folderId: 'folder1', + enrichItems: false, + status: Status.ACTIVE + }; + + expect(await facetContentModule.fetchContent(client, hub, facet, params)).toEqual([item1]); + + expect(facetContentModule.tryFetchContent).toHaveBeenCalledWith(client, hub, facet, params); + + expect(client.folders.get).toHaveBeenCalledWith('folder1'); + expect(folder1.related.contentItems.list).toHaveBeenCalled(); + }); + + it('should fetch items directly from repo if tryFetchContent with repoId fails', async () => { + jest.spyOn(facetContentModule, 'tryFetchContent').mockResolvedValue(null); + + const item1 = new ContentItem({ label: 'item1' }); + + const repo1 = new ContentRepository(); + repo1.related.contentItems.list = jest.fn().mockResolvedValue(new MockPage(ContentItem, [item1])); + + (dynamicContentClientFactory as jest.Mock).mockReturnValue({ + contentRepositories: { + get: jest.fn().mockResolvedValue(repo1) + } + }); + + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + const facet = { schema: 'http://amplience.com' }; + const params = { + repoId: 'repo1', + enrichItems: false, + status: Status.ACTIVE + }; + + expect(await facetContentModule.fetchContent(client, hub, facet, params)).toEqual([item1]); + + expect(facetContentModule.tryFetchContent).toHaveBeenCalledWith(client, hub, facet, params); + + expect(client.contentRepositories.get).toHaveBeenCalledWith('repo1'); + expect(repo1.related.contentItems.list).toHaveBeenCalled(); + }); + + it('should fetch items directly from hub if tryFetchContent with hub fails', async () => { + jest.spyOn(facetContentModule, 'tryFetchContent').mockResolvedValue(null); + + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + + const item1 = new ContentItem({ label: 'item1' }); + const item2 = new ContentItem({ label: 'item2' }); + + const repo1 = new ContentRepository(); + repo1.related.contentItems.list = jest.fn().mockResolvedValue(new MockPage(ContentItem, [item1])); + + const repo2 = new ContentRepository(); + repo2.related.contentItems.list = jest.fn().mockResolvedValue(new MockPage(ContentItem, [item2])); + + hub.related.contentRepositories.list = jest + .fn() + .mockResolvedValue(new MockPage(ContentRepository, [repo1, repo2])); + + const facet = { schema: 'http://amplience.com' }; + const params = { + enrichItems: false, + status: Status.ACTIVE + }; + + expect(await facetContentModule.fetchContent(client, hub, facet, params)).toEqual([item1, item2]); + + expect(facetContentModule.tryFetchContent).toHaveBeenCalledWith(client, hub, facet, params); + }); + + it('should not make requests if tryFetchContent succeeds', async () => { + const exampleItem = new ContentItem({ label: 'resultItem' }); + jest.spyOn(facetContentModule, 'tryFetchContent').mockResolvedValue([exampleItem]); + + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + const facet = { schema: 'http://amplience.com' }; + const params = { + folderId: 'folder1', + repoId: 'repo1', + enrichItems: false, + status: Status.ACTIVE + }; + + expect(await facetContentModule.fetchContent(client, hub, facet, params)).toEqual([exampleItem]); + + expect(facetContentModule.tryFetchContent).toHaveBeenCalledWith(client, hub, facet, params); + }); + + it('should parse the facet from a string if provided as such', async () => { + const exampleItem = new ContentItem({ label: 'resultItem' }); + jest.spyOn(facetContentModule, 'tryFetchContent').mockResolvedValue([exampleItem]); + + const client = await dynamicContentClientFactory(config); + const hub = new Hub({}); + const facet = 'schema:http://amplience.com'; + const params = { + folderId: 'folder1', + repoId: 'repo1', + enrichItems: false, + status: Status.ACTIVE + }; + + expect(await facetContentModule.fetchContent(client, hub, facet, params)).toEqual([exampleItem]); + + expect(facetContentModule.tryFetchContent).toHaveBeenCalledWith( + client, + hub, + { schema: 'http://amplience.com' }, + params + ); + }); + }); + + describe('getContent tests', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const nullClient = {} as any; + + afterEach((): void => { + jest.restoreAllMocks(); + }); + + it('should call fetchContent with requested singular folder and repo ids', async () => { + const exampleItem = new ContentItem({ label: 'resultItem' }); + jest.spyOn(facetContentModule, 'fetchContent').mockResolvedValue([exampleItem]); + + const client = nullClient; + const hub = new Hub({}); + const commonParams = { + enrichItems: false, + status: Status.ACTIVE + }; + const params = { + folderId: 'folder1', + repoId: 'repo1', + ...commonParams + }; + + expect(await facetContentModule.getContent(client, hub, undefined, params)).toEqual([exampleItem, exampleItem]); + + expect(facetContentModule.fetchContent).toHaveBeenCalledTimes(2); + + expect(facetContentModule.fetchContent).toHaveBeenNthCalledWith(1, client, hub, undefined, { + folderId: 'folder1', + ...commonParams + }); + + expect(facetContentModule.fetchContent).toHaveBeenNthCalledWith(2, client, hub, undefined, { + repoId: 'repo1', + ...commonParams + }); + }); + + it('should call fetchContent with requested array folder and repo ids', async () => { + const exampleItem = new ContentItem({ label: 'resultItem' }); + jest.spyOn(facetContentModule, 'fetchContent').mockResolvedValue([exampleItem]); + + const client = nullClient; + const hub = new Hub({}); + const commonParams = { + enrichItems: false, + status: Status.ACTIVE + }; + const params = { + folderId: ['folder1', 'folder2'], + repoId: ['repo1', 'repo2'], + ...commonParams + }; + + expect(await facetContentModule.getContent(client, hub, undefined, params)).toEqual([ + exampleItem, + exampleItem, + exampleItem, + exampleItem + ]); + + expect(facetContentModule.fetchContent).toHaveBeenCalledTimes(4); + + expect(facetContentModule.fetchContent).toHaveBeenNthCalledWith(1, client, hub, undefined, { + folderId: 'folder1', + ...commonParams + }); + + expect(facetContentModule.fetchContent).toHaveBeenNthCalledWith(2, client, hub, undefined, { + folderId: 'folder2', + ...commonParams + }); + + expect(facetContentModule.fetchContent).toHaveBeenNthCalledWith(3, client, hub, undefined, { + repoId: 'repo1', + ...commonParams + }); + + expect(facetContentModule.fetchContent).toHaveBeenNthCalledWith(4, client, hub, undefined, { + repoId: 'repo2', + ...commonParams + }); + }); + + it('should call fetchContent with no folder/repo id, if none is provided', async () => { + const exampleItem = new ContentItem({ label: 'resultItem' }); + jest.spyOn(facetContentModule, 'fetchContent').mockResolvedValue([exampleItem]); + + const client = nullClient; + const hub = new Hub({}); + const commonParams = { + enrichItems: false, + status: Status.ACTIVE + }; + const params = { + ...commonParams + }; + + expect(await facetContentModule.getContent(client, hub, undefined, params)).toEqual([exampleItem]); + + expect(facetContentModule.fetchContent).toHaveBeenCalledTimes(1); + + expect(facetContentModule.fetchContent).toHaveBeenNthCalledWith(1, client, hub, undefined, commonParams); + }); + + it('should call applyFacet only when facet is defined', async () => { + const exampleItem = new ContentItem({ label: 'resultItem' }); + jest.spyOn(facetContentModule, 'fetchContent').mockResolvedValue([exampleItem]); + jest.spyOn(facetModule, 'applyFacet').mockReturnValue([exampleItem]); + + const client = nullClient; + const hub = new Hub({}); + const facet = { schema: 'http://amplience.com' }; + const commonParams = { + enrichItems: false, + status: Status.ACTIVE + }; + const params = { + ...commonParams + }; + + expect(await facetContentModule.getContent(client, hub, facet, params)).toEqual([exampleItem]); + + expect(facetContentModule.fetchContent).toHaveBeenCalledTimes(1); + expect(facetContentModule.fetchContent).toHaveBeenNthCalledWith(1, client, hub, facet, commonParams); + + expect(facetModule.applyFacet).toHaveBeenCalledWith([exampleItem], facet); + + // should not call applyFacet when undefined + + (facetContentModule.fetchContent as jest.Mock).mockClear(); + (facetModule.applyFacet as jest.Mock).mockClear(); + + expect(await facetContentModule.getContent(client, hub, undefined, params)).toEqual([exampleItem]); + + expect(facetContentModule.fetchContent).toHaveBeenCalledTimes(1); + expect(facetContentModule.fetchContent).toHaveBeenNthCalledWith(1, client, hub, undefined, commonParams); + + expect(facetModule.applyFacet).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/src/common/filter/fetch-content.ts b/src/common/filter/fetch-content.ts new file mode 100644 index 00000000..c0e35468 --- /dev/null +++ b/src/common/filter/fetch-content.ts @@ -0,0 +1,285 @@ +import { + ContentItem, + DynamicContent, + FacetedContentItem, + FacetQuery, + HalResource, + Hub, + Page, + Status +} from 'dc-management-sdk-js'; +import paginator from '../dc-management-sdk-js/paginator'; +import { applyFacet, Facet, parseDateRange, parseFacet, tryGetArray } from './facet'; +import { isRegexString } from './regex'; +import { paginateWithProgress } from '../dc-management-sdk-js/paginate-with-progress'; + +// Threshold used to facet enriched content then request individually instead of fetching+filtering all content. +// Currently, facet should return 20 times less content items than a request for all of them to be used. +// If there are less than 20 content items, always facet. +export const facetEnrichThreshold = 20; +export const facetAlwaysMaximum = 20; + +interface FetchContentParams { + enrichItems?: boolean; + repoId?: string; + folderId?: string; + status?: Status; +} + +interface GetContentParams { + enrichItems?: boolean; + repoId?: string | string[]; + folderId?: string | string[]; + status?: Status; +} + +export const getTotalElements = (page: Page): number => { + if (page.page == null || page.page.totalElements == null) { + return page.getItems().length; + } + + return page.page.totalElements; +}; + +export const getItemCount = async ( + client: DynamicContent, + hub: Hub, + folderId: string | undefined, + repoId: string | undefined, + status: Status | undefined +): Promise => { + const options = { status, size: 1 }; + + if (folderId != null) { + const folder = await client.folders.get(folderId); + return getTotalElements(await folder.related.contentItems.list(options)); + } else if (repoId != null) { + const repo = await client.contentRepositories.get(repoId); + return getTotalElements(await repo.related.contentItems.list(options)); + } else { + const repos = await paginator(hub.related.contentRepositories.list); + + let result = 0; + for (const repo of repos) { + const page = await repo.related.contentItems.list(options); + result += getTotalElements(page); + } + return result; + } +}; + +export const shouldFacetEnriched = async ( + client: DynamicContent, + hub: Hub, + facetQuery: FacetQuery, + qString: string, + folderId: string | undefined, + repoId: string | undefined, + status: Status | undefined +): Promise => { + const facetCount = getTotalElements(await hub.related.contentItems.facet(facetQuery, { query: qString, size: 1 })); + + if (facetCount == 0) { + return 0; + } + + if (facetCount > facetAlwaysMaximum) { + const allCount = await getItemCount(client, hub, folderId, repoId, status); + + if (facetCount * facetEnrichThreshold >= allCount) { + return false; // Just get all content items. + } + } + + return true; +}; + +export const tryFetchContent = async ( + client: DynamicContent, + hub: Hub, + facet: Facet, + params: FetchContentParams +): Promise => { + const { repoId, folderId, enrichItems, status } = params; + const facetQuery: FacetQuery = { fields: [], returnEntities: true }; + const query: string[] = []; + + const schemaArray = tryGetArray(facet.schema, true); + if (schemaArray) { + facetQuery.fields.push({ + facetAs: 'ENUM', + field: 'schema', + filter: { + type: 'IN', + values: schemaArray + } + }); + } + + const localeArray = tryGetArray(facet.locale, true); + if (localeArray) { + facetQuery.fields.push({ + facetAs: 'ENUM', + field: 'locale', + filter: { + type: 'IN', + values: localeArray + } + }); + } + + if (facet.name) { + const names = tryGetArray(facet.name, false); + + // The facet endpoint cannot search for multiple label values at the moment. + if (names && names.length === 1) { + for (const name of names) { + query.push(`label:"${name.replace(/"/g, '\\"')}"`); + } + } + } + + if (facet.lastModifiedDate) { + const range = parseDateRange(facet.lastModifiedDate); + facetQuery.fields.push({ + facetAs: 'DATE', + field: 'lastModifiedDate', + filter: { + type: 'DATE', + values: [`${range.end},${range.start}`] + }, + range + }); + } + + if (facetQuery.fields.length === 0 && query.length === 0) { + return null; + } + + if (repoId) { + query.push(`contentRepositoryId:"${repoId}"`); + } + + if (folderId) { + query.push(`folderId:"${folderId}"`); + } + + if (status) { + query.push(`status:"${status}"`); + } else if (facet.status && !isRegexString(facet.status) && facet.status.indexOf('"') === -1) { + query.push(`status:"${facet.status}"`); + delete facet.status; + } + + if (enrichItems) { + // The facets endpoint does not return the content item body, so it must be requested manually. + // First, check if it's worth it enriching items individually instead of just fetching them all. + const qString = query.join(''); + + const should = await shouldFacetEnriched(client, hub, facetQuery, qString, folderId, repoId, status); + + if (should === 0) { + return []; + } else if (!should) { + return null; + } + + const items = await paginator(options => + hub.related.contentItems.facet(facetQuery, { ...options, query: qString }) + ); + const enriched: ContentItem[] = []; + + for (let i = 0; i < items.length; i++) { + enriched.push(await client.contentItems.get(items[i].id)); + } + + return enriched; + } else { + return paginator(options => hub.related.contentItems.facet(facetQuery, { ...options, query: query.join('') })); + } +}; + +export const fetchContent = async ( + client: DynamicContent, + hub: Hub, + facetOrString: Facet | string | undefined, + params: FetchContentParams +): Promise => { + const { repoId, folderId, status } = params; + + const options = status ? { status } : undefined; + let filtered: ContentItem[] | FacetedContentItem[] | null = null; + + if (facetOrString) { + let facet: Facet; + if (typeof facetOrString === 'string') { + facet = parseFacet(facetOrString); + } else { + facet = facetOrString; + } + + filtered = await tryFetchContent(client, hub, facet, params); + } + + if (filtered == null) { + if (folderId != null) { + const folder = await client.folders.get(folderId); + + return await paginateWithProgress(folder.related.contentItems.list, options, { + title: `Fetching content items by folder: ${folderId}` + }); + } else if (repoId != null) { + const repo = await client.contentRepositories.get(repoId); + + return await paginateWithProgress(repo.related.contentItems.list, options, { + title: `Fetching content items by repository id: ${repoId}` + }); + } else { + const repos = await paginator(hub.related.contentRepositories.list); + + const result: ContentItem[] = []; + for (const repo of repos) { + result.push( + ...(await paginateWithProgress(repo.related.contentItems.list, options, { + title: `Fetching content items for repository: ${repo.id}` + })) + ); + } + + return result; + } + } + + return filtered as ContentItem[]; +}; + +export const getContent = async ( + client: DynamicContent, + hub: Hub, + facetOrString: Facet | string | undefined, + params: GetContentParams +): Promise => { + const result: ContentItem[] = []; + const { repoId, folderId, enrichItems, status } = params; + const baseFetchParams = { enrichItems, status }; + + if (folderId != null) { + const folderIds = Array.isArray(folderId) ? folderId : [folderId]; + for (const folder of folderIds) { + result.push(...(await fetchContent(client, hub, facetOrString, { ...baseFetchParams, folderId: folder }))); + } + } + + if (repoId != null) { + const repoIds = Array.isArray(repoId) ? repoId : [repoId]; + for (const repo of repoIds) { + result.push(...(await fetchContent(client, hub, facetOrString, { ...baseFetchParams, repoId: repo }))); + } + } + + if (folderId == null && repoId == null) { + result.push(...(await fetchContent(client, hub, facetOrString, baseFetchParams))); + } + + return facetOrString ? applyFacet(result, facetOrString) : result; +}; diff --git a/src/common/filter/regex.spec.ts b/src/common/filter/regex.spec.ts new file mode 100644 index 00000000..37c83f09 --- /dev/null +++ b/src/common/filter/regex.spec.ts @@ -0,0 +1,64 @@ +import { hasRegexSpecialCharacter, isRegexString, removeEscapes } from './regex'; + +describe('regex', () => { + describe('isRegexString tests', () => { + it('should return true only if string starts and ends with /', () => { + expect(isRegexString('')).toBeFalsy(); + expect(isRegexString('/')).toBeFalsy(); + expect(isRegexString('nope')).toBeFalsy(); + expect(isRegexString('/not regex')).toBeFalsy(); + expect(isRegexString('/not/regex')).toBeFalsy(); + expect(isRegexString('still not/regex/')).toBeFalsy(); + + expect(isRegexString('/regex/')).toBeTruthy(); + expect(isRegexString('//')).toBeTruthy(); + }); + }); + + describe('hasRegexSpecialCharacter tests', () => { + it('should return true for all regex special characters', () => { + expect(hasRegexSpecialCharacter('')).toBeFalsy(); + expect(hasRegexSpecialCharacter('definitely not')).toBeFalsy(); + + expect(hasRegexSpecialCharacter('character - test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character / test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character ^ test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character $ test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character * test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character + test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character ? test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character . test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character ( test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character ) test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character | test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character [ test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character ] test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character { test')).toBeTruthy(); + expect(hasRegexSpecialCharacter('character } test')).toBeTruthy(); + + expect(hasRegexSpecialCharacter('all -/^$*+?.()|[]{}')).toBeTruthy(); + }); + + it('should return false for escaped regex special characters', () => { + expect(hasRegexSpecialCharacter('still \\* fine')).toBeFalsy(); + expect(hasRegexSpecialCharacter('still \\] fine')).toBeFalsy(); + expect(hasRegexSpecialCharacter('still \\ fine')).toBeFalsy(); + + expect(hasRegexSpecialCharacter('| not \\* fine')).toBeTruthy(); + }); + }); + + describe('removeEscapes tests', () => { + it('should remove escape backslashes', () => { + expect(removeEscapes('\\|')).toEqual('|'); + expect(removeEscapes('text\\|with\\|escaped\\|pipe')).toEqual('text|with|escaped|pipe'); + expect(removeEscapes('\\\\t')).toEqual('\\t'); + expect(removeEscapes('\\\\')).toEqual('\\'); + expect(removeEscapes('\\\\\\')).toEqual('\\'); + expect(removeEscapes('\\')).toEqual(''); + expect(removeEscapes('\\\\\\\\')).toEqual('\\\\'); + expect(removeEscapes('\\\\\\\\\\')).toEqual('\\\\'); + expect(removeEscapes('\\a\\b\\c\\d')).toEqual('abcd'); + }); + }); +}); diff --git a/src/common/filter/regex.ts b/src/common/filter/regex.ts new file mode 100644 index 00000000..c27cce15 --- /dev/null +++ b/src/common/filter/regex.ts @@ -0,0 +1,18 @@ +export function isRegexString(regex: string): boolean { + return regex.length > 1 && regex[0] === '/' && regex[regex.length - 1] === '/'; +} + +export function hasRegexSpecialCharacter(regex: string): boolean { + const regexMatch = /([^\\]|^)(\\\\)*[-\/^$*+?.()|[\]{}]/g; + return regexMatch.test(regex); +} + +export function removeEscapes(regex: string): string { + for (let i = 0; i < regex.length; i++) { + if (regex[i] === '\\') { + regex = regex.substr(0, i) + regex.substr(i + 1); + } + } + + return regex; +} diff --git a/src/common/hub-manager.spec.ts b/src/common/hub-manager.spec.ts new file mode 100644 index 00000000..338bff9a --- /dev/null +++ b/src/common/hub-manager.spec.ts @@ -0,0 +1,230 @@ +import HubManager from '../common/hub-manager'; +import * as sdk from 'dc-management-sdk-js'; +import * as configure from '../commands/configure'; +import fs from 'fs-extra'; +import * as questionHelpers from '../common/question-helpers'; // Adjust the path as needed + +// eslint-disable-next-line +const enquirer = require('enquirer'); + +const DummyHub = { + clientId: 'client-id', + clientSecret: 'client-id', + hubId: 'hub-id', + name: 'dummy-hub' +}; + +const DummyHubWithPAT = { + patToken: 'amp-pat', + hubId: 'hub-id', + name: 'dummy-hub' +}; + +jest.mock('dc-management-sdk-js', () => ({ + ...jest.requireActual('dc-management-sdk-js'), + DynamicContent: jest.fn() +})); + +jest.mock('enquirer', () => ({ + ...jest.requireActual('enquirer'), + AutoComplete: jest.fn(), + Input: jest.fn(), + Password: jest.fn() +})); + +jest.mock('../common/question-helpers'); + +describe('hub manager', function () { + const hubGetMock = jest.fn(); + const autocompleteRun = jest.fn(); + let configureSpy: jest.SpyInstance; + + afterEach((): void => { + jest.restoreAllMocks(); + }); + + afterAll((): void => { + jest.resetAllMocks(); + }); + + beforeEach((): void => { + jest.spyOn(fs, 'writeFileSync').mockImplementation(undefined); + jest.spyOn(fs, 'mkdirpSync').mockReturnValueOnce(undefined); + + configureSpy = jest.spyOn(configure, 'handler').mockReturnValue(); + + hubGetMock.mockReturnValue({ + name: 'dummy-hub' + }); + + autocompleteRun.mockResolvedValue(`${DummyHub.hubId} ${DummyHub.name}`); + + (sdk.DynamicContent as jest.Mock).mockReturnValue({ + hubs: { + get: hubGetMock + } + }); + + (enquirer.AutoComplete as jest.Mock).mockReturnValue({ + run: autocompleteRun + }); + }); + + const yargArgs = { + $0: 'test', + _: ['test'] + }; + + const mockEmptyConfig = (repeats = 1): void => { + const mock = jest.spyOn(fs, 'readJSONSync'); + + for (let i = 0; i < repeats; i++) { + mock.mockReturnValueOnce({}).mockReturnValueOnce([]); + } + }; + + const mockDefaultConfig = (): void => { + jest.spyOn(fs, 'readJSONSync').mockReturnValueOnce(DummyHub).mockReturnValueOnce([DummyHub]); + }; + + it('should create an empty json file if getHubs is called before any are entered', async () => { + mockEmptyConfig(); + + const mockedWriteFileSync = jest.spyOn(fs, 'writeFileSync'); + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(false); + HubManager.getHubs(); + expect(mockedWriteFileSync).toHaveBeenCalled(); + }); + + it('should NOT overwrite hubs.json if it exists already', async () => { + mockEmptyConfig(); + + const mockedWriteFileSync = jest.spyOn(fs, 'writeFileSync'); + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true); + HubManager.getHubs(); + expect(mockedWriteFileSync).not.toHaveBeenCalled(); + }); + + it('should save hub', async () => { + mockEmptyConfig(2); + + const mockedWriteFileSync = jest.spyOn(fs, 'writeFileSync'); + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true); + + (questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(false); + + await HubManager.addHub({ ...yargArgs, ...DummyHub }); + expect(mockedWriteFileSync).toHaveBeenCalled(); + }); + + it('should save hub with PAT token', async () => { + mockEmptyConfig(2); + + const mockedWriteFileSync = jest.spyOn(fs, 'writeFileSync'); + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true); + + (questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(true); + + await HubManager.addHub({ ...yargArgs, ...DummyHubWithPAT }); + expect(mockedWriteFileSync).toHaveBeenCalled(); + }); + + it('should save hub from user input', async () => { + const inputRun = jest.fn().mockResolvedValueOnce('client-id').mockResolvedValueOnce('hub-id'); + const passwordRun = jest.fn().mockResolvedValueOnce('client-secret'); + + (enquirer.Input as jest.Mock).mockReturnValue({ + run: inputRun + }); + + (enquirer.Password as jest.Mock).mockReturnValue({ + run: passwordRun + }); + + mockEmptyConfig(2); + + const mockedWriteFileSync = jest.spyOn(fs, 'writeFileSync'); + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true); + (questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(false); + await HubManager.addHub({ ...yargArgs }); + expect(mockedWriteFileSync).toHaveBeenCalled(); + + expect(inputRun).toHaveBeenCalledTimes(2); + expect(passwordRun).toHaveBeenCalledTimes(1); + }); + + it('should save hub from user input using PAT token', async () => { + const inputRun = jest.fn().mockResolvedValueOnce('hub-id'); + const passwordRun = jest.fn().mockResolvedValueOnce('amp-pat'); + + (enquirer.Input as jest.Mock).mockReturnValue({ + run: inputRun + }); + + (enquirer.Password as jest.Mock).mockReturnValue({ + run: passwordRun + }); + + mockEmptyConfig(2); + + const mockedWriteFileSync = jest.spyOn(fs, 'writeFileSync'); + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true); + (questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(true); + await HubManager.addHub({ ...yargArgs }); + expect(mockedWriteFileSync).toHaveBeenCalled(); + + expect(inputRun).toHaveBeenCalledTimes(1); + expect(passwordRun).toHaveBeenCalledTimes(1); + }); + + it('should fail to save a duplicate hub', async () => { + mockDefaultConfig(); + + jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true); + (questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(false); + await expect(HubManager.addHub({ ...yargArgs, ...DummyHub })).rejects.toThrow(`config already exists`); + }); + + it('should choose the dummy hub', async () => { + mockDefaultConfig(); + + await expect(HubManager.useHub({ ...yargArgs, hub: DummyHub.name })).resolves.toBeDefined(); + + expect(configureSpy).toHaveBeenCalled(); + expect(configureSpy.mock.calls[0][0].hubId).toEqual(DummyHub.hubId); + }); + + it('should fail to choose hub [foo]', async () => { + mockDefaultConfig(); + await expect(HubManager.useHub({ ...yargArgs, hub: 'foo' })).rejects.toThrow(`hub configuration not found`); + + expect(configureSpy).not.toHaveBeenCalled(); + }); + + it('should ask to choose a hub when none is provided and multiple are present', async () => { + jest + .spyOn(fs, 'readJSONSync') + .mockReturnValueOnce(DummyHub) + .mockReturnValueOnce([DummyHub, { ...DummyHub, hubId: 'hub-id2' }]) + .mockReturnValueOnce(DummyHub) + .mockReturnValueOnce([DummyHub, { ...DummyHub, hubId: 'hub-id2' }]); + + await expect(HubManager.useHub({ ...yargArgs, hub: '' })).resolves.toBeDefined(); + + expect(autocompleteRun).toHaveBeenCalledTimes(1); + expect(configureSpy).toHaveBeenCalled(); + expect(configureSpy.mock.calls[0][0].hubId).toEqual(DummyHub.hubId); + }); + + it('should list hubs', async () => { + jest + .spyOn(fs, 'readJSONSync') + .mockReturnValueOnce(DummyHub) + .mockReturnValueOnce([ + { ...DummyHub, isActive: true }, + { ...DummyHub, hubId: 'hub-id2' } + ]); + + HubManager.listHubs(); + }); +}); diff --git a/src/common/hub-manager.ts b/src/common/hub-manager.ts new file mode 100644 index 00000000..a4815d78 --- /dev/null +++ b/src/common/hub-manager.ts @@ -0,0 +1,161 @@ +import { join, dirname } from 'path'; +import fs from 'fs-extra'; +import chalk from 'chalk'; +import { handler as configure, CONFIG_FILENAME } from '../commands/configure'; +import { Arguments } from 'yargs'; +import dynamicContentClientFactory from '../services/dynamic-content-client-factory'; +import { asyncQuestion } from './question-helpers'; + +// eslint-disable-next-line +const { AutoComplete, Input, Password } = require('enquirer'); + +export const CONFIG_PATH = join( + process.env[process.platform == 'win32' ? 'USERPROFILE' : 'HOME'] || __dirname, + '.amplience', + 'hubs.json' +); + +export type HubConfiguration = { + clientId: string; + clientSecret: string; + hubId: string; + name?: string; + isActive?: boolean; + patToken?: string; +}; + +export const validateHub = async (creds: HubConfiguration): Promise => { + const client = dynamicContentClientFactory(creds); + const hub = await client.hubs.get(creds.hubId); + return { + ...creds, + name: hub.name + }; +}; + +const getHubs = (): HubConfiguration[] => { + const activeHub = fs.readJSONSync(CONFIG_FILENAME()); + + fs.mkdirpSync(dirname(CONFIG_PATH)); + if (!fs.existsSync(CONFIG_PATH)) { + fs.writeFileSync(CONFIG_PATH, JSON.stringify([]), { encoding: 'utf-8' }); + } + + const hubs = fs.readJSONSync(CONFIG_PATH, { encoding: 'utf-8' }); + return hubs.map((hub: HubConfiguration) => { + const obj = { + ...hub, + isActive: activeHub.hubId === hub.hubId + }; + + return obj; + }); +}; + +const saveHub = (hub: HubConfiguration): void => { + const hubs = [hub, ...getHubs().filter(h => h.hubId !== hub.hubId)]; + fs.writeFileSync(CONFIG_PATH, JSON.stringify(hubs, undefined, 4), { encoding: 'utf-8' }); +}; + +const activateHub = (creds: HubConfiguration): HubConfiguration => { + // make it active + configure({ + ...creds, + config: CONFIG_FILENAME(), + _: [], + $0: '' + }); + + console.log(`${chalk.green.bold('using')} hub [ ${chalk.green(creds.name || '')} ]`); + return creds; +}; + +// formatting helpers +const ask = async (message: string): Promise => await new Input({ message }).run(); +const secureAsk = async (message: string): Promise => await new Password({ message }).run(); +const helpTag = (message: string): string => chalk.gray(`(${message})`); +const sectionHeader = (message: string): void => console.log(`\n${message}\n`); + +const dcTag = chalk.bold.cyanBright('dynamic content'); +const credentialsHelpText = helpTag('credentials assigned by Amplience support'); +const hubIdHelpText = helpTag('found in hub settings -> properties'); + +export const addHub = async ( + args: Arguments<{ clientId?: string; clientSecret?: string; hubId?: string; patToken?: string }> +): Promise => { + // dc config + sectionHeader(`${dcTag} configuration ${credentialsHelpText}`); + + const usePAT = await asyncQuestion('Would you like to use a PAT Token? (y/n)\n'); + + if (usePAT) { + args.patToken = args.patToken || (await secureAsk(`PAT ${chalk.magenta('token')}:`)); + } else { + // novadev-693 allow id, secret, and hub id to be passed via command line + args.clientId = args.clientId || (await ask(`client ${chalk.magenta('id')}:`)); + args.clientSecret = args.clientSecret || (await secureAsk(`client ${chalk.magenta('secret')}:`)); + } + + args.hubId = args.hubId || (await ask(`hub id ${hubIdHelpText}:`)); + + // unique key for a hub is clientId/hubId + if (args.clientId && getHubs().find(hub => args.clientId === hub.clientId && args.hubId === hub.hubId)) { + throw new Error(`config already exists for client id [ ${args.clientId} ] and hub id [ ${args.hubId} ]`); + } + + if (usePAT && getHubs().find(hub => args.patToken === hub.patToken && args.hubId === hub.hubId)) { + throw new Error(`config already exists for PAT Token and hub id [ ${args.hubId} ]`); + } + + const validated = await validateHub(args as HubConfiguration); + if (validated && validated.name) { + saveHub(validated); + console.log(`${chalk.blueBright('added')} hub [ ${chalk.green(validated.name)} ]`); + await activateHub(validated); + } +}; + +const chooseHub = async (filter: string, exact = false): Promise => { + const filtered = getHubs().filter( + hub => + (hub.name && hub.name.indexOf(filter) > -1) || (exact ? hub.hubId === filter : hub.hubId.indexOf(filter) > -1) + ); + + if (filtered.length === 1) { + return filtered[0]; + } + + if (filtered.length === 0) { + throw new Error(`hub configuration not found for filter [ ${chalk.red(filter)} ]`); + } + + const hubWithId = await new AutoComplete({ + name: 'hub', + message: `choose a hub`, + limit: filtered.length, + multiple: false, + choices: filtered.map(hub => `${hub.hubId} ${hub.name}`), + initial: filtered.findIndex(hub => hub.isActive) + }).run(); + return await chooseHub(hubWithId.split(' ')[0], true); +}; + +const useHub = async (argv: Arguments<{ hub: string }>): Promise => { + const hubConfig = await chooseHub(argv.hub); + return await activateHub(hubConfig); +}; + +const listHubs = (): void => { + getHubs().forEach(hub => { + const hubName = hub.isActive ? chalk.green.bold(`* ${hub.name}`) : ` ${hub.name}`; + console.log(`${hub.hubId} ${hub.clientId?.substring(0, 8) || hub.patToken?.substring(0, 8)} ${hubName}`); + }); +}; + +export default { + getHubs, + addHub, + listHubs, + useHub, + validateHub +}; diff --git a/src/common/import/__mocks__/publish-queue.ts b/src/common/import/__mocks__/publish-queue.ts deleted file mode 100644 index 3082146a..00000000 --- a/src/common/import/__mocks__/publish-queue.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ContentItem } from 'dc-management-sdk-js'; -import { JobRequest } from '../publish-queue'; - -export const publishCalls: ContentItem[] = []; - -export class PublishQueue { - maxWaiting = 3; - attemptDelay = 1000; - failedJobs: JobRequest[] = []; - - waitInProgress = false; - - constructor() { - /* empty */ - } - - async publish(item: ContentItem): Promise { - // TODO: testing ability to throw - - publishCalls.push(item); - - return; - } - - async waitForAll(): Promise { - // TODO: testing ability to throw (in wait for publish) - - return; - } -} diff --git a/src/common/import/date-helpers.spec.ts b/src/common/import/date-helpers.spec.ts new file mode 100644 index 00000000..e1cfe39f --- /dev/null +++ b/src/common/import/date-helpers.spec.ts @@ -0,0 +1,64 @@ +import { dateMax, dateMin, dateOffset, sortByEndDate } from './date-helpers'; + +jest.mock('fs'); + +describe('date-helpers', () => { + describe('dateOffset', () => { + it('should return the current date plus the number of seconds', () => { + const now = Date.now(); + const allowance = 500; //+-0.5s allowance for test variation. + + expect(Math.abs(dateOffset(0).getTime() - now)).toBeLessThan(allowance); + expect(Math.abs(dateOffset(90).getTime() - (now + 90 * 1000))).toBeLessThan(allowance); + expect(Math.abs(dateOffset(23473).getTime() - (now + 23473 * 1000))).toBeLessThan(allowance); + expect(Math.abs(dateOffset(-123).getTime() - (now - 123 * 1000))).toBeLessThan(allowance); + }); + }); + + describe('dateMax', () => { + it('should return the later of two dates', () => { + const earlier = new Date('2022-01-07T15:31:47.337Z'); + const later = new Date('2022-01-07T15:32:47.337Z'); + + expect(dateMax(earlier, later)).toEqual(later); + expect(dateMax(later, earlier)).toEqual(later); + + expect(dateMax(later, later)).toEqual(later); + }); + }); + + describe('dateMin', () => { + it('should return the earlier of two dates', () => { + const earlier = new Date('2022-01-07T15:31:47.337Z'); + const later = new Date('2022-01-07T15:32:47.337Z'); + + expect(dateMin(earlier, later)).toEqual(earlier); + expect(dateMin(later, earlier)).toEqual(earlier); + + expect(dateMin(earlier, earlier)).toEqual(earlier); + }); + }); + + describe('sortByEndDate', () => { + it('should return the dates ordered by end date in ascending order', () => { + const start = new Date('2022-01-07T15:30:47.337Z').toISOString(); + const earlier = { start, end: new Date('2022-01-07T15:31:47.337Z').toISOString() }; + const later = { start, end: new Date('2022-01-07T15:32:47.337Z').toISOString() }; + const latest = { start, end: new Date('2022-01-07T15:33:47.337Z').toISOString() }; + + expect(sortByEndDate([earlier])).toEqual([earlier]); + expect(sortByEndDate([later, earlier])).toEqual([earlier, later]); + expect(sortByEndDate([earlier, later])).toEqual([earlier, later]); + + expect(sortByEndDate([earlier, later, latest])).toEqual([earlier, later, latest]); + expect(sortByEndDate([later, latest, earlier])).toEqual([earlier, later, latest]); + expect(sortByEndDate([latest, later, earlier])).toEqual([earlier, later, latest]); + expect(sortByEndDate([earlier, latest, later])).toEqual([earlier, later, latest]); + expect(sortByEndDate([later, earlier, latest])).toEqual([earlier, later, latest]); + expect(sortByEndDate([latest, earlier, later])).toEqual([earlier, later, latest]); + }); + it('should return an empty array when given one', () => { + expect(sortByEndDate([])).toEqual([]); + }); + }); +}); diff --git a/src/common/import/date-helpers.ts b/src/common/import/date-helpers.ts new file mode 100644 index 00000000..e42dfd1d --- /dev/null +++ b/src/common/import/date-helpers.ts @@ -0,0 +1,23 @@ +export interface TimeRange { + start?: string; + end?: string; +} + +export const dateOffset = (seconds: number): Date => { + const date = new Date(); + date.setSeconds(date.getSeconds() + seconds); + + return date; +}; + +export const dateMax = (date1: Date, date2: Date): Date => { + return date1 > date2 ? date1 : date2; +}; + +export const dateMin = (date1: Date, date2: Date): Date => { + return date1 <= date2 ? date1 : date2; +}; + +export const sortByEndDate = (ranges: Type[]): Type[] => { + return ranges.sort((a, b) => new Date(a.end as string).getTime() - new Date(b.end as string).getTime()); +}; diff --git a/src/common/import/publish-queue.spec.ts b/src/common/import/publish-queue.spec.ts deleted file mode 100644 index e149ccd0..00000000 --- a/src/common/import/publish-queue.spec.ts +++ /dev/null @@ -1,401 +0,0 @@ -import fetch from 'node-fetch'; -import { OAuth2Client, ContentItem, AccessToken } from 'dc-management-sdk-js'; -import { PublishingJob, PublishQueue } from './publish-queue'; - -jest.mock('node-fetch'); -jest.mock('dc-management-sdk-js/build/main/lib/oauth2/services/OAuth2Client'); - -interface PublishTemplate { - href: string; - status: number; - statusText: string; - headers?: Map; - - jsonProvider: (template: PublishTemplate) => PublishingJob; -} - -const defaultTemplate: PublishTemplate = { - href: '', - status: 404, - statusText: 'NOT_FOUND', - - jsonProvider: () => { - throw new Error('Not valid JSON'); - } -}; - -describe('publish-queue', () => { - describe('publishing tests', () => { - let totalPolls = 0; - let totalRequests = 0; - let authRequests = 0; - - beforeEach((): void => { - totalRequests = 0; - totalPolls = 0; - authRequests = 0; - }); - - afterEach((): void => { - jest.resetAllMocks(); - }); - - // should wait for all publishes to complete when calling waitForAll - - function sharedMock(templates: PublishTemplate[]): void { - (OAuth2Client.prototype.getToken as jest.Mock).mockImplementation(() => { - authRequests++; - // eslint-disable-next-line @typescript-eslint/camelcase - const result: AccessToken = { access_token: 'token-example', expires_in: 99999, refresh_token: 'refresh' }; - return Promise.resolve(result); - }); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ((fetch as any) as jest.Mock).mockImplementation((href, options) => { - const template: PublishTemplate = templates.find(template => template.href == href) || defaultTemplate; - - if (options.headers['Authorization'] != 'bearer token-example') { - throw new Error('Not authorized!'); - } - - totalRequests++; - - return Promise.resolve({ - status: template.status, - statusText: template.statusText, - headers: template.headers, - json: jest.fn().mockImplementation(() => Promise.resolve(template.jsonProvider(template))), - text: jest.fn().mockResolvedValue('Error Text') - }); - }); - } - - function getPublishableItem(id: string): ContentItem { - return new ContentItem({ - id: id, - _links: { - publish: { - href: '//publish-' + id - } - } - }); - } - - function publishStartTemplate(href: string, location: string): PublishTemplate { - return { - href: href, - status: 204, - statusText: 'No Content', - headers: new Map([['Location', location]]), - - jsonProvider: (): PublishingJob => { - throw new Error('No body'); - } - }; - } - - function progressStepsTemplate(href: string, polls: number, fail?: boolean | number): PublishTemplate { - let callNumber = 0; - - return { - href: href, - status: 200, - statusText: 'OK', - - jsonProvider: (): PublishingJob => { - const result: PublishingJob = { - id: href, - scheduledDate: '', - createdDate: '', - createdBy: '', - state: 'PREPARING', - _links: { self: { href } } - }; - - totalPolls++; - - if (typeof fail === 'number' && fail == callNumber) { - callNumber++; - throw new Error('Data does not parse.'); - } else { - if (callNumber == 0 && polls > 1) { - result.state = 'PREPARING'; - } else if (callNumber < polls - 1) { - result.state = 'PUBLISHING'; - } else { - result.state = fail === true ? 'FAILED' : 'COMPLETED'; - } - } - - callNumber++; - - return result; - } - }; - } - - function multiMock(count: number, polls: number): ContentItem[] { - const items: ContentItem[] = []; - const templates: PublishTemplate[] = []; - - for (let i = 0; i < count; i++) { - templates.push(publishStartTemplate(`//publish-id${i}`, `//publishJob-id${i}`)); - templates.push(progressStepsTemplate(`//publishJob-id${i}`, polls)); - - items.push(getPublishableItem(`id${i}`)); - } - - sharedMock(templates); - - return items; - } - - function makeQueue(): PublishQueue { - const queue = new PublishQueue({ clientId: 'id', clientSecret: 'secret', hubId: 'hub' }); - queue.attemptDelay = 0; - - return queue; - } - - it('should request a publish using the REST api, with authentication given by the creation arguments', async () => { - const item1 = getPublishableItem('id1'); - sharedMock([ - publishStartTemplate('//publish-id1', '//publishJob-id1'), - progressStepsTemplate('//publishJob-id1', 3) - ]); - - const queue = makeQueue(); - - await queue.publish(item1); - - await queue.waitForAll(); - - expect(authRequests).toBeGreaterThan(0); - expect(totalRequests).toEqual(4); - expect(totalPolls).toEqual(3); - }); - - it('should wait for publish completion when starting a publish and attempting to publish more', async () => { - const items = multiMock(10, 1); // 10 items, return success on the first poll (instant publish) - - const queue = makeQueue(); - - for (let i = 0; i < items.length; i++) { - await queue.publish(items[i]); - - // Starts polling when i == 1, and each time we continue one job has completed. - expect(totalPolls).toEqual(Math.max(0, i)); - } - - await queue.waitForAll(); - - expect(totalPolls).toEqual(10); - }); - - it('should never wait for publish completion when starting a publish, only when waiting or publishing more', async () => { - const items = multiMock(1, 1); // 10 items, return success on the first poll (instant publish) - - const queue = makeQueue(); // After 1 concurrent request, start waiting. - - for (let i = 0; i < items.length; i++) { - await queue.publish(items[i]); - } - - expect(totalPolls).toEqual(0); - - await queue.waitForAll(); - - expect(totalPolls).toEqual(1); - }); - - it('should complete immediately when calling waitForAll with no publishes in progress', async () => { - const queue = makeQueue(); - - await queue.waitForAll(); - - expect(totalPolls).toEqual(0); - }); - - it('should throw an error when publish link is not present', async () => { - const item1 = getPublishableItem('id1'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (item1 as any)._links = {}; - sharedMock([ - publishStartTemplate('//publish-id1', '//publishJob-id1'), - progressStepsTemplate('//publishJob-id1', 3) - ]); - - const queue = makeQueue(); - - let threw = false; - try { - await queue.publish(item1); - } catch (e) { - threw = true; - } - - expect(threw).toBeTruthy(); - - await queue.waitForAll(); - - expect(totalPolls).toEqual(0); - }); - - it('should throw an error when publish POST response headers do not include a Location for the job status', async () => { - const item1 = getPublishableItem('id1'); - sharedMock([ - { - href: '//publish-id1', - status: 204, - statusText: 'No Content', - headers: new Map(), - - jsonProvider: (): PublishingJob => { - throw new Error('No body'); - } - }, - progressStepsTemplate('//publishJob-id1', 3) - ]); - - const queue = makeQueue(); - - let threw = false; - try { - await queue.publish(item1); - } catch (e) { - threw = true; - } - - expect(threw).toBeTruthy(); - - await queue.waitForAll(); - - expect(totalPolls).toEqual(0); - }); - - it('should throw an error when publish fails to start (request is not OK)', async () => { - const item1 = getPublishableItem('id1'); - sharedMock([ - { - href: '//publish-id1', - status: 500, - statusText: 'Internal Server Error', - - jsonProvider: (): PublishingJob => { - throw new Error('No body'); - } - }, - progressStepsTemplate('//publishJob-id1', 3) - ]); - - const queue = makeQueue(); - - let threw = false; - try { - await queue.publish(item1); - } catch (e) { - threw = true; - } - - expect(threw).toBeTruthy(); - - await queue.waitForAll(); - - expect(totalPolls).toEqual(0); - }); - - it('should ignore an attempt waiting for job status if fetching it does not succeed, and request again later as usual', async () => { - const item1 = getPublishableItem('id1'); - - sharedMock([ - publishStartTemplate('//publish-id1', '//publishJob-id1'), - progressStepsTemplate('//publishJob-id1', 3, 1) - ]); - - const queue = makeQueue(); - - await queue.publish(item1); - - await queue.waitForAll(); - - expect(queue.failedJobs.length).toEqual(0); - expect(totalPolls).toEqual(3); - expect(totalRequests).toEqual(4); - }); - - it('should report failed publishes in the failedJobs list', async () => { - const item1 = getPublishableItem('id1'); - const item2 = getPublishableItem('id2'); // fails - const item3 = getPublishableItem('id3'); // fails - - sharedMock([ - publishStartTemplate('//publish-id1', '//publishJob-id1'), - progressStepsTemplate('//publishJob-id1', 1), - publishStartTemplate('//publish-id2', '//publishJob-id2'), - progressStepsTemplate('//publishJob-id2', 1, true), - publishStartTemplate('//publish-id3', '//publishJob-id3'), - progressStepsTemplate('//publishJob-id3', 1, true) - ]); - - const queue = makeQueue(); - - await queue.publish(item1); - await queue.publish(item2); - await queue.publish(item3); - - await queue.waitForAll(); - - expect(queue.failedJobs.length).toEqual(2); - expect(queue.failedJobs[0].item).toEqual(item2); - expect(queue.failedJobs[1].item).toEqual(item3); - expect(totalPolls).toEqual(3); - expect(totalRequests).toEqual(6); - }); - - it('should still correctly waitForAll if a previous publish is waiting to start', async () => { - const items = multiMock(10, 1); // 10 items, return success on the first poll (instant publish) - - const queue = makeQueue(); - - for (let i = 0; i < items.length; i++) { - // Deliberately avoid waiting after starting the first publish that would have to wait. - // This is an unlikely situation, but handling it consistently is useful. - - if (i < 5) { - await queue.publish(items[i]); - } else { - queue.publish(items[i]); - } - } - - await queue.waitForAll(); - - expect(totalPolls).toEqual(10); - }); - - it('should error publishes when waiting for a publish job exceeds the maxAttempts number', async () => { - const items = multiMock(3, 5); // 3 items, return success on the 5th poll (after our limit) - - const queue = makeQueue(); // After 1 concurrent request, start waiting. - queue.maxAttempts = 2; // Fail after 2 incomplete polls. - - for (let i = 0; i < items.length; i++) { - await queue.publish(items[i]); - - if (queue.failedJobs.length > 0) { - // The first job should have failed. - expect(i).toEqual(1); // We only waited for the first job after the second was put in the queue. - expect(queue.failedJobs[0].item).toBe(items[0]); - break; - } - - expect(i).toBeLessThan(1); - } - - await queue.waitForAll(); - - expect(totalPolls).toEqual(4); // 2 total publish requests. 2 waits before each before giving up. - expect(queue.failedJobs.length).toEqual(2); - }); - }); -}); diff --git a/src/common/import/publish-queue.ts b/src/common/import/publish-queue.ts deleted file mode 100644 index e28bf1aa..00000000 --- a/src/common/import/publish-queue.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { ContentItem, OAuth2Client, AxiosHttpClient } from 'dc-management-sdk-js'; -import fetch, { Response } from 'node-fetch'; -import { HalLink } from 'dc-management-sdk-js/build/main/lib/hal/models/HalLink'; -import { ConfigurationParameters } from '../../commands/configure'; - -export interface PublishingJob { - id: string; - scheduledDate: string; - createdDate: string; - createdBy: string; - state: 'PREPARING' | 'PUBLISHING' | 'COMPLETED' | 'FAILED'; - - _links?: { [name: string]: HalLink }; -} - -async function delay(duration: number): Promise { - return new Promise((resolve): void => { - setTimeout(resolve, duration); - }); -} - -export interface JobRequest { - item: ContentItem; - href: string; -} - -export class PublishQueue { - maxAttempts = 30; - attemptDelay = 1000; - failedJobs: JobRequest[] = []; - - private inProgressJobs: JobRequest[] = []; - private waitingList: { promise: Promise; resolver: () => void }[] = []; - private auth: OAuth2Client; - private awaitingAll: boolean; - - waitInProgress = false; - - constructor(credentials: ConfigurationParameters) { - const http = new AxiosHttpClient({}); - this.auth = new OAuth2Client( - // eslint-disable-next-line @typescript-eslint/camelcase - { client_id: credentials.clientId, client_secret: credentials.clientSecret }, - { authUrl: process.env.AUTH_URL }, - http - ); - } - - private async getToken(): Promise { - const token = await this.auth.getToken(); - return token.access_token; - } - - private async fetch(href: string, method: string): Promise { - return await fetch(href, { method: method, headers: { Authorization: 'bearer ' + (await this.getToken()) } }); - } - - async publish(item: ContentItem): Promise { - await this.rateLimit(); - - // Do publish - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const publishLink = (item._links as any)['publish']; - - if (publishLink == null) { - throw new Error('Cannot publish the item - link not available.'); - } - - // Need to manually fetch the publish endpoint. - - const publish = await this.fetch(publishLink.href, 'POST'); - if (publish.status != 204) { - throw new Error(`Failed to start publish: ${publish.statusText} - ${await publish.text()}`); - } - - const publishJobInfoHref = publish.headers.get('Location'); - - if (publishJobInfoHref == null) { - throw new Error('Expected publish job location in header. Has the publish workflow changed?'); - } - - this.inProgressJobs.push({ href: publishJobInfoHref, item }); - } - - private async waitForOldestPublish(): Promise { - if (this.inProgressJobs.length === 0) { - return; - } - - this.waitInProgress = true; - - const oldestJob = this.inProgressJobs[0]; - this.inProgressJobs.splice(0, 1); - - // Request the status for the oldest ID. - // If it's still not published/errored, then wait a bit and try again. - - let attempts = 0; - for (; attempts < this.maxAttempts; attempts++) { - let job: PublishingJob; - try { - job = await (await this.fetch(oldestJob.href, 'GET')).json(); - } catch (e) { - // Could not fetch job information. - continue; - } - - if (job.state === 'COMPLETED') { - break; - } else if (job.state === 'FAILED') { - this.failedJobs.push(oldestJob); - break; - } else { - await delay(this.attemptDelay); - } - } - - if (attempts == this.maxAttempts) { - this.failedJobs.push(oldestJob); - } - - // The wait completed. Notify the first in the queue. - - const oldestWaiter = this.waitingList[0]; - if (oldestWaiter != null) { - this.waitingList.splice(0, 1); - - oldestWaiter.resolver(); // Resolve the promise. - } - - if (this.waitingList.length > 0 || this.awaitingAll) { - // Still more waiting. - await this.waitForOldestPublish(); - } else { - this.waitInProgress = false; - } - } - - private async rateLimit(): Promise { - if (this.inProgressJobs.length == 0) { - return; - } - - // We need to wait. - let resolver: () => void = () => { - /* */ - }; - const myPromise = new Promise((resolve): void => { - resolver = resolve; - }); - - this.waitingList.push({ promise: myPromise, resolver: resolver }); - - if (!this.waitInProgress) { - // Start a wait. - this.waitForOldestPublish(); - } - - await myPromise; - } - - async waitForAll(): Promise { - if (this.waitInProgress) { - // Wait for the last item on the list to complete. - await this.waitingList[this.waitingList.length - 1].promise; - } - - // Continue regardless of waiters. - this.awaitingAll = true; - await this.waitForOldestPublish(); - } -} diff --git a/src/common/json-resolver/json-resolver.spec.ts b/src/common/json-resolver/json-resolver.spec.ts index ce25470e..516558db 100644 --- a/src/common/json-resolver/json-resolver.spec.ts +++ b/src/common/json-resolver/json-resolver.spec.ts @@ -6,7 +6,7 @@ import path from 'path'; jest.mock('fs'); jest.mock('path'); -describe('content type schema helper', function() { +describe('content type schema helper', function () { beforeEach((): void => { jest.resetAllMocks(); }); @@ -23,9 +23,7 @@ describe('content type schema helper', function() { 2 ); - const scope = nock(basePath) - .get(path) - .reply(200, data); + const scope = nock(basePath).get(path).reply(200, data); const response = await jsonResolver(url); @@ -33,11 +31,11 @@ describe('content type schema helper', function() { expect(response).toEqual(data); } - it('should load JSON from a url (http) as object', async function() { + it('should load JSON from a url (http) as object', async function () { await successfulAxiosGetInvocation('http://example.com', '/schema.json'); }); - it('should load JSON from a url (https) as object', async function() { + it('should load JSON from a url (https) as object', async function () { await successfulAxiosGetInvocation('https://example.com', '/schema.json'); }); }); @@ -57,25 +55,25 @@ describe('content type schema helper', function() { expect(response).toEqual(JSON.stringify(mockSchemaData)); } - it('should load JSON from a local file (relative path) using __dirname as relative dir', async function() { + it('should load JSON from a local file (relative path) using __dirname as relative dir', async function () { const mockPathResolve = path.resolve as jest.Mock; await successfulLocalFileInvocation('./content-type-schema/schema.json'); expect(mockPathResolve).toHaveBeenCalledWith(__dirname, './content-type-schema/schema.json'); }); - it('should load JSON from a local file (relative path) using a supplied relative dir', async function() { + it('should load JSON from a local file (relative path) using a supplied relative dir', async function () { const mockPathResolve = path.resolve as jest.Mock; await successfulLocalFileInvocation('./content-type-schema/schema.json', '/foo'); expect(mockPathResolve).toHaveBeenCalledWith('/foo', './content-type-schema/schema.json'); }); - it('should load JSON from a local file (windows relative path) using a supplied relative dir', async function() { + it('should load JSON from a local file (windows relative path) using a supplied relative dir', async function () { const mockPathResolve = path.resolve as jest.Mock; await successfulLocalFileInvocation('.\\content-type-schema\\schema.json', '\\foo'); expect(mockPathResolve).toHaveBeenCalledWith('\\foo', '.\\content-type-schema\\schema.json'); }); - it('should load JSON from a local file (with file url)', async function() { + it('should load JSON from a local file (with file url)', async function () { await successfulLocalFileInvocation('file://content-type-schema/schema.json'); }); }); @@ -88,42 +86,42 @@ describe('content type schema helper', function() { jest.resetAllMocks(); }); - it('should load valid JSON (Object as string passed in)', async function() { + it('should load valid JSON (Object as string passed in)', async function () { const json = { foo: 'bar', bar: 'baz' }; const response = await jsonResolver(JSON.stringify(json)); expect(mockFileRead).toHaveBeenCalledTimes(0); expect(response).toEqual(JSON.stringify(json)); }); - it('should load valid JSON (Object as escaped string passed in)', async function() { + it('should load valid JSON (Object as escaped string passed in)', async function () { const escapedjson = '{"foo":"bar","bar":"baz"}'; const response = await jsonResolver(escapedjson); expect(mockFileRead).toHaveBeenCalledTimes(0); expect(response).toEqual(escapedjson); }); - it('should load valid JSON (Array passed in)', async function() { + it('should load valid JSON (Array passed in)', async function () { const json = [{ foo: 'bar', bar: 'baz' }]; const response = await jsonResolver(JSON.stringify(json)); expect(mockFileRead).toHaveBeenCalledTimes(0); expect(response).toEqual(JSON.stringify(json)); }); - it('should fail to load invalid JSON and fall out at the end (null passed in)', async function() { + it('should fail to load invalid JSON and fall out at the end (null passed in)', async function () { mockExistsSync.mockReturnValue(false); await expect(jsonResolver('null', '/tmp')).rejects.toThrowErrorMatchingSnapshot(); expect(mockFileRead).not.toHaveBeenCalled(); }); - it('should fail to load invalid JSON and fall out at the end', async function() { + it('should fail to load invalid JSON and fall out at the end', async function () { mockExistsSync.mockReturnValue(false); await expect(jsonResolver('this is just a string', '/tmp')).rejects.toThrowErrorMatchingSnapshot(); expect(mockFileRead).not.toHaveBeenCalled(); }); - it('should fail to load invalid JSON and fall out at the end (undefined passing in)', async function() { + it('should fail to load invalid JSON and fall out at the end (undefined passing in)', async function () { mockExistsSync.mockReturnValue(false); await expect(jsonResolver(undefined, '/tmp')).rejects.toThrowErrorMatchingSnapshot(); diff --git a/src/common/media/__mocks__/ch-client-factory.ts b/src/common/media/__mocks__/ch-client-factory.ts index 86580440..b8d1c075 100644 --- a/src/common/media/__mocks__/ch-client-factory.ts +++ b/src/common/media/__mocks__/ch-client-factory.ts @@ -4,6 +4,6 @@ import { ConfigurationParameters } from '../../../commands/configure'; import { MockContentHub } from '../mock-ch'; // eslint-disable-next-line @typescript-eslint/no-unused-vars -const chClientFactory = (_: ConfigurationParameters): ContentHub => (new MockContentHub() as any) as ContentHub; +const chClientFactory = (_: ConfigurationParameters): ContentHub => new MockContentHub() as any as ContentHub; export default chClientFactory; diff --git a/src/common/media/__mocks__/media-rewriter.ts b/src/common/media/__mocks__/media-rewriter.ts index da2fdfd1..ce17f4f2 100644 --- a/src/common/media/__mocks__/media-rewriter.ts +++ b/src/common/media/__mocks__/media-rewriter.ts @@ -4,7 +4,10 @@ import { RepositoryContentItem } from '../../content-item/content-dependancy-tre export class MediaRewriter { static rewrites = 0; - constructor(private config: ConfigurationParameters, private items: RepositoryContentItem[]) {} + constructor( + private config: ConfigurationParameters, + private items: RepositoryContentItem[] + ) {} async rewrite(): Promise> { MediaRewriter.rewrites++; diff --git a/src/common/media/media-rewriter.spec.ts b/src/common/media/media-rewriter.spec.ts index c23d3586..f583855c 100644 --- a/src/common/media/media-rewriter.spec.ts +++ b/src/common/media/media-rewriter.spec.ts @@ -7,14 +7,6 @@ import { MockContentHub } from './mock-ch'; jest.mock('../../services/ch-client-factory'); -// eslint-disable-next-line @typescript-eslint/no-explicit-any -jest.mock('promise-retry', () => (fn: unknown, options: any): unknown => { - const retryActual = jest.requireActual('promise-retry'); - options.minTimeout = 0; - options.maxTimeout = 0; - return retryActual(fn, options); -}); - let exampleLinks: RepositoryContentItem[] = []; describe('media-link-injector', () => { @@ -146,7 +138,7 @@ describe('media-link-injector', () => { const rewriter = new MediaRewriter({ clientId: '', clientSecret: '', hubId: '' }, []); await expect(rewriter.rewrite()).rejects.toThrowErrorMatchingInlineSnapshot( - `"Could not obtain settings from DAM. Make sure you have the required permissions. Error: Simulated settings error."` + `"Could not obtain settings from DAM. Make sure you have the required permissions: Simulated settings error."` ); }); @@ -159,32 +151,6 @@ describe('media-link-injector', () => { ); }); - it('should fail when getting assets does not work a certain number of times in a row', async () => { - MockContentHub.throwOnAssetList = true; - const rewriter = new MediaRewriter({ clientId: '', clientSecret: '', hubId: '' }, exampleLinks); - - await expect(rewriter.rewrite()).rejects.toThrowErrorMatchingInlineSnapshot( - `"Request for assets failed after 3 attempts."` - ); - - expect(MockContentHub.requests).toMatchInlineSnapshot(` - Array [ - Object { - "n": 4, - "q": "(name:/imageProperty|imageNested|imageArray1|imageArray2/)", - }, - Object { - "n": 4, - "q": "(name:/imageProperty|imageNested|imageArray1|imageArray2/)", - }, - Object { - "n": 4, - "q": "(name:/imageProperty|imageNested|imageArray1|imageArray2/)", - }, - ] - `); - }); - it('should make multiple asset requests if the query gets too long (3000 chars)', async () => { const expectedCharLimit = 3000; const expectedRequests = 3; diff --git a/src/common/media/media-rewriter.ts b/src/common/media/media-rewriter.ts index 9b5313cb..771059c0 100644 --- a/src/common/media/media-rewriter.ts +++ b/src/common/media/media-rewriter.ts @@ -5,7 +5,6 @@ import { ConfigurationParameters } from '../../commands/configure'; import chClientFactory from '../../services/ch-client-factory'; import { RepositoryContentItem } from '../content-item/content-dependancy-tree'; import { MediaLinkInjector } from '../content-item/media-link-injector'; -import promiseRetry from 'promise-retry'; /** * Exports media related to given content items from an existing repository. @@ -18,7 +17,10 @@ export class MediaRewriter { private endpoint: string; private defaultHost: string; - constructor(private config: ConfigurationParameters, private items: RepositoryContentItem[]) { + constructor( + private config: ConfigurationParameters, + private items: RepositoryContentItem[] + ) { this.injector = new MediaLinkInjector(items); } @@ -39,7 +41,7 @@ export class MediaRewriter { return endpoint.id === settings.di.defaultEndpoint; }); } catch (e) { - throw new Error(`Could not obtain settings from DAM. Make sure you have the required permissions. ${e}`); + throw new Error(`Could not obtain settings from DAM. Make sure you have the required permissions: ${e.message}`); } if (endpoint == null) { @@ -51,36 +53,18 @@ export class MediaRewriter { } private async queryAndAdd(query: string, count: number, assets: Map): Promise { - let attemptCount = 0; + const result = await this.dam.assets.list({ + q: '(' + query + ')', + n: count + }); - try { - return await promiseRetry( - async (retry, attempt) => { - try { - const result = await this.dam.assets.list({ - q: '(' + query + ')', - n: count - }); - - const items = result.getItems(); - - items.forEach(asset => { - assets.set(asset.name as string, asset); - }); - - return items.length; - } catch (e) { - attemptCount = attempt; - retry(e); - return 0; - } - }, - { retries: 2 } - ); - } catch (e) { - // Too many retries, fail the request. - throw new Error(`Request for assets failed after ${attemptCount} attempts.`); - } + const items = result.getItems(); + + items.forEach(asset => { + assets.set(asset.name as string, asset); + }); + + return items.length; } private getLinkNames(): Set { diff --git a/src/common/progress-bar/progress-bar.ts b/src/common/progress-bar/progress-bar.ts new file mode 100644 index 00000000..bb7bccce --- /dev/null +++ b/src/common/progress-bar/progress-bar.ts @@ -0,0 +1,14 @@ +import cliProgress from 'cli-progress'; + +export const createProgressBar = ({ title = 'Progress' }) => { + return new cliProgress.SingleBar({ + format: `${title} | {bar} | {percentage}% || {value}/{total}` + }); +}; + +export const progressBar = (total: number, start: number, { title = 'Progress' }) => { + const progress = createProgressBar({ title }); + progress.start(total, start); + + return progress; +}; diff --git a/src/common/publish/publish-options.ts b/src/common/publish/publish-options.ts new file mode 100644 index 00000000..e8f6ffcc --- /dev/null +++ b/src/common/publish/publish-options.ts @@ -0,0 +1,11 @@ +import { FileLog } from '../file-log'; + +export default interface PublishOptions { + id?: string | string[]; + repoId?: string | string[]; + folderId?: string | string[]; + facet?: string; + logFile: FileLog; + force?: boolean; + silent?: boolean; +} diff --git a/src/common/publishing/content-item-publishing-job-service.spec.ts b/src/common/publishing/content-item-publishing-job-service.spec.ts new file mode 100644 index 00000000..9c4503d9 --- /dev/null +++ b/src/common/publishing/content-item-publishing-job-service.spec.ts @@ -0,0 +1,62 @@ +import { DynamicContent, PublishingJob } from 'dc-management-sdk-js'; +import { PublishingJobStatus } from 'dc-management-sdk-js/build/main/lib/model/PublishingJobStatus'; +import { ContentItemPublishingJobService } from './content-item-publishing-job-service'; + +jest.mock('../burstable-queue/burstable-queue', () => ({ + BurstableQueue: jest.fn().mockImplementation(() => ({ + add: (fn: () => Promise) => fn(), + onIdle: async () => Promise.resolve() + })) +})); + +const mockClient: { + publishingJob: { + get: jest.Mock, [string]>; + }; +} = { + publishingJob: { + get: jest.fn() + } +}; + +describe('ContentItemPublishingJobService', () => { + let service: ContentItemPublishingJobService; + const baseJob = { id: 'job1' } as PublishingJob; + + beforeEach(() => { + jest.clearAllMocks(); + service = new ContentItemPublishingJobService(mockClient as unknown as DynamicContent); + }); + + it('calls callback when job completes', async () => { + (mockClient.publishingJob.get as jest.Mock).mockResolvedValue({ ...baseJob, state: PublishingJobStatus.COMPLETED }); + + const cb = jest.fn(); + await service.check(baseJob, cb); + await service.onIdle(); + + expect(cb).toHaveBeenCalledWith(expect.objectContaining({ state: PublishingJobStatus.COMPLETED })); + }); + + it('calls callback when job fails', async () => { + (mockClient.publishingJob.get as jest.Mock).mockResolvedValue({ ...baseJob, state: PublishingJobStatus.FAILED }); + + const cb = jest.fn(); + await service.check(baseJob, cb); + await service.onIdle(); + + expect(cb).toHaveBeenCalledWith(expect.objectContaining({ state: PublishingJobStatus.FAILED })); + }); + + it('retries until job is done', async () => { + (mockClient.publishingJob.get as jest.Mock) + .mockResolvedValueOnce({ ...baseJob, state: PublishingJobStatus.PREPARING }) + .mockResolvedValueOnce({ ...baseJob, state: PublishingJobStatus.COMPLETED }); + + const cb = jest.fn(); + await service.check(baseJob, cb); + await service.onIdle(); + + expect(cb).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/common/publishing/content-item-publishing-job-service.ts b/src/common/publishing/content-item-publishing-job-service.ts new file mode 100644 index 00000000..6af193a6 --- /dev/null +++ b/src/common/publishing/content-item-publishing-job-service.ts @@ -0,0 +1,41 @@ +import { DynamicContent, PublishingJob } from 'dc-management-sdk-js'; +import { BurstableQueue } from '../burstable-queue/burstable-queue'; +import { PublishingJobStatus } from 'dc-management-sdk-js/build/main/lib/model/PublishingJobStatus'; + +export class ContentItemPublishingJobService { + private client; + private queue; + + constructor(client: DynamicContent) { + this.client = client; + this.queue = new BurstableQueue({}); + } + + async check(publishingJob: PublishingJob, action: (publishingJob: PublishingJob) => Promise) { + this.queue.add(async () => { + const latestPublishJob = await this.client.publishingJob.get(publishingJob.id); + + if ( + latestPublishJob.state === PublishingJobStatus.FAILED || + latestPublishJob.state === PublishingJobStatus.COMPLETED + ) { + action(latestPublishJob); + } else { + // if publish has not been done then add it to the back of the queue + this.check(latestPublishJob, action); + } + }); + } + + async onIdle() { + return this.queue.onIdle(); + } + + get size() { + return this.queue.size(); + } + + get pending() { + return this.queue.pending(); + } +} diff --git a/src/common/publishing/content-item-publishing-service.spec.ts b/src/common/publishing/content-item-publishing-service.spec.ts new file mode 100644 index 00000000..5b9060a9 --- /dev/null +++ b/src/common/publishing/content-item-publishing-service.spec.ts @@ -0,0 +1,51 @@ +import { ContentItem, PublishingJob } from 'dc-management-sdk-js'; +import { ContentItemPublishingService } from './content-item-publishing-service'; + +jest.mock('../burstable-queue/burstable-queue', () => ({ + BurstableQueue: jest.fn().mockImplementation(() => ({ + add: (fn: () => Promise) => fn(), + onIdle: async () => Promise.resolve() + })) +})); + +const createMockContentItem = (id: string, jobId: string): ContentItem => { + const publishJob: PublishingJob = { id: jobId } as PublishingJob; + const publishLocation = { related: { publishingJob: jest.fn().mockResolvedValue(publishJob) } }; + return { + id, + related: { publish: jest.fn().mockResolvedValue(publishLocation) } + } as unknown as ContentItem; +}; + +describe('ContentItemPublishingService', () => { + let service: ContentItemPublishingService; + let item1: ContentItem; + let item2: ContentItem; + + beforeEach(() => { + service = new ContentItemPublishingService(); + item1 = createMockContentItem('item-1', 'job-1'); + item2 = createMockContentItem('item-2', 'job-2'); + }); + + it('publishes a content item and stores the job', async () => { + const cb = jest.fn(); + + await service.publish(item1, cb); + await service.onIdle(); + + expect(cb).toHaveBeenCalledWith(item1, expect.objectContaining({ id: 'job-1' })); + expect(service.publishJobs.map(j => j.id)).toEqual(['job-1']); + }); + + it('handles multiple publishes', async () => { + const cb = jest.fn(); + + await service.publish(item1, cb); + await service.publish(item2, cb); + await service.onIdle(); + + expect(cb).toHaveBeenCalledTimes(2); + expect(service.publishJobs.map(j => j.id)).toEqual(['job-1', 'job-2']); + }); +}); diff --git a/src/common/publishing/content-item-publishing-service.ts b/src/common/publishing/content-item-publishing-service.ts new file mode 100644 index 00000000..ef93c930 --- /dev/null +++ b/src/common/publishing/content-item-publishing-service.ts @@ -0,0 +1,28 @@ +import { ContentItem, PublishingJob } from 'dc-management-sdk-js'; +import { BurstableQueue } from '../burstable-queue/burstable-queue'; + +export class ContentItemPublishingService { + private queue; + private _publishJobs: PublishingJob[] = []; + + constructor() { + this.queue = new BurstableQueue({}); + } + + async publish(contentItem: ContentItem, action: (contentItem: ContentItem, publishJob: PublishingJob) => void) { + this.queue.add(async () => { + const publishJobLocation = await contentItem.related.publish(); + const publishJob = await publishJobLocation.related.publishingJob(); + this._publishJobs.push(publishJob); + action(contentItem, publishJob); + }); + } + + get publishJobs() { + return this._publishJobs; + } + + async onIdle() { + return this.queue.onIdle(); + } +} diff --git a/src/common/publishing/content-item-unpublishing-service.spec.ts b/src/common/publishing/content-item-unpublishing-service.spec.ts new file mode 100644 index 00000000..30fa6777 --- /dev/null +++ b/src/common/publishing/content-item-unpublishing-service.spec.ts @@ -0,0 +1,81 @@ +import { ContentItem, ContentItemPublishingStatus } from 'dc-management-sdk-js'; +import { ContentItemUnpublishingService } from './content-item-unpublishing-service'; + +jest.mock('../burstable-queue/burstable-queue', () => { + return { + BurstableQueue: jest.fn().mockImplementation(() => ({ + add: (fn: () => Promise) => fn(), + onIdle: jest.fn().mockResolvedValue(undefined) + })) + }; +}); + +const createMockContentItem = ( + id: string, + status: ContentItemPublishingStatus = ContentItemPublishingStatus.LATEST +): ContentItem => { + return { + id, + publishingStatus: status, + related: { + unpublish: jest.fn().mockImplementationOnce(() => Promise.resolve()) + } + } as unknown as ContentItem; +}; + +describe('ContentItemUnpublishingService', () => { + let service: ContentItemUnpublishingService; + + beforeEach(() => { + service = new ContentItemUnpublishingService(); + }); + + it('unpublishes a content item that has a status of LATEST', async () => { + const item = createMockContentItem('item-latest', ContentItemPublishingStatus.LATEST); + const action = jest.fn(); + + await service.unpublish(item, action); + await service.onIdle(); + + expect(item.related.unpublish).toHaveBeenCalled(); + expect(action).toHaveBeenCalled(); + + expect(item.related.unpublish).toHaveBeenCalledTimes(1); + expect(action).toHaveBeenCalledWith(expect.objectContaining({ id: 'item-latest' })); + expect(action).toHaveBeenCalledTimes(1); + }); + + it('unpublishes a content item that has a status of EARLY', async () => { + const item = createMockContentItem('item-early', ContentItemPublishingStatus.EARLY); + const action = jest.fn(); + + await service.unpublish(item, action); + await service.onIdle(); + + expect(item.related.unpublish).toHaveBeenCalledTimes(1); + expect(action).toHaveBeenCalledWith(expect.objectContaining({ id: 'item-early' })); + expect(action).toHaveBeenCalledTimes(1); + }); + + it('does not unpublish if content item has a status of NONE', async () => { + const item = createMockContentItem('item-none', ContentItemPublishingStatus.NONE); + const action = jest.fn(); + + await service.unpublish(item, action); + await service.onIdle(); + + expect(item.related.unpublish).not.toHaveBeenCalled(); + expect(action).toHaveBeenCalled(); + }); + + it('does not unpublish if content item has a status of UNPUBLISHED', async () => { + const item = createMockContentItem('item-unpublished', ContentItemPublishingStatus.UNPUBLISHED); + const action = jest.fn(); + + await service.unpublish(item, action); + await service.onIdle(); + + expect(item.related.unpublish).not.toHaveBeenCalled(); + expect(action).toHaveBeenCalled(); + }); +}); diff --git a/src/common/publishing/content-item-unpublishing-service.ts b/src/common/publishing/content-item-unpublishing-service.ts new file mode 100644 index 00000000..8ca65a56 --- /dev/null +++ b/src/common/publishing/content-item-unpublishing-service.ts @@ -0,0 +1,26 @@ +import { ContentItem, ContentItemPublishingStatus } from 'dc-management-sdk-js'; +import { BurstableQueue } from '../burstable-queue/burstable-queue'; + +export class ContentItemUnpublishingService { + private queue; + + constructor() { + this.queue = new BurstableQueue({}); + } + + async unpublish(contentItem: ContentItem, action: (contentItem: ContentItem) => void) { + const canUnpublish = (state: ContentItemPublishingStatus | undefined) => + state && [ContentItemPublishingStatus.LATEST, ContentItemPublishingStatus.EARLY].includes(state); + this.queue.add(async () => { + if (canUnpublish(contentItem.publishingStatus)) { + await contentItem.related.unpublish(); + } + + action(contentItem); + }); + } + + async onIdle() { + return this.queue.onIdle(); + } +} diff --git a/src/common/webhooks/get-all-webhook.ts b/src/common/webhooks/get-all-webhook.ts new file mode 100644 index 00000000..0a882817 --- /dev/null +++ b/src/common/webhooks/get-all-webhook.ts @@ -0,0 +1,6 @@ +import { Hub } from 'dc-management-sdk-js'; +import paginator from '../dc-management-sdk-js/paginator'; + +export const getAllWebhooks = async (hub: Hub) => { + return await paginator(hub.related.webhooks.list); +}; diff --git a/src/common/webhooks/get-webhooks-by-ids.ts b/src/common/webhooks/get-webhooks-by-ids.ts new file mode 100644 index 00000000..0d268ffe --- /dev/null +++ b/src/common/webhooks/get-webhooks-by-ids.ts @@ -0,0 +1,15 @@ +import { Hub } from 'dc-management-sdk-js'; + +export const getWebhooksByIds = async (hub: Hub, ids: string[]) => { + const webhooks = []; + + for (const id of ids) { + try { + webhooks.push(await hub.related.webhooks.get(id)); + } catch (e) { + // silently fail missing webhooks + } + } + + return webhooks; +}; diff --git a/src/common/yargs/sorting-options.spec.ts b/src/common/yargs/sorting-options.spec.ts index 6e7ca798..77e6b646 100644 --- a/src/common/yargs/sorting-options.spec.ts +++ b/src/common/yargs/sorting-options.spec.ts @@ -1,13 +1,13 @@ import { extractSortable } from './sorting-options'; -describe('paging options', function() { - describe('extractSortable tests', function() { - it('should return a default empty object when supplied an empty object', function() { +describe('paging options', function () { + describe('extractSortable tests', function () { + it('should return a default empty object when supplied an empty object', function () { const result = extractSortable({}); expect(result).toEqual({}); }); - it('should return the sort value', function() { + it('should return the sort value', function () { const result = extractSortable({ sort: 'createdBy,asc' }); expect(result).toEqual({ sort: 'createdBy,asc' }); }); diff --git a/src/common/yargs/yargs-object-transformer.spec.ts b/src/common/yargs/yargs-object-transformer.spec.ts index b4cc576a..7e179cdc 100644 --- a/src/common/yargs/yargs-object-transformer.spec.ts +++ b/src/common/yargs/yargs-object-transformer.spec.ts @@ -100,7 +100,7 @@ describe('transformYargObjectToArray', () => { } }; - expect(() => transformYargObjectToArray(yargsObject)).toThrowError( + expect(() => transformYargObjectToArray(yargsObject)).toThrow( new Error('Targeted array indexes are unsupported, please provide a full array index starting at 0') ); }); @@ -126,7 +126,7 @@ describe('transformYargObjectToArray', () => { } }; - expect(() => transformYargObjectToArray(yargsObject)).toThrowError( + expect(() => transformYargObjectToArray(yargsObject)).toThrow( new Error('Targeted array indexes are unsupported, please provide a full array index starting at 0') ); }); diff --git a/src/error-handler.spec.ts b/src/error-handler.spec.ts index 91ecc079..40a24e39 100644 --- a/src/error-handler.spec.ts +++ b/src/error-handler.spec.ts @@ -1,7 +1,10 @@ import { HttpError, HttpMethod } from 'dc-management-sdk-js'; +import { HttpError as ChHttpError } from 'dc-management-sdk-js'; import errorHandler from './error-handler'; -describe('error handler tests', function() { +jest.useFakeTimers().setSystemTime(new Date('2025-02-24T01:01:01.001Z')); + +describe('error handler tests', function () { const spyConsoleError = jest.spyOn(console, 'error'); beforeEach(() => { jest.resetAllMocks(); @@ -24,7 +27,7 @@ describe('error handler tests', function() { expect(spyConsoleError.mock.calls[0][0]).toMatchSnapshot(); }); - describe('HttpErrors', function() { + describe('HttpErrors', function () { it('should display sdk http error', async () => { errorHandler(new HttpError('Message')); expect(spyConsoleError.mock.calls[0][0]).toMatchSnapshot(); @@ -66,5 +69,17 @@ describe('error handler tests', function() { errorHandler(new HttpError('Message', undefined, { status: 501, data: {} })); expect(spyConsoleError.mock.calls[0][0]).toMatchSnapshot(); }); + + it('should display sdk http network error', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + errorHandler(new HttpError('Network error', undefined, { status: undefined as any, data: {} })); + expect(spyConsoleError.mock.calls[0][0]).toMatchSnapshot(); + }); + + it('should display contenthub http network error', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + errorHandler(new ChHttpError('Network error', undefined, { status: undefined as any, data: {} })); + expect(spyConsoleError.mock.calls[0][0]).toMatchSnapshot(); + }); }); }); diff --git a/src/error-handler.ts b/src/error-handler.ts index 2261eb03..12fe6696 100644 --- a/src/error-handler.ts +++ b/src/error-handler.ts @@ -3,7 +3,7 @@ import { HttpError } from 'dc-management-sdk-js'; const httpErrorFactory: { [key: number]: (httpError: HttpError) => string } = { 400: (httpError: HttpError) => `Error: Request failed with status code 400\n${JSON.stringify(httpError.response, null, 2)}`, - 401: () => 'Error: Unauthorized - Please ensure your client ID & secret are correct.', + 401: () => 'Error: Unauthorized - Please ensure your client ID & secret or PAT token are correct.', 403: (httpError: HttpError) => { return httpError.request ? `Error: The requested action (${httpError.request.method}: ${httpError.request.url}) is not available (forbidden), ensure you have permission to perform this action.` @@ -12,6 +12,7 @@ const httpErrorFactory: { [key: number]: (httpError: HttpError) => string } = { 429: () => 'Error: Too many requests - Please try again later.', 500: (httpError: HttpError) => `Error: Internal Server Error - ${httpError.message}` }; + export type SupportedErrors = string | { message: string } | HttpError; const buildMessage = (err: SupportedErrors): string => { @@ -24,13 +25,20 @@ const buildMessage = (err: SupportedErrors): string => { if (builder) { return builder(err); } + if (!err.response.status) { + return `Error: No response from server - check your network connection.`; + } } return `Error: ${err.message}`; }; +const generateTimestamp = (): string => { + return new Date().toISOString(); +}; + const errorHandler = (err: SupportedErrors): void => { - console.error(`\n${buildMessage(err)}`); + console.error(`\n${generateTimestamp()} ${buildMessage(err)}`); }; export default errorHandler; diff --git a/src/interfaces/clean-hub-builder-options.ts b/src/interfaces/clean-hub-builder-options.ts index 8944bc62..dbb87f7c 100644 --- a/src/interfaces/clean-hub-builder-options.ts +++ b/src/interfaces/clean-hub-builder-options.ts @@ -5,4 +5,5 @@ export interface CleanHubBuilderOptions { logFile: FileLog; force?: boolean; step?: CleanHubStepId; + ignoreSchemaValidation?: boolean; } diff --git a/src/interfaces/clone-hub-builder-options.ts b/src/interfaces/clone-hub-builder-options.ts index a71a343d..1e7b932e 100644 --- a/src/interfaces/clone-hub-builder-options.ts +++ b/src/interfaces/clone-hub-builder-options.ts @@ -3,24 +3,21 @@ import { FileLog } from '../common/file-log'; export interface CloneHubBuilderOptions { dir: string; - dstHubId?: string; dstClientId?: string; dstSecret?: string; - revertLog: Promise; step?: CloneHubStepId; - mapFile?: string; force?: boolean; validate?: boolean; skipIncomplete?: boolean; media?: boolean; logFile: FileLog; - lastPublish?: boolean; publish?: boolean; republish?: boolean; - excludeKeys?: boolean; + acceptSnapshotLimits: boolean; + ignoreSchemaValidation?: boolean; } diff --git a/src/interfaces/copy-item-builder-options.interface.ts b/src/interfaces/copy-item-builder-options.interface.ts index 0318d5e3..fac6e3a5 100644 --- a/src/interfaces/copy-item-builder-options.interface.ts +++ b/src/interfaces/copy-item-builder-options.interface.ts @@ -3,30 +3,23 @@ import { FileLog } from '../common/file-log'; export interface CopyItemBuilderOptions { srcRepo?: string; srcFolder?: string; - dstRepo?: string; dstFolder?: string; - dstHubId?: string; dstClientId?: string; dstSecret?: string; - facet?: string; - mapFile?: string; force?: boolean; validate?: boolean; skipIncomplete?: boolean; media?: boolean; logFile: FileLog; - revertLog: Promise; - lastPublish?: boolean; publish?: boolean; republish?: boolean; - excludeKeys?: boolean; - exportedIds?: string[]; + ignoreSchemaValidation?: boolean; } diff --git a/src/interfaces/delete-extension-builder-options.ts b/src/interfaces/delete-extension-builder-options.ts new file mode 100644 index 00000000..c07f7153 --- /dev/null +++ b/src/interfaces/delete-extension-builder-options.ts @@ -0,0 +1,6 @@ +import { FileLog } from '../common/file-log'; + +export interface DeleteExtensionBuilderOptions { + logFile: FileLog; + force?: boolean; +} diff --git a/src/interfaces/delete-webhook-builder-options.ts b/src/interfaces/delete-webhook-builder-options.ts new file mode 100644 index 00000000..9bdf3881 --- /dev/null +++ b/src/interfaces/delete-webhook-builder-options.ts @@ -0,0 +1,6 @@ +import { FileLog } from '../common/file-log'; + +export interface DeleteWebhookBuilderOptions { + logFile: FileLog; + force?: boolean; +} diff --git a/src/interfaces/export-event-builder-options.interface.ts b/src/interfaces/export-event-builder-options.interface.ts new file mode 100644 index 00000000..ea9af3d3 --- /dev/null +++ b/src/interfaces/export-event-builder-options.interface.ts @@ -0,0 +1,10 @@ +import { FileLog } from '../common/file-log'; + +export interface ExportEventBuilderOptions { + dir: string; + id?: string; + fromDate?: string; + toDate?: string; + logFile: FileLog; + snapshots: boolean; +} diff --git a/src/interfaces/export-item-builder-options.interface.ts b/src/interfaces/export-item-builder-options.interface.ts index bddae8e5..a6d767e7 100644 --- a/src/interfaces/export-item-builder-options.interface.ts +++ b/src/interfaces/export-item-builder-options.interface.ts @@ -7,6 +7,5 @@ export interface ExportItemBuilderOptions { facet?: string; logFile: FileLog; publish?: boolean; - exportedIds?: string[]; } diff --git a/src/interfaces/export-webhook-builder-options.ts b/src/interfaces/export-webhook-builder-options.ts new file mode 100644 index 00000000..3e130237 --- /dev/null +++ b/src/interfaces/export-webhook-builder-options.ts @@ -0,0 +1,9 @@ +import { FileLog } from '../common/file-log'; + +export interface ExportWebhookBuilderOptions { + dir: string; + id?: string | string[]; + logFile: FileLog; + force?: boolean; + silent?: boolean; +} diff --git a/src/interfaces/import-event-builder-options.interface.ts b/src/interfaces/import-event-builder-options.interface.ts new file mode 100644 index 00000000..61f6c95d --- /dev/null +++ b/src/interfaces/import-event-builder-options.interface.ts @@ -0,0 +1,11 @@ +import { FileLog } from '../common/file-log'; + +export interface ImportEventBuilderOptions { + dir: string; + mapFile?: string; + originalIds: boolean; + schedule: boolean; + acceptSnapshotLimits: boolean; + catchup: boolean; + logFile: FileLog; +} diff --git a/src/interfaces/import-item-builder-options.interface.ts b/src/interfaces/import-item-builder-options.interface.ts index 2a387937..f9cbdafd 100644 --- a/src/interfaces/import-item-builder-options.interface.ts +++ b/src/interfaces/import-item-builder-options.interface.ts @@ -13,6 +13,6 @@ export interface ImportItemBuilderOptions { excludeKeys?: boolean; media?: boolean; logFile: FileLog; - revertLog: Promise; + ignoreSchemaValidation?: boolean; } diff --git a/src/interfaces/import-settings-builder-options.interface.ts b/src/interfaces/import-settings-builder-options.interface.ts index e8cd2418..7482cfe4 100644 --- a/src/interfaces/import-settings-builder-options.interface.ts +++ b/src/interfaces/import-settings-builder-options.interface.ts @@ -2,6 +2,7 @@ import { FileLog } from '../common/file-log'; export interface ImportSettingsBuilderOptions { filePath: string; + allowDelete?: boolean; mapFile?: string; logFile: FileLog; force?: boolean; diff --git a/src/interfaces/import-webhook-builder-options.ts b/src/interfaces/import-webhook-builder-options.ts new file mode 100644 index 00000000..b8bf0db3 --- /dev/null +++ b/src/interfaces/import-webhook-builder-options.ts @@ -0,0 +1,9 @@ +import { FileLog } from '../common/file-log'; + +export interface ImportWebhookBuilderOptions { + dir: string; + logFile: FileLog; + force?: boolean; + silent?: boolean; + mapFile?: string; +} diff --git a/src/services/ch-client-factory.ts b/src/services/ch-client-factory.ts index 422ec12a..94f7da02 100644 --- a/src/services/ch-client-factory.ts +++ b/src/services/ch-client-factory.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/camelcase */ import { ContentHub } from '../common/ch-api/ContentHub'; import { ConfigurationParameters } from '../commands/configure'; @@ -13,5 +12,4 @@ const chClientFactory = (config: ConfigurationParameters): ContentHub => authUrl: process.env.AUTH_URL } ); - export default chClientFactory; diff --git a/src/services/dynamic-content-client-factory.spec.ts b/src/services/dynamic-content-client-factory.spec.ts index 932bc51c..0034b4ba 100644 --- a/src/services/dynamic-content-client-factory.spec.ts +++ b/src/services/dynamic-content-client-factory.spec.ts @@ -1,10 +1,10 @@ -/* eslint-disable @typescript-eslint/camelcase */ +import { DCHttpClient } from '../common/dc-management-sdk-js/http-client/dc-http-client'; import dynamicContentClientFactory from './dynamic-content-client-factory'; import { DynamicContent } from 'dc-management-sdk-js'; jest.mock('dc-management-sdk-js'); -describe('dynamic-content-client-factory', function() { +describe('dynamic-content-client-factory', function () { const resetEnv = (): void => { delete process.env.API_URL; delete process.env.AUTH_URL; @@ -19,7 +19,11 @@ describe('dynamic-content-client-factory', function() { hubId: 'hub-id' }); expect(dynamicContent).toBeInstanceOf(DynamicContent); - expect(DynamicContent).toHaveBeenCalledWith({ client_id: 'client-id', client_secret: 'client-secret' }, {}); + expect(DynamicContent).toHaveBeenCalledWith( + { client_id: 'client-id', client_secret: 'client-secret' }, + {}, + expect.any(DCHttpClient) + ); }); it('should create a new DynamicContent client using the supplied env vars', () => { @@ -37,7 +41,8 @@ describe('dynamic-content-client-factory', function() { { apiUrl: 'API_URL', authUrl: 'AUTH_URL' - } + }, + expect.any(DCHttpClient) ); }); }); diff --git a/src/services/dynamic-content-client-factory.ts b/src/services/dynamic-content-client-factory.ts index 853635b2..4c4a3cb1 100644 --- a/src/services/dynamic-content-client-factory.ts +++ b/src/services/dynamic-content-client-factory.ts @@ -1,17 +1,19 @@ -/* eslint-disable @typescript-eslint/camelcase */ import { DynamicContent } from 'dc-management-sdk-js'; import { ConfigurationParameters } from '../commands/configure'; +import { DCHttpClient } from '../common/dc-management-sdk-js/http-client/dc-http-client'; const dynamicContentClientFactory = (config: ConfigurationParameters): DynamicContent => new DynamicContent( { client_id: config.clientId, - client_secret: config.clientSecret + client_secret: config.clientSecret, + patToken: config.patToken }, { apiUrl: process.env.API_URL, authUrl: process.env.AUTH_URL - } + }, + new DCHttpClient({ timeout: 25000 }) ); export default dynamicContentClientFactory; diff --git a/src/services/export.service.spec.ts b/src/services/export.service.spec.ts index 7b88b980..f6193e82 100644 --- a/src/services/export.service.spec.ts +++ b/src/services/export.service.spec.ts @@ -63,7 +63,7 @@ describe('export service tests', () => { (fs.writeFileSync as jest.Mock).mockImplementationOnce(() => { throw new Error('Cannot write to file/directory'); }); - expect(() => writeJsonToFile('my-filename', new ContentType())).toThrowError( + expect(() => writeJsonToFile('my-filename', new ContentType())).toThrow( /^Unable to write file: my-filename, aborting export$/ ); }); diff --git a/src/services/export.service.ts b/src/services/export.service.ts index b532ae6d..960e0eb4 100644 --- a/src/services/export.service.ts +++ b/src/services/export.service.ts @@ -14,6 +14,7 @@ export const uniqueFilenamePath = (dir: string, file = '', extension: string, ex } file = sanitize(file, { replacement: '_' }); + if (file.trim().length == 0) file = 'item'; let counter = 0; let uniqueFilename = ''; diff --git a/src/services/import.service.spec.ts b/src/services/import.service.spec.ts index 79af522d..51bfad96 100644 --- a/src/services/import.service.spec.ts +++ b/src/services/import.service.spec.ts @@ -17,8 +17,6 @@ describe('loadJsonFromDirectory tests', () => { it('should throw an error if any import file is not json', (): void => { expect(() => loadJsonFromDirectory(__dirname + '/__fixtures__/load-json-from-directory/bad-json/', ContentType) - ).toThrowError( - /^Non-JSON file found: .*__fixtures__\/load-json-from-directory\/bad-json\/bad-json\.json, aborting...$/ - ); + ).toThrow(/^Non-JSON file found: .*__fixtures__\/load-json-from-directory\/bad-json\/bad-json\.json, aborting...$/); }); }); diff --git a/src/view/data-presenter.spec.ts b/src/view/data-presenter.spec.ts index 122070a5..b4da0881 100644 --- a/src/view/data-presenter.spec.ts +++ b/src/view/data-presenter.spec.ts @@ -20,7 +20,7 @@ describe('DataPresenter', (): void => { jest.restoreAllMocks(); }); - describe('single item', function() { + describe('single item', function () { const singleItem: TestItem = { foo: 'bar', key: 'value '.repeat(20) @@ -50,8 +50,8 @@ describe('DataPresenter', (): void => { }); }); - describe('collection of items tests', function() { - describe('collection of items', function() { + describe('collection of items tests', function () { + describe('collection of items', function () { const collectionOfItems: TestItem[] = [ { foo: 'bar1', @@ -92,7 +92,7 @@ describe('DataPresenter', (): void => { }); }); - describe('collection of 0 items', function() { + describe('collection of 0 items', function () { it('should render a collection of items in a horizontal table', (): void => { new DataPresenter([]).render(); expect(stdoutWriteSpy.mock.calls[0][0]).toMatchSnapshot();