From f605f26f9de1d111c26d65dd3b8955491b357481 Mon Sep 17 00:00:00 2001 From: David Blass Date: Fri, 18 Oct 2024 14:11:31 -0400 Subject: [PATCH 01/21] feat: migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing (#217) # Description This PR migrates the repo off of Zod schemas toward pure TS with JSDoc annotations that can eventually be used to extract metadata for display in docs. Generally the external behavior should be identical, with obvious exceptions where schema entry points are no longer available etc., so this would constitute a breaking change for consumers relying on those entrypoints or whose inputs may no longer be valid with new type safety around video/image options. I've also updated all the tests to `.ts` so we can be sure the types for the API are working as we expect going forward. Although all the tests are passing, the doc generation issue remains unsolved, causing the repo-wide build to fail, so that will need to be updated to use a JSDoc parsing tool. However, it should be quite straightforward to wire that up in place of the previous Zod-embedded metadata. For now, I'm opening this against the `beta` branch so the required JSDoc parsing logic can be added and other changes can be experimented with before broader consumption. ## Issue Ticket Number N/A ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [X] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Fix or improve the documentation - [X] This change requires a documentation update # Checklist (Still a draft, need to figure out how to work around missing schemas in build) - [ ] I have followed the contributing guidelines of this project as mentioned in [CONTRIBUTING.md](/CONTRIBUTING.md) - [ ] I have created an [issue](https://github.com/colbyfayock/cloudinary-util/issues) ticket for this PR - [ ] I have checked to ensure there aren't other open [Pull Requests](https://github.com/colbyfayock/cloudinary-util/pulls) for the same update/change? - [ ] I have performed a self-review of my own code - [ ] I have run tests locally to ensure they all pass - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes needed to the documentation BREAKING CHANGES: removes zod schemas, refactors type system --- .eslintrc.cjs | 1 + docs/src/lib/util.ts | 2 +- packages/types/CHANGELOG.md | 70 +- packages/types/src/index.ts | 22 +- .../src/types/cloudinary-upload-widget.ts | 2 +- .../src/types/cloudinary-video-player.ts | 17 +- packages/types/src/types/configuration.ts | 6 +- packages/types/src/types/resources.ts | 14 +- packages/url-loader/CHANGELOG.md | 69 +- packages/url-loader/build.ts | 22 - packages/url-loader/package.json | 12 +- .../url-loader/src/constants/parameters.ts | 506 ++++----- .../url-loader/src/constants/qualifiers.ts | 694 ++++++------ packages/url-loader/src/index.ts | 40 +- packages/url-loader/src/lib/cloudinary.ts | 329 +++--- packages/url-loader/src/lib/plugin.ts | 72 ++ .../url-loader/src/lib/transformations.ts | 18 +- packages/url-loader/src/lib/upload-widget.ts | 108 +- packages/url-loader/src/lib/upload.ts | 36 +- packages/url-loader/src/lib/utils.ts | 44 + packages/url-loader/src/lib/video-player.ts | 35 +- packages/url-loader/src/plugins/abr.ts | 42 +- packages/url-loader/src/plugins/cropping.ts | 142 +-- .../url-loader/src/plugins/default-image.ts | 43 +- packages/url-loader/src/plugins/effects.ts | 107 +- packages/url-loader/src/plugins/enhance.ts | 42 +- packages/url-loader/src/plugins/extract.ts | 94 +- .../url-loader/src/plugins/fill-background.ts | 57 +- packages/url-loader/src/plugins/flags.ts | 62 +- .../src/plugins/named-transformations.ts | 64 +- packages/url-loader/src/plugins/overlays.ts | 202 ++-- .../src/plugins/preserve-transformations.ts | 45 +- .../src/plugins/raw-transformations.ts | 42 +- packages/url-loader/src/plugins/recolor.ts | 63 +- .../src/plugins/remove-background.ts | 41 +- packages/url-loader/src/plugins/remove.ts | 72 +- .../src/plugins/replace-background.ts | 72 +- packages/url-loader/src/plugins/replace.ts | 58 +- packages/url-loader/src/plugins/restore.ts | 37 +- packages/url-loader/src/plugins/sanitize.ts | 40 +- packages/url-loader/src/plugins/seo.ts | 34 +- packages/url-loader/src/plugins/underlays.ts | 160 +-- packages/url-loader/src/plugins/version.ts | 34 +- packages/url-loader/src/plugins/zoompan.ts | 62 +- packages/url-loader/src/schema.ts | 4 - packages/url-loader/src/types/analytics.ts | 9 - packages/url-loader/src/types/asset.ts | 190 ++-- packages/url-loader/src/types/config.ts | 9 - packages/url-loader/src/types/image.ts | 55 +- packages/url-loader/src/types/plugins.ts | 68 +- packages/url-loader/src/types/qualifiers.ts | 33 +- packages/url-loader/src/types/video.ts | 17 +- .../url-loader/tests/lib/cloudinary.spec.js | 985 ---------------- .../url-loader/tests/lib/cloudinary.spec.ts | 1006 +++++++++++++++++ .../tests/lib/upload-widget.spec.js | 117 -- .../tests/lib/upload-widget.spec.ts | 121 ++ packages/url-loader/tests/lib/upload.spec.js | 47 - packages/url-loader/tests/lib/upload.spec.ts | 47 + .../url-loader/tests/lib/video-player.spec.js | 270 ----- .../url-loader/tests/lib/video-player.spec.ts | 261 +++++ packages/url-loader/tests/plugins/abr.spec.js | 40 - packages/url-loader/tests/plugins/abr.spec.ts | 43 + .../url-loader/tests/plugins/cropping.spec.js | 304 ----- .../url-loader/tests/plugins/cropping.spec.ts | 414 +++++++ .../url-loader/tests/plugins/default.spec.js | 48 - .../url-loader/tests/plugins/default.spec.ts | 54 + .../url-loader/tests/plugins/effects.spec.js | 90 -- .../url-loader/tests/plugins/effects.spec.ts | 85 ++ .../url-loader/tests/plugins/extract.spec.js | 101 -- .../url-loader/tests/plugins/extract.spec.ts | 97 ++ .../tests/plugins/fill-background.spec.js | 71 -- .../tests/plugins/fill-background.spec.ts | 67 ++ .../url-loader/tests/plugins/flags.spec.js | 59 - .../url-loader/tests/plugins/flags.spec.ts | 75 ++ .../plugins/named-transformations.spec.js | 92 -- .../plugins/named-transformations.spec.ts | 80 ++ .../url-loader/tests/plugins/overlays.spec.js | 443 -------- .../url-loader/tests/plugins/overlays.spec.ts | 464 ++++++++ .../plugins/preserve-transformations.spec.js | 40 - .../plugins/preserve-transformations.spec.ts | 37 + .../tests/plugins/raw-transformations.spec.js | 55 - .../tests/plugins/raw-transformations.spec.ts | 46 + .../url-loader/tests/plugins/recolor.spec.js | 86 -- .../url-loader/tests/plugins/recolor.spec.ts | 83 ++ .../tests/plugins/remove-background.spec.js | 47 - .../tests/plugins/remove-background.spec.ts | 41 + .../{remove.spec.js => remove.spec.ts} | 87 +- .../tests/plugins/replace-background.spec.js | 66 -- .../tests/plugins/replace-background.spec.ts | 64 ++ .../{replace.spec.js => replace.spec.ts} | 43 +- .../url-loader/tests/plugins/restore.spec.js | 47 - .../url-loader/tests/plugins/restore.spec.ts | 41 + .../url-loader/tests/plugins/sanitize.spec.ts | 46 +- .../tests/plugins/underlays.spec.js | 63 -- .../tests/plugins/underlays.spec.ts | 63 ++ .../url-loader/tests/plugins/zoompan.spec.js | 132 --- .../url-loader/tests/plugins/zoompan.spec.ts | 118 ++ packages/util/CHANGELOG.md | 21 +- packages/util/src/index.ts | 3 +- pnpm-lock.yaml | 35 +- pnpm-workspace.yaml | 2 +- tsconfig.json | 2 +- 102 files changed, 5281 insertions(+), 5587 deletions(-) delete mode 100644 packages/url-loader/build.ts create mode 100644 packages/url-loader/src/lib/plugin.ts create mode 100644 packages/url-loader/src/lib/utils.ts delete mode 100644 packages/url-loader/src/schema.ts delete mode 100644 packages/url-loader/src/types/analytics.ts delete mode 100644 packages/url-loader/src/types/config.ts delete mode 100644 packages/url-loader/tests/lib/cloudinary.spec.js create mode 100644 packages/url-loader/tests/lib/cloudinary.spec.ts delete mode 100644 packages/url-loader/tests/lib/upload-widget.spec.js create mode 100644 packages/url-loader/tests/lib/upload-widget.spec.ts delete mode 100644 packages/url-loader/tests/lib/upload.spec.js create mode 100644 packages/url-loader/tests/lib/upload.spec.ts delete mode 100644 packages/url-loader/tests/lib/video-player.spec.js create mode 100644 packages/url-loader/tests/lib/video-player.spec.ts delete mode 100644 packages/url-loader/tests/plugins/abr.spec.js create mode 100644 packages/url-loader/tests/plugins/abr.spec.ts delete mode 100644 packages/url-loader/tests/plugins/cropping.spec.js create mode 100644 packages/url-loader/tests/plugins/cropping.spec.ts delete mode 100644 packages/url-loader/tests/plugins/default.spec.js create mode 100644 packages/url-loader/tests/plugins/default.spec.ts delete mode 100644 packages/url-loader/tests/plugins/effects.spec.js create mode 100644 packages/url-loader/tests/plugins/effects.spec.ts delete mode 100644 packages/url-loader/tests/plugins/extract.spec.js create mode 100644 packages/url-loader/tests/plugins/extract.spec.ts delete mode 100644 packages/url-loader/tests/plugins/fill-background.spec.js create mode 100644 packages/url-loader/tests/plugins/fill-background.spec.ts delete mode 100644 packages/url-loader/tests/plugins/flags.spec.js create mode 100644 packages/url-loader/tests/plugins/flags.spec.ts delete mode 100644 packages/url-loader/tests/plugins/named-transformations.spec.js create mode 100644 packages/url-loader/tests/plugins/named-transformations.spec.ts delete mode 100644 packages/url-loader/tests/plugins/overlays.spec.js create mode 100644 packages/url-loader/tests/plugins/overlays.spec.ts delete mode 100644 packages/url-loader/tests/plugins/preserve-transformations.spec.js create mode 100644 packages/url-loader/tests/plugins/preserve-transformations.spec.ts delete mode 100644 packages/url-loader/tests/plugins/raw-transformations.spec.js create mode 100644 packages/url-loader/tests/plugins/raw-transformations.spec.ts delete mode 100644 packages/url-loader/tests/plugins/recolor.spec.js create mode 100644 packages/url-loader/tests/plugins/recolor.spec.ts delete mode 100644 packages/url-loader/tests/plugins/remove-background.spec.js create mode 100644 packages/url-loader/tests/plugins/remove-background.spec.ts rename packages/url-loader/tests/plugins/{remove.spec.js => remove.spec.ts} (51%) delete mode 100644 packages/url-loader/tests/plugins/replace-background.spec.js create mode 100644 packages/url-loader/tests/plugins/replace-background.spec.ts rename packages/url-loader/tests/plugins/{replace.spec.js => replace.spec.ts} (76%) delete mode 100644 packages/url-loader/tests/plugins/restore.spec.js create mode 100644 packages/url-loader/tests/plugins/restore.spec.ts delete mode 100644 packages/url-loader/tests/plugins/underlays.spec.js create mode 100644 packages/url-loader/tests/plugins/underlays.spec.ts delete mode 100644 packages/url-loader/tests/plugins/zoompan.spec.js create mode 100644 packages/url-loader/tests/plugins/zoompan.spec.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index fce0f644..6a54a8fa 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -38,5 +38,6 @@ module.exports = defineConfig({ "@typescript-eslint/ban-types": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-namespace": ["warn", { allowDeclarations: true }], }, }); diff --git a/docs/src/lib/util.ts b/docs/src/lib/util.ts index 4aeb7783..731b9c73 100644 --- a/docs/src/lib/util.ts +++ b/docs/src/lib/util.ts @@ -6,7 +6,7 @@ export function sortByKey( array: Array = [], key: string, - type: string = "asc" + type: string = "asc", ) { function compare(a: object, b: object) { let keyA = a[key]; diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 58fd93c7..7167d311 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,148 +1,127 @@ # [@cloudinary-util/types-v1.5.11](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.10...@cloudinary-util/types-v1.5.11) (2024-10-07) - ### Bug Fixes -* Add cloudinaryAnalytics to Video Player types [#171](https://github.com/cloudinary-community/cloudinary-util/issues/171) ([#208](https://github.com/cloudinary-community/cloudinary-util/issues/208)) ([60da2de](https://github.com/cloudinary-community/cloudinary-util/commit/60da2de13ae511fd21805b9e1d510be627ce3de7)) +- Add cloudinaryAnalytics to Video Player types [#171](https://github.com/cloudinary-community/cloudinary-util/issues/171) ([#208](https://github.com/cloudinary-community/cloudinary-util/issues/208)) ([60da2de](https://github.com/cloudinary-community/cloudinary-util/commit/60da2de13ae511fd21805b9e1d510be627ce3de7)) # [@cloudinary-util/types-v1.5.10](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.9...@cloudinary-util/types-v1.5.10) (2024-10-04) - ### Bug Fixes -* Adds videojs dispose method to Video Player type ([2fd75c1](https://github.com/cloudinary-community/cloudinary-util/commit/2fd75c1c6ceac2496f2fa258d466e1e0d2d1f9cd)) +- Adds videojs dispose method to Video Player type ([2fd75c1](https://github.com/cloudinary-community/cloudinary-util/commit/2fd75c1c6ceac2496f2fa258d466e1e0d2d1f9cd)) # [@cloudinary-util/types-v1.5.9](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.8...@cloudinary-util/types-v1.5.9) (2024-09-16) - ### Bug Fixes -* fixing player text track options ([a03577d](https://github.com/cloudinary-community/cloudinary-util/commit/a03577d60589626d9b1d6eed098e7afb07eaf0d1)) +- fixing player text track options ([a03577d](https://github.com/cloudinary-community/cloudinary-util/commit/a03577d60589626d9b1d6eed098e7afb07eaf0d1)) # [@cloudinary-util/types-v1.5.8](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.7...@cloudinary-util/types-v1.5.8) (2024-09-13) - ### Bug Fixes -* adding textTracks types to video player ([3b766a3](https://github.com/cloudinary-community/cloudinary-util/commit/3b766a37a3ffec17507a79c1bd6e4a7f01fdfa39)) +- adding textTracks types to video player ([3b766a3](https://github.com/cloudinary-community/cloudinary-util/commit/3b766a37a3ffec17507a79c1bd6e4a7f01fdfa39)) # [@cloudinary-util/types-v1.5.7](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.6...@cloudinary-util/types-v1.5.7) (2024-09-11) - ### Bug Fixes -* adding type definition for resource context ([2ef1311](https://github.com/cloudinary-community/cloudinary-util/commit/2ef13118602f1efc39a85a7e05fa958c6e1cd2f1)) +- adding type definition for resource context ([2ef1311](https://github.com/cloudinary-community/cloudinary-util/commit/2ef13118602f1efc39a85a7e05fa958c6e1cd2f1)) # [@cloudinary-util/types-v1.5.6](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.5...@cloudinary-util/types-v1.5.6) (2024-09-06) - ### Bug Fixes -* making resource types optional that aren't potentially always there ([7d0b6ce](https://github.com/cloudinary-community/cloudinary-util/commit/7d0b6ce397a6e01087d96aef2c399a067ec998ee)) +- making resource types optional that aren't potentially always there ([7d0b6ce](https://github.com/cloudinary-community/cloudinary-util/commit/7d0b6ce397a6e01087d96aef2c399a067ec998ee)) # [@cloudinary-util/types-v1.5.5](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.4...@cloudinary-util/types-v1.5.5) (2024-09-05) - ### Bug Fixes -* fixing resource type, adding more fields, reorganizing ([466dd1b](https://github.com/cloudinary-community/cloudinary-util/commit/466dd1b9efe702e8630e21d72e77081a010e96a6)) +- fixing resource type, adding more fields, reorganizing ([466dd1b](https://github.com/cloudinary-community/cloudinary-util/commit/466dd1b9efe702e8630e21d72e77081a010e96a6)) # [@cloudinary-util/types-v1.5.4](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.3...@cloudinary-util/types-v1.5.4) (2024-09-05) - ### Bug Fixes -* add video player types ([#194](https://github.com/cloudinary-community/cloudinary-util/issues/194)) ([f7f9e6e](https://github.com/cloudinary-community/cloudinary-util/commit/f7f9e6edaaa7963c97ef923653b62af7182c7272)) +- add video player types ([#194](https://github.com/cloudinary-community/cloudinary-util/issues/194)) ([f7f9e6e](https://github.com/cloudinary-community/cloudinary-util/commit/f7f9e6edaaa7963c97ef923653b62af7182c7272)) # [@cloudinary-util/types-v1.5.3](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.2...@cloudinary-util/types-v1.5.3) (2024-09-03) - ### Bug Fixes -* export the new widget types ([#193](https://github.com/cloudinary-community/cloudinary-util/issues/193)) ([8ec71be](https://github.com/cloudinary-community/cloudinary-util/commit/8ec71be305de51d2d8340ac7346676768aeea57c)), closes [#191](https://github.com/cloudinary-community/cloudinary-util/issues/191) +- export the new widget types ([#193](https://github.com/cloudinary-community/cloudinary-util/issues/193)) ([8ec71be](https://github.com/cloudinary-community/cloudinary-util/commit/8ec71be305de51d2d8340ac7346676768aeea57c)), closes [#191](https://github.com/cloudinary-community/cloudinary-util/issues/191) # [@cloudinary-util/types-v1.5.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.1...@cloudinary-util/types-v1.5.2) (2024-09-03) - ### Bug Fixes -* add more upload widget types ([#191](https://github.com/cloudinary-community/cloudinary-util/issues/191)) ([b1cb91a](https://github.com/cloudinary-community/cloudinary-util/commit/b1cb91a78bb6c4879ee26b37f1fd89392f2c5090)) +- add more upload widget types ([#191](https://github.com/cloudinary-community/cloudinary-util/issues/191)) ([b1cb91a](https://github.com/cloudinary-community/cloudinary-util/commit/b1cb91a78bb6c4879ee26b37f1fd89392f2c5090)) # [@cloudinary-util/types-v1.5.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.0...@cloudinary-util/types-v1.5.1) (2024-08-30) - ### Bug Fixes -* moving access mode type from resource to its own definition ([7f449fd](https://github.com/cloudinary-community/cloudinary-util/commit/7f449fd6d4e1b94d2c2bcc2859922555bd6f79f8)) +- moving access mode type from resource to its own definition ([7f449fd](https://github.com/cloudinary-community/cloudinary-util/commit/7f449fd6d4e1b94d2c2bcc2859922555bd6f79f8)) # [@cloudinary-util/types-v1.5.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.4.0...@cloudinary-util/types-v1.5.0) (2024-08-30) - ### Bug Fixes -* top level type import ([933e124](https://github.com/cloudinary-community/cloudinary-util/commit/933e124d92c8b782933d376d5e7bc4d12274c49e)) - +- top level type import ([933e124](https://github.com/cloudinary-community/cloudinary-util/commit/933e124d92c8b782933d376d5e7bc4d12274c49e)) ### Features -* adding Cloudinary Resource type ([e3ad47e](https://github.com/cloudinary-community/cloudinary-util/commit/e3ad47ef1718f560de37b3206f20dde7abdab784)) +- adding Cloudinary Resource type ([e3ad47e](https://github.com/cloudinary-community/cloudinary-util/commit/e3ad47ef1718f560de37b3206f20dde7abdab784)) # [@cloudinary-util/types-v1.4.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.3.2...@cloudinary-util/types-v1.4.0) (2024-08-21) - ### Features -* deprecating controlBar in video player as not recommended for use ([429f40a](https://github.com/cloudinary-community/cloudinary-util/commit/429f40a7c546a653181e36e5fc2077fb2e5598e0)) +- deprecating controlBar in video player as not recommended for use ([429f40a](https://github.com/cloudinary-community/cloudinary-util/commit/429f40a7c546a653181e36e5fc2077fb2e5598e0)) # [@cloudinary-util/types-v1.3.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.3.1...@cloudinary-util/types-v1.3.2) (2024-08-21) - ### Bug Fixes -* prepublish build ([b2e84d2](https://github.com/cloudinary-community/cloudinary-util/commit/b2e84d20a8cc97dee42e9ce32822322a7166811d)) -* releaserc ([2d11e72](https://github.com/cloudinary-community/cloudinary-util/commit/2d11e727aeb03bec5138a4dc451b620a814f87b6)) +- prepublish build ([b2e84d2](https://github.com/cloudinary-community/cloudinary-util/commit/b2e84d20a8cc97dee42e9ce32822322a7166811d)) +- releaserc ([2d11e72](https://github.com/cloudinary-community/cloudinary-util/commit/2d11e727aeb03bec5138a4dc451b620a814f87b6)) # [@cloudinary-util/types-v1.3.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.3.0...@cloudinary-util/types-v1.3.1) (2024-08-21) - ### Bug Fixes -* adding dist files to config ([ef9b56e](https://github.com/cloudinary-community/cloudinary-util/commit/ef9b56e64a475e7a479bdac554fa05381cff08a1)) +- adding dist files to config ([ef9b56e](https://github.com/cloudinary-community/cloudinary-util/commit/ef9b56e64a475e7a479bdac554fa05381cff08a1)) # [@cloudinary-util/types-v1.3.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.2.0...@cloudinary-util/types-v1.3.0) (2024-08-20) - ### Features -* adding configuration types ([4478dd4](https://github.com/cloudinary-community/cloudinary-util/commit/4478dd4619cea25a36cd4436e8b855aca1f27701)) +- adding configuration types ([4478dd4](https://github.com/cloudinary-community/cloudinary-util/commit/4478dd4619cea25a36cd4436e8b855aca1f27701)) # [@cloudinary-util/types-v1.2.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.1.0...@cloudinary-util/types-v1.2.0) (2024-08-07) - ### Features -* url-loader@5.6.0 ([#166](https://github.com/cloudinary-community/cloudinary-util/issues/166)) ([26736af](https://github.com/cloudinary-community/cloudinary-util/commit/26736afe7c9e32bad971beb273c71a9519c36944)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) +- url-loader@5.6.0 ([#166](https://github.com/cloudinary-community/cloudinary-util/issues/166)) ([26736af](https://github.com/cloudinary-community/cloudinary-util/commit/26736afe7c9e32bad971beb273c71a9519c36944)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) # [@cloudinary-util/types-v1.2.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.1.0...@cloudinary-util/types-v1.2.0-beta.1) (2024-08-02) - ### Features -* getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) +- getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) # [@cloudinary-util/types-v1.2.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.1.0...@cloudinary-util/types-v1.2.0-beta.1) (2024-08-02) - ### Features -* getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) +- getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) # [@cloudinary-util/types-v1.1.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.1.0-beta.1...@cloudinary-util/types-v1.1.0-beta.2) (2024-08-01) - ### Bug Fixes -* adding config options to upload widget options ([0d979d2](https://github.com/cloudinary-community/cloudinary-util/commit/0d979d261ff1dfdde50d47686decf10e7a5a4a39)) +- adding config options to upload widget options ([0d979d2](https://github.com/cloudinary-community/cloudinary-util/commit/0d979d261ff1dfdde50d47686decf10e7a5a4a39)) # [@cloudinary-util/types-v1.1.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.0.5...@cloudinary-util/types-v1.1.0-beta.1) (2024-07-09) @@ -150,14 +129,13 @@ ### Bug Fixes -* adding config options to upload widget options ([0d979d2](https://github.com/cloudinary-community/cloudinary-util/commit/0d979d261ff1dfdde50d47686decf10e7a5a4a39)) +- adding config options to upload widget options ([0d979d2](https://github.com/cloudinary-community/cloudinary-util/commit/0d979d261ff1dfdde50d47686decf10e7a5a4a39)) # [@cloudinary-util/types-v1.0.5](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.0.4...@cloudinary-util/types-v1.0.5) (2024-05-23) - ### Features -* Improve plugin types, modernize monorepo structure ([#161](https://github.com/cloudinary-community/cloudinary-util/issues/161)) ([8ad6066](https://github.com/cloudinary-community/cloudinary-util/commit/8ad60661d4b3c78c08e9dd1939171a689eeb7b08)) +- Improve plugin types, modernize monorepo structure ([#161](https://github.com/cloudinary-community/cloudinary-util/issues/161)) ([8ad6066](https://github.com/cloudinary-community/cloudinary-util/commit/8ad60661d4b3c78c08e9dd1939171a689eeb7b08)) # [@cloudinary-util/types-v1.0.5](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.0.4...@cloudinary-util/types-v1.0.5) (2024-05-23) diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index a30c58ba..1b13275b 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1,5 +1,9 @@ export type { - CloudinaryResource, CloudinaryResourceAccessMode, CloudinaryResourceContext, CloudinaryResourceDeliveryType, CloudinaryResourceResourceType + CloudinaryResource, + CloudinaryResourceAccessMode, + CloudinaryResourceContext, + CloudinaryResourceDeliveryType, + CloudinaryResourceResourceType, } from "./types/resources.js"; export type { @@ -14,7 +18,7 @@ export type { CloudinaryUploadWidgetInstanceMethods, CloudinaryUploadWidgetOptions, CloudinaryUploadWidgetResults, - CloudinaryUploadWidgetSources + CloudinaryUploadWidgetSources, } from "./types/cloudinary-upload-widget.js"; export type { @@ -22,16 +26,20 @@ export type { CloudinaryVideoPlayerOptionPosterOptions, CloudinaryVideoPlayerOptions, CloudinaryVideoPlayerOptionsColors, - CloudinaryVideoPlayerOptionsLogo, CloudinaryVideoPlayerPlaylistByTagOptions, - CloudinaryVideoPlayerPlaylistOptions, CloudinaryVideoPlayerTextTracks, CloudinaryVideoPlayerTextTracksTrack, CloudinaryVideoPlayerTextTracksTrackOptions, CloudinaryVideoPlayerTextTracksTrackOptionsBox, + CloudinaryVideoPlayerOptionsLogo, + CloudinaryVideoPlayerPlaylistByTagOptions, + CloudinaryVideoPlayerPlaylistOptions, + CloudinaryVideoPlayerTextTracks, + CloudinaryVideoPlayerTextTracksTrack, + CloudinaryVideoPlayerTextTracksTrackOptions, + CloudinaryVideoPlayerTextTracksTrackOptionsBox, CloudinaryVideoPlayerTextTracksTrackOptionsGravity, - CloudinaryVideoPlayerTextTracksTrackOptionsTheme + CloudinaryVideoPlayerTextTracksTrackOptionsTheme, } from "./types/cloudinary-video-player.js"; export type { CloudinaryAssetConfiguration, CloudinaryAssetConfigurationAuthToken, CloudinaryAssetConfigurationCloud, - CloudinaryAssetConfigurationUrl + CloudinaryAssetConfigurationUrl, } from "./types/configuration.js"; - diff --git a/packages/types/src/types/cloudinary-upload-widget.ts b/packages/types/src/types/cloudinary-upload-widget.ts index fad533e1..4796fac3 100644 --- a/packages/types/src/types/cloudinary-upload-widget.ts +++ b/packages/types/src/types/cloudinary-upload-widget.ts @@ -1,4 +1,4 @@ -import type { CloudinaryResource } from './resources.js'; +import type { CloudinaryResource } from "./resources.js"; // Sourced from: https://cloudinary.com/documentation/upload_widget_reference diff --git a/packages/types/src/types/cloudinary-video-player.ts b/packages/types/src/types/cloudinary-video-player.ts index cf6d7a99..25810143 100644 --- a/packages/types/src/types/cloudinary-video-player.ts +++ b/packages/types/src/types/cloudinary-video-player.ts @@ -306,9 +306,8 @@ export interface CloudinaryVideoPlayer { videojs: { cloudinary: { dispose: () => void; - } - } - + }; + }; } export interface CloudinaryVideoPlayerOptionsLogo { @@ -366,8 +365,10 @@ export interface CloudinaryVideoPlayerTextTracksTrack { export interface CloudinaryVideoPlayerTextTracks { captions?: CloudinaryVideoPlayerTextTracksTrack; - options?: CloudinaryVideoPlayerTextTracksTrackOptions - subtitles?: CloudinaryVideoPlayerTextTracksTrack | Array; + options?: CloudinaryVideoPlayerTextTracksTrackOptions; + subtitles?: + | CloudinaryVideoPlayerTextTracksTrack + | Array; } export interface CloudinaryVideoPlayerOptions @@ -442,7 +443,9 @@ export interface CloudinaryVideoPlayerOptions }; analytics?: boolean; allowUsageReport?: boolean; - cloudinaryAnalytics?: boolean | CloudinaryVideoPlayerOptionsCloudinaryAnalytics; + cloudinaryAnalytics?: + | boolean + | CloudinaryVideoPlayerOptionsCloudinaryAnalytics; // ------------ Delivery ------------ cloud_name?: string; @@ -495,4 +498,4 @@ export interface CloudinaryVideoPlayerOptionsCloudinaryAnalyticsCustomData { customData3?: string; customData4?: string; customData5?: string; -} \ No newline at end of file +} diff --git a/packages/types/src/types/configuration.ts b/packages/types/src/types/configuration.ts index 1d9d64e8..c3b49b4f 100644 --- a/packages/types/src/types/configuration.ts +++ b/packages/types/src/types/configuration.ts @@ -23,16 +23,16 @@ export interface CloudinaryAssetConfigurationUrl { useRootPath?: boolean; forceVersion?: boolean; queryParams?: Record | string; -}; +} export interface CloudinaryAssetConfigurationCloud { cloudName?: string; apiKey?: string; apiSecret?: string; authToken?: CloudinaryAssetConfigurationAuthToken; -}; +} export interface CloudinaryAssetConfiguration { cloud?: CloudinaryAssetConfigurationCloud; url?: CloudinaryAssetConfigurationUrl; -} \ No newline at end of file +} diff --git a/packages/types/src/types/resources.ts b/packages/types/src/types/resources.ts index a020048f..f8e32834 100644 --- a/packages/types/src/types/resources.ts +++ b/packages/types/src/types/resources.ts @@ -1,5 +1,13 @@ -export type CloudinaryResourceAccessMode = "public" | "authenticated" | (string & {}); -export type CloudinaryResourceResourceType = "image" | "video" | "raw" | "auto" | (string & {}); +export type CloudinaryResourceAccessMode = + | "public" + | "authenticated" + | (string & {}); +export type CloudinaryResourceResourceType = + | "image" + | "video" + | "raw" + | "auto" + | (string & {}); export type CloudinaryResourceDeliveryType = | "animoto" | "asset" @@ -68,4 +76,4 @@ export interface CloudinaryResource { version: number; width: number; [key: string]: unknown; -} \ No newline at end of file +} diff --git a/packages/url-loader/CHANGELOG.md b/packages/url-loader/CHANGELOG.md index 569aace7..ba4c7295 100644 --- a/packages/url-loader/CHANGELOG.md +++ b/packages/url-loader/CHANGELOG.md @@ -1,158 +1,137 @@ # [@cloudinary-util/url-loader-v5.10.5](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.4...@cloudinary-util/url-loader-v5.10.5) (2024-10-07) - ### Bug Fixes -* update gravity type in url loader ([#205](https://github.com/cloudinary-community/cloudinary-util/issues/205)) ([afd9a96](https://github.com/cloudinary-community/cloudinary-util/commit/afd9a96997e3ce1ce9673a5a95aa07b53297af51)), closes [#196](https://github.com/cloudinary-community/cloudinary-util/issues/196) +- update gravity type in url loader ([#205](https://github.com/cloudinary-community/cloudinary-util/issues/205)) ([afd9a96](https://github.com/cloudinary-community/cloudinary-util/commit/afd9a96997e3ce1ce9673a5a95aa07b53297af51)), closes [#196](https://github.com/cloudinary-community/cloudinary-util/issues/196) # [@cloudinary-util/url-loader-v5.10.4](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.3...@cloudinary-util/url-loader-v5.10.4) (2024-10-04) - ### Bug Fixes -* format file url-loader index, force build/deploy ([71a535c](https://github.com/cloudinary-community/cloudinary-util/commit/71a535cf1a2fa6234755127e1201a9e3aad240a6)) +- format file url-loader index, force build/deploy ([71a535c](https://github.com/cloudinary-community/cloudinary-util/commit/71a535cf1a2fa6234755127e1201a9e3aad240a6)) # [@cloudinary-util/url-loader-v5.10.3](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.2...@cloudinary-util/url-loader-v5.10.3) (2024-09-13) - ### Bug Fixes -* reordering to force deploy ([443e1f7](https://github.com/cloudinary-community/cloudinary-util/commit/443e1f75da6963ce52d236913c786cdcb1d504fa)) +- reordering to force deploy ([443e1f7](https://github.com/cloudinary-community/cloudinary-util/commit/443e1f75da6963ce52d236913c786cdcb1d504fa)) # [@cloudinary-util/url-loader-v5.10.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.1...@cloudinary-util/url-loader-v5.10.2) (2024-09-06) - ### Bug Fixes -* updating type of radius property to include number ([f5c260f](https://github.com/cloudinary-community/cloudinary-util/commit/f5c260ffe97fb977c9d5bb79251aa77e33ea9b1d)) +- updating type of radius property to include number ([f5c260f](https://github.com/cloudinary-community/cloudinary-util/commit/f5c260ffe97fb977c9d5bb79251aa77e33ea9b1d)) # [@cloudinary-util/url-loader-v5.10.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.0...@cloudinary-util/url-loader-v5.10.1) (2024-09-04) - ### Bug Fixes -* default the version to 1 when constructing a cld url ([#195](https://github.com/cloudinary-community/cloudinary-util/issues/195)) ([204da50](https://github.com/cloudinary-community/cloudinary-util/commit/204da50bb490b53ff5c53b5bdb1e7351a63b58bb)), closes [#181](https://github.com/cloudinary-community/cloudinary-util/issues/181) +- default the version to 1 when constructing a cld url ([#195](https://github.com/cloudinary-community/cloudinary-util/issues/195)) ([204da50](https://github.com/cloudinary-community/cloudinary-util/commit/204da50bb490b53ff5c53b5bdb1e7351a63b58bb)), closes [#181](https://github.com/cloudinary-community/cloudinary-util/issues/181) # [@cloudinary-util/url-loader-v5.10.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.9.1...@cloudinary-util/url-loader-v5.10.0) (2024-09-03) - ### Features -* Crop by X and Y Coordinates ([#192](https://github.com/cloudinary-community/cloudinary-util/issues/192)) ([091b73d](https://github.com/cloudinary-community/cloudinary-util/commit/091b73db2dd45e523d1c989ef6ca48785ad1e9f5)) +- Crop by X and Y Coordinates ([#192](https://github.com/cloudinary-community/cloudinary-util/issues/192)) ([091b73d](https://github.com/cloudinary-community/cloudinary-util/commit/091b73db2dd45e523d1c989ef6ca48785ad1e9f5)) # [@cloudinary-util/url-loader-v5.9.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.9.0...@cloudinary-util/url-loader-v5.9.1) (2024-08-30) - ### Bug Fixes -* updating how config options are exported ([dcffee0](https://github.com/cloudinary-community/cloudinary-util/commit/dcffee02ce906d1edbb8a1bfbe1bd15166af6231)) +- updating how config options are exported ([dcffee0](https://github.com/cloudinary-community/cloudinary-util/commit/dcffee02ce906d1edbb8a1bfbe1bd15166af6231)) # [@cloudinary-util/url-loader-v5.9.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.8.0...@cloudinary-util/url-loader-v5.9.0) (2024-08-28) - ### Features -* Extract ([#190](https://github.com/cloudinary-community/cloudinary-util/issues/190)) ([3b0896f](https://github.com/cloudinary-community/cloudinary-util/commit/3b0896f1916cd1bd1c76ebd6a1656d6d1e9002fc)), closes [#168](https://github.com/cloudinary-community/cloudinary-util/issues/168) +- Extract ([#190](https://github.com/cloudinary-community/cloudinary-util/issues/190)) ([3b0896f](https://github.com/cloudinary-community/cloudinary-util/commit/3b0896f1916cd1bd1c76ebd6a1656d6d1e9002fc)), closes [#168](https://github.com/cloudinary-community/cloudinary-util/issues/168) # [@cloudinary-util/url-loader-v5.8.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.7.1...@cloudinary-util/url-loader-v5.8.0) (2024-08-28) - ### Features -* Adds preserveTransformations to URL Loader ([#184](https://github.com/cloudinary-community/cloudinary-util/issues/184)) ([56e7f79](https://github.com/cloudinary-community/cloudinary-util/commit/56e7f79a5f19cda80c4d5a661553741c5f4c181c)), closes [#183](https://github.com/cloudinary-community/cloudinary-util/issues/183) +- Adds preserveTransformations to URL Loader ([#184](https://github.com/cloudinary-community/cloudinary-util/issues/184)) ([56e7f79](https://github.com/cloudinary-community/cloudinary-util/commit/56e7f79a5f19cda80c4d5a661553741c5f4c181c)), closes [#183](https://github.com/cloudinary-community/cloudinary-util/issues/183) # [@cloudinary-util/url-loader-v5.7.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.7.0...@cloudinary-util/url-loader-v5.7.1) (2024-08-26) - ### Bug Fixes -* added all the gravity types as a Zod enum ([#172](https://github.com/cloudinary-community/cloudinary-util/issues/172)) ([d667e24](https://github.com/cloudinary-community/cloudinary-util/commit/d667e249e8644aa2d04ee98a6df7ac8881908207)), closes [#170](https://github.com/cloudinary-community/cloudinary-util/issues/170) +- added all the gravity types as a Zod enum ([#172](https://github.com/cloudinary-community/cloudinary-util/issues/172)) ([d667e24](https://github.com/cloudinary-community/cloudinary-util/commit/d667e249e8644aa2d04ee98a6df7ac8881908207)), closes [#170](https://github.com/cloudinary-community/cloudinary-util/issues/170) # [@cloudinary-util/url-loader-v5.7.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.6.1...@cloudinary-util/url-loader-v5.7.0) (2024-08-21) - ### Features -* v5.7.0 ([#179](https://github.com/cloudinary-community/cloudinary-util/issues/179)) ([21abfb8](https://github.com/cloudinary-community/cloudinary-util/commit/21abfb8f8c048e9b5335be673c8da1b20a7cc83a)) +- v5.7.0 ([#179](https://github.com/cloudinary-community/cloudinary-util/issues/179)) ([21abfb8](https://github.com/cloudinary-community/cloudinary-util/commit/21abfb8f8c048e9b5335be673c8da1b20a7cc83a)) # [@cloudinary-util/url-loader-v5.7.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.6.1...@cloudinary-util/url-loader-v5.7.0-beta.1) (2024-08-21) - ### Features -* Using /types to import Config Options ([#178](https://github.com/cloudinary-community/cloudinary-util/issues/178)) ([d3763e6](https://github.com/cloudinary-community/cloudinary-util/commit/d3763e65af42493dfdcd4010cbd0ded96acdd063)) +- Using /types to import Config Options ([#178](https://github.com/cloudinary-community/cloudinary-util/issues/178)) ([d3763e6](https://github.com/cloudinary-community/cloudinary-util/commit/d3763e65af42493dfdcd4010cbd0ded96acdd063)) # [@cloudinary-util/url-loader-v5.6.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.6.0...@cloudinary-util/url-loader-v5.6.1) (2024-08-21) - ### Bug Fixes -* Fixes undefined aspect ratio `undefined:undefined` with no width or height ([#177](https://github.com/cloudinary-community/cloudinary-util/issues/177)) ([f12adaa](https://github.com/cloudinary-community/cloudinary-util/commit/f12adaaaf21ac63977684eebaf39e0b896e85058)), closes [#176](https://github.com/cloudinary-community/cloudinary-util/issues/176) +- Fixes undefined aspect ratio `undefined:undefined` with no width or height ([#177](https://github.com/cloudinary-community/cloudinary-util/issues/177)) ([f12adaa](https://github.com/cloudinary-community/cloudinary-util/commit/f12adaaaf21ac63977684eebaf39e0b896e85058)), closes [#176](https://github.com/cloudinary-community/cloudinary-util/issues/176) # [@cloudinary-util/url-loader-v5.6.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.5.0...@cloudinary-util/url-loader-v5.6.0) (2024-08-07) - ### Bug Fixes -* falsy check for replacebackground ([5574e39](https://github.com/cloudinary-community/cloudinary-util/commit/5574e39c1d245dbccb52a3e44a1e79eb906df9c0)) - +- falsy check for replacebackground ([5574e39](https://github.com/cloudinary-community/cloudinary-util/commit/5574e39c1d245dbccb52a3e44a1e79eb906df9c0)) ### Features -* url-loader@5.6.0 ([#166](https://github.com/cloudinary-community/cloudinary-util/issues/166)) ([26736af](https://github.com/cloudinary-community/cloudinary-util/commit/26736afe7c9e32bad971beb273c71a9519c36944)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) +- url-loader@5.6.0 ([#166](https://github.com/cloudinary-community/cloudinary-util/issues/166)) ([26736af](https://github.com/cloudinary-community/cloudinary-util/commit/26736afe7c9e32bad971beb273c71a9519c36944)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) # [@cloudinary-util/url-loader-v5.6.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.6.0-beta.1...@cloudinary-util/url-loader-v5.6.0-beta.2) (2024-08-06) - ### Bug Fixes -* updating enum value to allow for both the list of values and string ([1b4c403](https://github.com/cloudinary-community/cloudinary-util/commit/1b4c403a7b27a1883e7e9aec21c56fbbd099767a)) +- updating enum value to allow for both the list of values and string ([1b4c403](https://github.com/cloudinary-community/cloudinary-util/commit/1b4c403a7b27a1883e7e9aec21c56fbbd099767a)) # [@cloudinary-util/url-loader-v5.6.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.5.0...@cloudinary-util/url-loader-v5.6.0-beta.1) (2024-08-02) - ### Features -* force version ([cb63bff](https://github.com/cloudinary-community/cloudinary-util/commit/cb63bff1efa23eb2968c2b8b0094235987a68012)) -* getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) +- force version ([cb63bff](https://github.com/cloudinary-community/cloudinary-util/commit/cb63bff1efa23eb2968c2b8b0094235987a68012)) +- getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) # [@cloudinary-util/url-loader-v5.5.0-beta.3](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.5.0-beta.2...@cloudinary-util/url-loader-v5.5.0-beta.3) (2024-08-02) - ### Features -* Generative Replace Background ([#167](https://github.com/cloudinary-community/cloudinary-util/issues/167)) ([4129214](https://github.com/cloudinary-community/cloudinary-util/commit/412921423f69bc7ead546f62543784bce3d30bf6)) +- Generative Replace Background ([#167](https://github.com/cloudinary-community/cloudinary-util/issues/167)) ([4129214](https://github.com/cloudinary-community/cloudinary-util/commit/412921423f69bc7ead546f62543784bce3d30bf6)) # [@cloudinary-util/url-loader-v5.5.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.5.0-beta.1...@cloudinary-util/url-loader-v5.5.0-beta.2) (2024-08-02) ### Features -* force version ([cb63bff](https://github.com/cloudinary-community/cloudinary-util/commit/cb63bff1efa23eb2968c2b8b0094235987a68012)) +- force version ([cb63bff](https://github.com/cloudinary-community/cloudinary-util/commit/cb63bff1efa23eb2968c2b8b0094235987a68012)) # [@cloudinary-util/url-loader-v5.5.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.4.0...@cloudinary-util/url-loader-v5.5.0-beta.1) (2024-08-02) - ### Features -* getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) +- getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) # [@cloudinary-util/url-loader-v5.4.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.3.1...@cloudinary-util/url-loader-v5.4.0-beta.1) (2024-08-02) - ### Features -* getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) +- getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) # [@cloudinary-util/url-loader-v5.5.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.4.0...@cloudinary-util/url-loader-v5.5.0) (2024-08-02) -* Generative Replace Background ([#167](https://github.com/cloudinary-community/cloudinary-util/issues/167)) ([4129214](https://github.com/cloudinary-community/cloudinary-util/commit/412921423f69bc7ead546f62543784bce3d30bf6)) +- Generative Replace Background ([#167](https://github.com/cloudinary-community/cloudinary-util/issues/167)) ([4129214](https://github.com/cloudinary-community/cloudinary-util/commit/412921423f69bc7ead546f62543784bce3d30bf6)) # [@cloudinary-util/url-loader-v5.4.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.3.1...@cloudinary-util/url-loader-v5.4.0-beta.1) (2024-07-09) - ### Features -* Improve plugin types, modernize monorepo structure ([#161](https://github.com/cloudinary-community/cloudinary-util/issues/161)) ([8ad6066](https://github.com/cloudinary-community/cloudinary-util/commit/8ad60661d4b3c78c08e9dd1939171a689eeb7b08)) +- Improve plugin types, modernize monorepo structure ([#161](https://github.com/cloudinary-community/cloudinary-util/issues/161)) ([8ad6066](https://github.com/cloudinary-community/cloudinary-util/commit/8ad60661d4b3c78c08e9dd1939171a689eeb7b08)) # [@cloudinary-util/url-loader-v5.3.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.3.0...@cloudinary-util/url-loader-v5.3.1) (2024-05-24) diff --git a/packages/url-loader/build.ts b/packages/url-loader/build.ts deleted file mode 100644 index a42e9ee7..00000000 --- a/packages/url-loader/build.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { fromHere, readFile, shell, walkPaths, writeFile } from "@arktype/fs"; -import { printNode, zodToTs } from "zod-to-ts"; -import { constructUrlPropsSchema } from "./src/schema.js"; - -shell("pnpm tsup src/index.ts src/schema.ts --format esm,cjs --dts --clean"); - -const tsTypeSrc = printNode( - zodToTs(constructUrlPropsSchema, "constructUrlPropsSchema").node -); - -walkPaths(fromHere("dist"), { - include: (path) => path.endsWith("ts"), -}).forEach((path) => { - const originalSrc = readFile(path); - writeFile( - path, - originalSrc.replace( - "type ConstructUrlProps = z.infer;", - `type ConstructUrlProps = ${tsTypeSrc};` - ) - ); -}); diff --git a/packages/url-loader/package.json b/packages/url-loader/package.json index 5f71201f..793314ca 100644 --- a/packages/url-loader/package.json +++ b/packages/url-loader/package.json @@ -8,10 +8,6 @@ ".": { "require": "./dist/index.cjs", "import": "./dist/index.js" - }, - "./schema": { - "require": "./dist/schema.cjs", - "import": "./dist/schema.js" } }, "sideEffects": false, @@ -20,7 +16,7 @@ "dist/**" ], "scripts": { - "build": "tsx ./build.ts", + "build": "pnpm tsup src --format esm,cjs --dts --clean --no-splitting", "dev": "tsup src/index.ts src/schema.ts --format esm,cjs --watch --dts", "lint": "TIMING=1 eslint \"src/**/*.ts*\"", "lint:attw": "attw --pack . --exclude-entrypoints \"schema\"", @@ -34,12 +30,10 @@ "dependencies": { "@cloudinary-util/types": "workspace:*", "@cloudinary-util/util": "workspace:*", - "@cloudinary/url-gen": "1.15.0", - "zod": "^3.22.4" + "@cloudinary/url-gen": "1.15.0" }, "devDependencies": { - "@types/node": "^17.0.12", - "zod-to-ts": "^1.2.0" + "@types/node": "^17.0.12" }, "publishConfig": { "access": "public" diff --git a/packages/url-loader/src/constants/parameters.ts b/packages/url-loader/src/constants/parameters.ts index 09a1a290..4b67a5e4 100644 --- a/packages/url-loader/src/constants/parameters.ts +++ b/packages/url-loader/src/constants/parameters.ts @@ -1,309 +1,209 @@ -import { z } from "zod"; - -/** enum */ - -export const cropModesEnum = z.enum([ - "auto", - "crop", - "fill", - "fill_pad", - "fit", - "imagga_crop", - "imagga_scale", - "lfill", - "limit", - "lpad", - "mfit", - "mpad", - "pad", - "scale", - "thumb", -]); - -export const extractModesEnum = z.enum([ - "content", - "mask", -]); - -export const flagsEnum = z.enum([ - "animated", - "any_format", - "apng", - "attachment", - "awebp", - "clip", - "clip_evenodd", - "cutter", - "force_icc", - "force_strip", - "getinfo", - "group4", - "hlsv3", - "ignore_aspect_ratio", - "ignore_mask_channels", - "immutable_cache", - "keep_attribution", - "keep_dar", - "keep_iptc", - "layer_apply", - "lossy", - "mono", - "no_overflow", - "no_stream", - "png8_fl_png24_fl_png32", - "preserve_transparency", - "progressive", - "rasterize", - "region_relative", - "relative", - "replace_image", - "sanitize", - "splice", - "streaming_attachment", - "strip_profile", - "text_disallow_overflow", - "text_no_trim", - "tiff8_lzw", - "tiled", - "truncate_ts", - "waveform", -]); - -/** Angle - a */ - -export const angle = { - qualifier: "a", - schema: z.union([z.string(), z.number()]).describe( - JSON.stringify({ - text: "Rotates or flips an asset by the specified number of degrees or automatically according to its orientation or available metadata.", - url: "https://cloudinary.com/documentation/transformation_reference#a_angle", - }), - ), -}; +import type { StringifiablePrimative } from "../lib/utils.js"; + +/** + * @description Mode to use when cropping an asset. + * @url https://cloudinary.com/documentation/transformation_reference#c_crop_resize + */ +export type CropMode = + | "auto" + | "crop" + | "fill" + | "fill_pad" + | "fit" + | "imagga_crop" + | "imagga_scale" + | "lfill" + | "limit" + | "lpad" + | "mfit" + | "mpad" + | "pad" + | "scale" + | "thumb"; + +/** + * @description Whether to keep the content of the extracted area, or to replace it with a mask. + * @url https://cloudinary.com/documentation/transformation_reference#e_extract + */ +export type ExtractMode = "content" | "mask"; + +/** + * @description Rotates or flips an asset by the specified number of degrees or automatically according to its orientation or available metadata. + * @url https://cloudinary.com/documentation/transformation_reference#a_angle + */ +export type Angle = string | number; /** Aspect Ratio */ -export const aspectRatioModesEnum = z.enum([ - "vflip", - "hflip", - "ignore", - "auto_right", - "auto_left", -]); - -const aspectRatioSchema = z.union([ - z.number(), - aspectRatioModesEnum, - z.intersection(z.string(), z.object({})) // Quirk to allow enum + string -]); - -export const aspectRatio = { - qualifier: "ar", - schema: aspectRatioSchema.describe( - JSON.stringify({ - text: "Crops or resizes the asset to a new aspect ratio.", - url: "https://cloudinary.com/documentation/transformation_reference#ar_aspect_ratio", - }), - ), -}; - -/** Crop */ - -const cropSchema = cropModesEnum; - -export const crop = { - qualifier: "c", - schema: cropSchema.describe( - JSON.stringify({ - text: "Mode to use when cropping an asset.", - url: "https://cloudinary.com/documentation/transformation_reference#c_crop_resize", - }), - ), -}; - -/** extractMode */ - -const extractModeSchema = extractModesEnum; - -export const extractMode = { - schema: extractModeSchema - .default('content') - .describe(JSON.stringify({ - text: "Whether to keep the content of the extracted area, or to replace it with a mask.", - url: "https://cloudinary.com/documentation/transformation_reference#e_extract", - }), - ), -}; - -/** Flags */ - -export const flags = { - qualifier: "fl", - schema: z.union([flagsEnum, z.array(flagsEnum)]).describe( - JSON.stringify({ - text: "Alters the regular behavior of another transformation or the overall delivery behavior.", - url: "https://cloudinary.com/documentation/transformation_reference#fl_flag", - }), - ), -}; - -/** Format */ - -export const format = { - qualifier: "f", - // @TODO: enum - schema: z.string().describe( - JSON.stringify({ - text: "Converts (if necessary) and delivers an asset in the specified format regardless of the file extension used in the delivery URL.", - url: "https://cloudinary.com/documentation/transformation_reference#f_format", - }), - ), -}; - -/** Gravity */ - -export type Gravity = z.infer; - -const gravitySchema = z.union([ - z.enum([ - "auto", - "auto_content_aware", - "center", - "custom", - "east", - "face", - "face_center", - "multi_face", - "north", - "north_east", - "north_west", - "south", - "south_east", - "south_west", - "west", - "xy_center", - "face:center", - "face:auto", - "faces", - "faces:center", - "faces:auto", - "body", - "body:face", - "adv_face", - "adv_faces", - "adv_eyes", - "custom:face", - "custom:faces", - "custom:adv_face", - "custom:adv_faces", - "auto:adv_face", - "auto:adv_faces", - "auto:adv_eyes", - "auto:body", - "auto:face", - "auto:faces", - "auto:custom_no_override", - "auto:none", - "liquid", - "ocr_text" - ]), - // Quirk to allow enum + string - z.intersection(z.string(), z.object({})) -]); - -export const gravity = { - qualifier: "g", - schema: gravitySchema.describe( - JSON.stringify({ - text: "Determines which part of an asset to focus on. Note: Default of auto is applied for supported crop modes only.", - url: "https://cloudinary.com/documentation/transformation_reference#g_gravity", - }), - ), -}; - -/** Height */ - -const heightSchema = z.union([z.number(), z.string()]); - -export const height = { - qualifier: "h", - schema: heightSchema.describe( - JSON.stringify({ - text: "A qualifier that determines the height of a transformed asset or an overlay.", - url: "https://cloudinary.com/documentation/transformation_reference#h_height", - }), - ), -}; - -/** Multiple */ - -const multipleSchema = z.boolean(); - -export const multiple = { - schema: multipleSchema.describe( - JSON.stringify({ - text: "Should generative AI features detect multiple instances.", - }), - ), -}; - -/** Prompt */ - -export const prompt = { - schema: z.string().describe( - JSON.stringify({ - text: "Natural language descriptions used for generative AI capabilities.", - }), - ), -}; - -/** Width */ - -const widthSchema = z.union([z.number(), z.string()]); - -export const width = { - qualifier: "w", - schema: widthSchema.describe( - JSON.stringify({ - text: "A qualifier that sets the desired width of an asset using a specified value, or automatically based on the available width.", - url: "https://cloudinary.com/documentation/transformation_reference#w_width", - }), - ), -}; - -/** X */ - -export const x = { - qualifier: "x", - schema: z.union([z.string(), z.number()]).describe( - JSON.stringify({ - text: "Adjusts the starting location or offset of the x axis.", - url: "https://cloudinary.com/documentation/transformation_reference#x_y_coordinates", - }), - ), -}; - -/** Y */ - -export const y = { - qualifier: "y", - schema: z.union([z.string(), z.number()]).describe( - JSON.stringify({ - text: "Adjusts the starting location or offset of the y axis.", - url: "https://cloudinary.com/documentation/transformation_reference#x_y_coordinates", - }), - ), -}; +export type AspectRatioMode = + | "vflip" + | "hflip" + | "ignore" + | "auto_right" + | "auto_left"; + +/** + * @description Crops or resizes the asset to a new aspect ratio. + * @url https://cloudinary.com/documentation/transformation_reference#ar_aspect_ratio + */ +export type AspectRatio = AspectRatioMode | number | (string & {}); + +export type Flag = + | "animated" + | "any_format" + | "apng" + | "attachment" + | "awebp" + | "clip" + | "clip_evenodd" + | "cutter" + | "force_icc" + | "force_strip" + | "getinfo" + | "group4" + | "hlsv3" + | "ignore_aspect_ratio" + | "ignore_mask_channels" + | "immutable_cache" + | "keep_attribution" + | "keep_dar" + | "keep_iptc" + | "layer_apply" + | "lossy" + | "mono" + | "no_overflow" + | "no_stream" + | "png8_fl_png24_fl_png32" + | "preserve_transparency" + | "progressive" + | "rasterize" + | "region_relative" + | "relative" + | "replace_image" + | "sanitize" + | "splice" + | "streaming_attachment" + | "strip_profile" + | "text_disallow_overflow" + | "text_no_trim" + | "tiff8_lzw" + | "tiled" + | "truncate_ts" + | "waveform"; + +/** + * @description Alters the regular behavior of another transformation or the overall delivery behavior. + * @url https://cloudinary.com/documentation/transformation_reference#fl_flag + * @qualifier fl + */ +export type FlagsDefinition = ListableFlags | FlagRecord; + +export type ListableFlags = Flag | ReadonlyArray; + +export type FlagRecord = Partial>; + +/** + * @description Converts (if necessary) and delivers an asset in the specified format regardless of the file extension used in the delivery URL. + * @url https://cloudinary.com/documentation/transformation_reference#f_format + * @qualifier f + */ +export type Format = string; + +/** + * @description Determines which part of an asset to focus on. Note: Default of auto is applied for supported crop modes only. + * @url https://cloudinary.com/documentation/transformation_reference#g_gravity + */ +export type Gravity = + | "auto" + | "auto_content_aware" + | "center" + | "custom" + | "east" + | "face" + | "face_center" + | "multi_face" + | "north" + | "north_east" + | "north_west" + | "south" + | "south_east" + | "south_west" + | "west" + | "xy_center" + | "face:center" + | "face:auto" + | "faces" + | "faces:center" + | "faces:auto" + | "body" + | "body:face" + | "adv_face" + | "adv_faces" + | "adv_eyes" + | "custom:face" + | "custom:faces" + | "custom:adv_face" + | "custom:adv_faces" + | "auto:adv_face" + | "auto:adv_faces" + | "auto:adv_eyes" + | "auto:body" + | "auto:face" + | "auto:faces" + | "auto:custom_no_override" + | "auto:none" + | "liquid" + | "ocr_text" + | (string & {}); + +/** + * @description A qualifier that determines the height of a transformed asset or an overlay. + * @url https://cloudinary.com/documentation/transformation_reference#h_height + */ +export type Height = number | string; + +/** + * @description Should generative AI features detect multiple instances. + */ +export type Multiple = boolean; + +/** + * @description Natural language descriptions used for generative AI capabilities. + */ +export type ListablePrompts = string | ReadonlyArray; + +/** + * @description A qualifier that sets the desired width of an asset using a specified value, or automatically based on the available width. + * @url https://cloudinary.com/documentation/transformation_reference#w_width + */ +export type Width = number | string; + +/** + * @description Adjusts the starting location or offset of the x axis. + * @url https://cloudinary.com/documentation/transformation_reference#x_y_coordinates + */ +export type X = number | string; + +/** + * @description Adjusts the starting location or offset of the y axis. + * @url https://cloudinary.com/documentation/transformation_reference#x_y_coordinates + */ +export type Y = number | string; /** Zoom */ -const zoomSchema = z.string(); - -export const zoom = { - schema: zoomSchema.describe( - JSON.stringify({ - text: "Controls how close to crop to the detected coordinates when using face-detection, custom-coordinate, or object-specific gravity.", - url: "https://cloudinary.com/documentation/transformation_reference#z_zoom", - }), - ), -}; +/** + * @description Controls how close to crop to the detected coordinates when using face-detection, custom-coordinate, or object-specific gravity. + * @url https://cloudinary.com/documentation/transformation_reference#z_zoom + */ +export type Zoom = number | string; + +// this was originally called PositionOptions but it conflicts with a +// DOM type, leading to confusing results if e.g. the import is deleted, +// the type falls back to the global +export interface PositionalOptions { + angle?: Angle; + gravity?: Gravity; + x?: X; + y?: Y; +} diff --git a/packages/url-loader/src/constants/qualifiers.ts b/packages/url-loader/src/constants/qualifiers.ts index 301fcdbe..9af1a60f 100644 --- a/packages/url-loader/src/constants/qualifiers.ts +++ b/packages/url-loader/src/constants/qualifiers.ts @@ -1,41 +1,47 @@ import { convertColorHexToRgb, testColorIsHex } from "@cloudinary-util/util"; -import { z } from "zod"; - -import type { Qualifier } from "../types/qualifiers.js"; -import { - angle, - aspectRatio, - crop, - gravity, - height, - width, - x, - y, -} from "./parameters.js"; - -const convertersColors = [ + +import type { OptionName } from "../lib/plugin.js"; +import type { + QualifierConfig, + QualifierConverters, +} from "../types/qualifiers.js"; +import type { Angle, PositionalOptions } from "./parameters.js"; + +const convertersColors: QualifierConverters[] = [ { test: testColorIsHex, convert: convertColorHexToRgb, }, ]; -export const primary: Record = { - aspectRatio, - crop, - gravity, - height, - width, -} as const; - -export const position: Record = { - angle, - gravity, - x, - y, -} as const; - -export const text: Record = { +export const primary: { [k in OptionName]?: QualifierConfig } = { + aspectRatio: { + qualifier: "ar", + }, + crop: { + qualifier: "c", + }, + gravity: { + qualifier: "g", + }, + height: { + qualifier: "h", + }, + width: { qualifier: "w" }, +}; + +export const position: { [k in keyof PositionalOptions]-?: QualifierConfig } = { + angle: { + qualifier: "a", + }, + gravity: { + qualifier: "g", + }, + x: { qualifier: "x" }, + y: { qualifier: "y" }, +}; + +export const text: Record = { alignment: { qualifier: false, order: 6, @@ -85,514 +91,520 @@ export const text: Record = { qualifier: false, order: 5, }, -} as const; +}; + +export interface QualifierOptions { + angle?: Angle; + + /** + * @description Applies the selected artistic filter. + * @url https://cloudinary.com/documentation/transformation_reference#e_art + */ + art?: string; + + /** + * @description Automatically adjusts the image brightness and blends the result with the original image. + * @url https://cloudinary.com/documentation/transformation_reference#e_auto_brightness + */ + autoBrightness?: boolean | string; + + /** + * @description Automatically adjusts the image color balance and blends the result with the original image. + * @url https://cloudinary.com/documentation/transformation_reference#e_auto_color + */ + autoColor?: boolean | string; + + /** + * @description Automatically adjusts the image contrast and blends the result with the original image. + * @url https://cloudinary.com/documentation/transformation_reference#e_auto_contrast + */ + autoContrast?: boolean | string; + + /** + * @description Applies stripes or color adjustment to help people with common color blind conditions to differentiate between colors that are similar for them. + * @url https://cloudinary.com/documentation/transformation_reference#e_assist_colorblind + */ + assistColorblind?: boolean | string; + + /** + * @description Applies a background to empty or transparent areas. + * @url https://cloudinary.com/documentation/transformation_reference#b_background + */ + background?: string; + + /** + * @description Converts an image to black and white. + * @url https://cloudinary.com/documentation/transformation_reference#e_blackwhite + */ + blackwhite?: boolean | string; + + /** + * @description Applies a blurring filter to an asset. + * @url https://cloudinary.com/documentation/transformation_reference#e_blur + */ + blur?: boolean | string; + + /** + * @description Blurs all detected faces in an image. + * @url https://cloudinary.com/documentation/transformation_reference#e_blur_faces + */ + blurFaces?: boolean | string; + + /** + * @description Applies a blurring filter to the region of an image specified by x, y, width and height, or an area of text. If no region is specified, the whole image is blurred. + * @url https://cloudinary.com/documentation/transformation_reference#e_blur_region + */ + blurRegion?: boolean | string; + + /** + * @description Adds a solid border around an image or video. + * @url https://cloudinary.com/documentation/transformation_reference#bo_border + */ + border?: string; + + /** + * @description Adjusts the image or video brightness. + * @url https://cloudinary.com/documentation/transformation_reference#e_brightness + */ + brightness?: boolean | string; + + /** + * @description Adjusts image brightness modulation in HSB to prevent artifacts in some images. + * @url https://cloudinary.com/documentation/transformation_reference#e_brightness_hsb + */ + brightnessHSB?: boolean | string; + + /** + * @description Applies a cartoon effect to an image. + * @url https://cloudinary.com/documentation/transformation_reference#e_cartoonify + */ + cartoonify?: boolean | string; + + /** + * @description A qualifier that specifies the color to use with the corresponding transformation. + * @url https://cloudinary.com/documentation/transformation_reference#co_color + */ + color?: string; + + /** + * @description Colorizes an image. By default, gray is used for colorization. You can specify a different color using the color qualifier. + * @url https://cloudinary.com/documentation/transformation_reference#e_colorize + */ + colorize?: number | string; + + /** + * @description Adjusts an image or video contrast. + * @url https://cloudinary.com/documentation/transformation_reference#e_contrast + */ + contrast?: boolean | string; + + /** + * @description Displaces the pixels in an image according to the color channels of the pixels in another specified image (a gradient map specified with the overlay parameter). + * @url https://cloudinary.com/documentation/transformation_reference#e_displace + */ + displace?: string; + + /** + * @description Distorts an image to a new shape by either adjusting its corners or by warping it into an arc. + * @url https://cloudinary.com/documentation/transformation_reference#e_distort + */ + distort?: string; + + /** + * @description Adjusts the fill light and optionally blends the result with the original image. + * @url https://cloudinary.com/documentation/transformation_reference#e_fill_light + */ + fillLight?: boolean | string; + + /** + * @description Adjusts the image or video gamma level. + * @url https://cloudinary.com/documentation/transformation_reference#e_gamma + */ + gamma?: boolean | string; + + /** + * @description Applies a gradient fade effect from the edge of an image. + * @url https://cloudinary.com/documentation/transformation_reference#e_gradient_fade + */ + gradientFade?: boolean | string; + + /** + * @description Converts an image to grayscale (multiple shades of gray). + * @url https://cloudinary.com/documentation/transformation_reference#e_grayscale + */ + grayscale?: boolean; + + /** + * @description Adjusts an image's hue. + * @url https://cloudinary.com/documentation/transformation_reference#e_hue + */ + hue?: boolean | string; + + /** + * @description Adjusts an image's colors, contrast and brightness to improve its appearance. + * @url https://cloudinary.com/documentation/transformation_reference#e_improve + */ + improve?: boolean | string; + + /** + * @description Loops a video or animated image the specified number of times. + * @url https://cloudinary.com/documentation/transformation_reference#e_loop + */ + loop?: boolean | number | string; + + /** + * @description A qualifier that blends image layers using the multiply blend mode. + * @url https://cloudinary.com/documentation/transformation_reference#e_multiply + */ + multiply?: boolean; + + /** + * @description https://cloudinary.com/documentation/transformation_reference#e_negate + * @url https://cloudinary.com/documentation/transformation_reference#e_negate + */ + negate?: string | boolean; + + /** + * @description https://cloudinary.com/documentation/transformation_reference#e_noise + * @url https://cloudinary.com/documentation/transformation_reference#e_noise + */ + noise?: boolean; + + /** + * @description https://cloudinary.com/documentation/transformation_reference#e_oil_paint + * @url https://cloudinary.com/documentation/transformation_reference#e_oil_paint + */ + oilPaint?: string | boolean; + + /** + * @description Adjusts the opacity of an asset and makes it semi-transparent. + * @url https://cloudinary.com/documentation/transformation_reference#o_opacity + */ + opacity?: string | number; + + /** + * @description Adds an outline effect to an image. + * @url https://cloudinary.com/documentation/transformation_reference#e_outline + */ + outline?: boolean | string; + + /** + * @description Applies a pixelation effect. + * @url https://cloudinary.com/documentation/transformation_reference#e_pixelate + */ + pixelate?: boolean | string; + + /** + * @description Pixelates all detected faces in an image. + * @url https://cloudinary.com/documentation/transformation_reference#e_pixelate_faces + */ + pixelateFaces?: boolean | string; + + /** + * @description Pixelates the region of an image specified by x, y, width and height, or an area of text. + * @url https://cloudinary.com/documentation/transformation_reference#e_pixelate_region + */ + pixelateRegion?: boolean | string; + + /** + * @description Rounds the corners of an image or video. + * @url https://cloudinary.com/documentation/transformation_reference#r_round_corners + */ + radius?: string | number; + + /** + * @description Automatically removes red eyes in an image. + * @url https://cloudinary.com/documentation/transformation_reference#e_redeye + */ + redeye?: boolean | string; + + /** + * @description Maps an input color and those similar to the input color to corresponding shades of a specified output color. + * @url https://cloudinary.com/documentation/transformation_reference#e_replace_color + */ + replaceColor?: string; + + /** + * @description Adjusts an image or video saturation level. + * @url https://cloudinary.com/documentation/transformation_reference#e_saturation + */ + saturation?: boolean | string; + + /** + * @description A qualifier that blends image layers using the screen blend mode. + * @url https://cloudinary.com/documentation/transformation_reference#e_screen + */ + screen?: boolean; + + /** + * @description Changes the color scheme of an image to sepia. + * @url https://cloudinary.com/documentation/transformation_reference#e_sepia + */ + sepia?: boolean | string; + + /** + * @description Adds a gray shadow to the bottom right of an image. + * @url https://cloudinary.com/documentation/transformation_reference#e_shadow + */ + shadow?: boolean | string; + + /** + * @description Applies a sharpening filter. + * @url https://cloudinary.com/documentation/transformation_reference#e_sharpen + */ + sharpen?: boolean | string; + + /** + * @description Skews an image according to the two specified values in degrees. + * @url https://cloudinary.com/documentation/transformation_reference#e_shear + */ + shear?: string; + + /** + * @description Simulates the way an image would appear to someone with the specified color blind condition. + * @url https://cloudinary.com/documentation/transformation_reference#e_simulate_colorblind + */ + simulateColorblind?: boolean | string; + + /** + * @description Blends an image with one or more tint colors at a specified intensity. + * @url https://cloudinary.com/documentation/transformation_reference#e_tint + */ + tint?: boolean | string; + + /** + * @description Detects and removes image edges whose color is similar to the corner pixels. + * @url https://cloudinary.com/documentation/transformation_reference#e_trim + */ + trim?: boolean | string; + + /** + * @description Applies an unsharp mask filter to an image. + * @url https://cloudinary.com/documentation/transformation_reference#e_unsharp_mask + */ + unsharpMask?: boolean | string; + + /** + * @description Vectorizes an image. + * @url https://cloudinary.com/documentation/transformation_reference#e_vectorize + */ + vectorize?: boolean | string; + + /** + * @description Applies a vibrance filter to an image. + * @url https://cloudinary.com/documentation/transformation_reference#e_vibrance + */ + vibrance?: boolean | string; + + /** + * @description Applies a vignette effect to an image. + * @url https://cloudinary.com/documentation/transformation_reference#e_vignette + */ + vignette?: boolean | string; +} export const effects = { - angle, + angle: { + qualifier: "a", + }, art: { prefix: "e", qualifier: "art", - schema: z.string().describe( - JSON.stringify({ - text: "Applies the selected artistic filter.", - url: "https://cloudinary.com/documentation/transformation_reference#e_art", - }) - ), }, autoBrightness: { prefix: "e", qualifier: "auto_brightness", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Automatically adjusts the image brightness and blends the result with the original image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_auto_brightness", - }) - ), }, autoColor: { prefix: "e", qualifier: "auto_color", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Automatically adjusts the image color balance and blends the result with the original image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_auto_color", - }) - ), }, autoContrast: { prefix: "e", qualifier: "auto_contrast", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Automatically adjusts the image contrast and blends the result with the original image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_auto_contrast", - }) - ), }, assistColorblind: { prefix: "e", qualifier: "assist_colorblind", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Applies stripes or color adjustment to help people with common color blind conditions to differentiate between colors that are similar for them.", - url: "https://cloudinary.com/documentation/transformation_reference#e_assist_colorblind", - }) - ), }, background: { qualifier: "b", - schema: z.string().describe( - JSON.stringify({ - text: "Applies a background to empty or transparent areas.", - url: "https://cloudinary.com/documentation/transformation_reference#b_background", - }) - ), }, blackwhite: { prefix: "e", qualifier: "blackwhite", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Converts an image to black and white.", - url: "https://cloudinary.com/documentation/transformation_reference#e_blackwhite", - }) - ), }, blur: { prefix: "e", qualifier: "blur", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Applies a blurring filter to an asset.", - url: "https://cloudinary.com/documentation/transformation_reference#e_blur", - }) - ), }, blurFaces: { prefix: "e", qualifier: "blur_faces", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Blurs all detected faces in an image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_blur_faces", - }) - ), }, blurRegion: { prefix: "e", qualifier: "blur_region", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Applies a blurring filter to the region of an image specified by x, y, width and height, or an area of text. If no region is specified, the whole image is blurred.", - url: "https://cloudinary.com/documentation/transformation_reference#e_blur_region", - }) - ), }, border: { qualifier: "bo", - schema: z.string().describe( - JSON.stringify({ - text: "Adds a solid border around an image or video.", - url: "https://cloudinary.com/documentation/transformation_reference#bo_border", - }) - ), }, brightness: { prefix: "e", qualifier: "brightness", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Adjusts the image or video brightness.", - url: "https://cloudinary.com/documentation/transformation_reference#e_brightness", - }) - ), }, brightnessHSB: { prefix: "e", qualifier: "brightness_hsb", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Adjusts image brightness modulation in HSB to prevent artifacts in some images.", - url: "https://cloudinary.com/documentation/transformation_reference#e_brightness_hsb", - }) - ), }, cartoonify: { prefix: "e", qualifier: "cartoonify", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Applies a cartoon effect to an image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_cartoonify", - }) - ), }, color: { qualifier: "co", - schema: z.string().describe( - JSON.stringify({ - text: "A qualifier that specifies the color to use with the corresponding transformation.", - url: "https://cloudinary.com/documentation/transformation_reference#co_color", - }) - ), converters: convertersColors, }, colorize: { prefix: "e", qualifier: "colorize", - schema: z.string().describe( - JSON.stringify({ - text: "Colorizes an image. By default, gray is used for colorization. You can specify a different color using the color qualifier.", - url: "https://cloudinary.com/documentation/transformation_reference#e_colorize", - }) - ), }, contrast: { prefix: "e", qualifier: "contrast", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Adjusts an image or video contrast.", - url: "https://cloudinary.com/documentation/transformation_reference#e_contrast", - }) - ), }, displace: { prefix: "e", qualifier: "distort", - schema: z.string().describe( - JSON.stringify({ - text: "Displaces the pixels in an image according to the color channels of the pixels in another specified image (a gradient map specified with the overlay parameter).", - url: "https://cloudinary.com/documentation/transformation_reference#e_displace", - }) - ), }, distort: { prefix: "e", qualifier: "distort", - schema: z.string().describe( - JSON.stringify({ - text: "Distorts an image to a new shape by either adjusting its corners or by warping it into an arc.", - url: "https://cloudinary.com/documentation/transformation_reference#e_distort", - }) - ), }, fillLight: { prefix: "e", qualifier: "fill_light", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Adjusts the fill light and optionally blends the result with the original image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_fill_light", - }) - ), }, gamma: { prefix: "e", qualifier: "gamma", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Adjusts the image or video gamma level.", - url: "https://cloudinary.com/documentation/transformation_reference#e_gamma", - }) - ), }, gradientFade: { prefix: "e", qualifier: "gradient_fade", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Applies a gradient fade effect from the edge of an image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_gradient_fade", - }) - ), }, grayscale: { prefix: "e", qualifier: "grayscale", - schema: z.boolean().describe( - JSON.stringify({ - text: "Converts an image to grayscale (multiple shades of gray).", - url: "https://cloudinary.com/documentation/transformation_reference#e_grayscale", - }) - ), }, hue: { prefix: "e", qualifier: "hue", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Adjusts an image's hue.", - url: "https://cloudinary.com/documentation/transformation_reference#e_hue", - }) - ), }, improve: { prefix: "e", qualifier: "improve", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Adjusts an image's colors, contrast and brightness to improve its appearance.", - url: "https://cloudinary.com/documentation/transformation_reference#e_improve", - }) - ), }, loop: { prefix: "e", qualifier: "loop", - schema: z.union([z.boolean(), z.number(), z.string()]).describe( - JSON.stringify({ - text: "Loops a video or animated image the specified number of times.", - url: "https://cloudinary.com/documentation/transformation_reference#e_loop", - }) - ), }, multiply: { prefix: "e", qualifier: "multiply", - schema: z.boolean().describe( - JSON.stringify({ - text: "A qualifier that blends image layers using the multiply blend mode", - url: "https://cloudinary.com/documentation/transformation_reference#e_multiply", - }) - ), }, negate: { prefix: "e", qualifier: "negate", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "https://cloudinary.com/documentation/transformation_reference#e_negate", - url: "https://cloudinary.com/documentation/transformation_reference#e_negate", - }) - ), }, noise: { prefix: "e", qualifier: "noise", - schema: z.boolean().describe( - JSON.stringify({ - text: "https://cloudinary.com/documentation/transformation_reference#e_noise", - url: "https://cloudinary.com/documentation/transformation_reference#e_noise", - }) - ), }, oilPaint: { prefix: "e", qualifier: "oil_paint", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "https://cloudinary.com/documentation/transformation_reference#e_oil_paint", - url: "https://cloudinary.com/documentation/transformation_reference#e_oil_paint", - }) - ), }, opacity: { qualifier: "o", - schema: z.union([z.string(), z.number()]).describe( - JSON.stringify({ - text: "Adjusts the opacity of an asset and makes it semi-transparent.", - url: "https://cloudinary.com/documentation/transformation_reference#o_opacity", - }) - ), }, outline: { prefix: "e", qualifier: "outline", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Adds an outline effect to an image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_outline", - }) - ), }, pixelate: { prefix: "e", qualifier: "pixelate", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Applies a pixelation effect.", - url: "https://cloudinary.com/documentation/transformation_reference#e_pixelate", - }) - ), }, pixelateFaces: { prefix: "e", qualifier: "pixelate_faces", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Pixelates all detected faces in an image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_pixelate_faces", - }) - ), }, pixelateRegion: { prefix: "e", qualifier: "pixelate_region", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Pixelates the region of an image specified by x, y, width and height, or an area of text.", - url: "https://cloudinary.com/documentation/transformation_reference#e_pixelate_region", - }) - ), }, radius: { qualifier: "r", - schema: z.union([ z.string(), z.number() ]).describe( - JSON.stringify({ - text: "Rounds the corners of an image or video.", - url: "https://cloudinary.com/documentation/transformation_reference#r_round_corners", - }) - ), }, redeye: { prefix: "e", qualifier: "redeye", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Automatically removes red eyes in an image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_redeye", - }) - ), }, replaceColor: { prefix: "e", qualifier: "replace_color", - schema: z.string().describe( - JSON.stringify({ - text: "Maps an input color and those similar to the input color to corresponding shades of a specified output color.", - url: "https://cloudinary.com/documentation/transformation_reference#e_replace_color", - }) - ), }, saturation: { prefix: "e", qualifier: "saturation", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Adjusts an image or video saturation level.", - url: "https://cloudinary.com/documentation/transformation_reference#e_saturation", - }) - ), }, screen: { prefix: "e", qualifier: "screen", - schema: z.boolean().describe( - JSON.stringify({ - text: "A qualifier that blends image layers using the screen blend mode.", - url: "https://cloudinary.com/documentation/transformation_reference#e_screen", - }) - ), }, sepia: { prefix: "e", qualifier: "sepia", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Changes the color scheme of an image to sepia.", - url: "https://cloudinary.com/documentation/transformation_reference#e_sepia", - }) - ), }, shadow: { prefix: "e", qualifier: "shadow", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Adds a gray shadow to the bottom right of an image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_shadow", - }) - ), }, sharpen: { prefix: "e", qualifier: "sharpen", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Applies a sharpening filter.", - url: "https://cloudinary.com/documentation/transformation_reference#e_sharpen", - }) - ), }, shear: { prefix: "e", qualifier: "shear", - schema: z.string().describe( - JSON.stringify({ - text: "Skews an image according to the two specified values in degrees.", - url: "https://cloudinary.com/documentation/transformation_reference#e_shear", - }) - ), }, simulateColorblind: { prefix: "e", qualifier: "simulate_colorblind", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Simulates the way an image would appear to someone with the specified color blind condition.", - url: "https://cloudinary.com/documentation/transformation_reference#e_simulate_colorblind", - }) - ), }, tint: { prefix: "e", qualifier: "tint", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Blends an image with one or more tint colors at a specified intensity.", - url: "https://cloudinary.com/documentation/transformation_reference#e_tint", - }) - ), }, trim: { prefix: "e", qualifier: "trim", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Detects and removes image edges whose color is similar to the corner pixels.", - url: "https://cloudinary.com/documentation/transformation_reference#e_trim", - }) - ), }, unsharpMask: { prefix: "e", qualifier: "unsharp_mask", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Applies an unsharp mask filter to an image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_unsharp_mask", - }) - ), }, vectorize: { prefix: "e", qualifier: "vectorize", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Vectorizes an image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_vectorize", - }) - ), }, vibrance: { prefix: "e", qualifier: "vibrance", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Applies a vibrance filter to an image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_vibrance", - }) - ), }, vignette: { prefix: "e", qualifier: "vignette", - schema: z.union([z.string(), z.boolean()]).describe( - JSON.stringify({ - text: "Applies a vignette effect to an image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_vignette", - }) - ), - }, -} as const; + }, +} as const satisfies { [k in keyof QualifierOptions]-?: QualifierConfig }; diff --git a/packages/url-loader/src/index.ts b/packages/url-loader/src/index.ts index c255951f..7d7bf9e8 100644 --- a/packages/url-loader/src/index.ts +++ b/packages/url-loader/src/index.ts @@ -3,7 +3,9 @@ export { constructCloudinaryUrl, transformationPlugins, - type ConstructUrlProps + type AnalyticsOptions, + type ConfigOptions, + type ConstructUrlProps, } from "./lib/cloudinary.js"; // Upload Widget @@ -15,12 +17,12 @@ export { type CloudinaryUploadWidgetErrorCallback, type CloudinaryUploadWidgetResultCallback, type GenerateUploadWidgetResultCallback, - type GetUploadWidgetOptions + type GetUploadWidgetOptions, } from "./lib/upload-widget.js"; export { generateSignatureCallback, - type GenerateSignatureCallback + type GenerateSignatureCallback, } from "./lib/upload.js"; // Video Player @@ -28,35 +30,25 @@ export { export { getVideoPlayerOptions, type GetVideoPlayerOptions, - type GetVideoPlayerOptionsLogo + type GetVideoPlayerOptionsLogo, } from "./lib/video-player.js"; // Transformation definitions -export { effects, position, primary, text } from "./constants/qualifiers.js"; +export { + effects, + position as position, + primary as primary, + text, +} from "./constants/qualifiers.js"; // General Types -export type { - AnalyticsOptions, - CloudinaryAnalyticsOptions -} from "./types/analytics.js"; - export type { AssetOptions } from "./types/asset.js"; - -export type { - CloudinaryConfigurationOptions, - ConfigOptions -} from "./types/config.js"; - export type { ImageOptions } from "./types/image.js"; - +export type { PluginOptions, PluginResults } from "./types/plugins.js"; export type { - PluginOptions, - PluginResults, - PluginSettings -} from "./types/plugins.js"; - -export type { QualiferConverters, Qualifier } from "./types/qualifiers.js"; - + QualifierConfig as Qualifier, + QualifierConverters, +} from "./types/qualifiers.js"; export type { VideoOptions } from "./types/video.js"; diff --git a/packages/url-loader/src/lib/cloudinary.ts b/packages/url-loader/src/lib/cloudinary.ts index 76988bcb..3a508f40 100644 --- a/packages/url-loader/src/lib/cloudinary.ts +++ b/packages/url-loader/src/lib/cloudinary.ts @@ -1,130 +1,132 @@ +import type { CloudinaryAssetConfiguration } from "@cloudinary-util/types"; import { objectHasKey, parseUrl, type ParseUrl } from "@cloudinary-util/util"; import { Cloudinary, type CloudinaryImage, type CloudinaryVideo, } from "@cloudinary/url-gen"; -import { z } from "zod"; - -import { abrPlugin } from "../plugins/abr.js"; -import { croppingPlugin } from "../plugins/cropping.js"; -import { defaultImagePlugin } from "../plugins/default-image.js"; -import { effectsPlugin } from "../plugins/effects.js"; -import { enhancePlugin } from "../plugins/enhance.js"; -import { extractPlugin } from "../plugins/extract.js"; -import { fillBackgroundPlugin } from "../plugins/fill-background.js"; -import { flagsPlugin } from "../plugins/flags.js"; -import { namedTransformationsPlugin } from "../plugins/named-transformations.js"; -import { overlaysPlugin } from "../plugins/overlays.js"; -import { preserveTransformationsPlugin } from "../plugins/preserve-transformations.js"; -import { rawTransformationsPlugin } from "../plugins/raw-transformations.js"; -import { recolorPlugin } from "../plugins/recolor.js"; -import { removeBackgroundPlugin } from "../plugins/remove-background.js"; -import { removePlugin } from "../plugins/remove.js"; -import { replaceBackgroundPlugin } from "../plugins/replace-background.js"; -import { replacePlugin } from "../plugins/replace.js"; -import { restorePlugin } from "../plugins/restore.js"; -import { sanitizePlugin } from "../plugins/sanitize.js"; -import { seoPlugin } from "../plugins/seo.js"; -import { underlaysPlugin } from "../plugins/underlays.js"; -import { zoompanPlugin } from "../plugins/zoompan.js"; - -import { analyticsOptionsSchema } from "../types/analytics.js"; -import { configOptionsSchema } from "../types/config.js"; -import { imageOptionsSchema } from "../types/image.js"; -import { videoOptionsSchema } from "../types/video.js"; - -import { versionPlugin } from "../plugins/version.js"; +import type { IAnalyticsOptions } from "@cloudinary/url-gen/sdkAnalytics/interfaces/IAnalyticsOptions"; + +import { AbrPlugin } from "../plugins/abr.js"; +import { DefaultImagePlugin } from "../plugins/default-image.js"; +import { EffectsPlugin } from "../plugins/effects.js"; +import { FillBackgroundPlugin } from "../plugins/fill-background.js"; +import { FlagsPlugin } from "../plugins/flags.js"; +import { PreserveTransformationsPlugin } from "../plugins/preserve-transformations.js"; +import { RawTransformationsPlugin } from "../plugins/raw-transformations.js"; +import { RecolorPlugin } from "../plugins/recolor.js"; +import { RemoveBackgroundPlugin } from "../plugins/remove-background.js"; +import { RemovePlugin } from "../plugins/remove.js"; +import { ReplaceBackgroundPlugin } from "../plugins/replace-background.js"; +import { ReplacePlugin } from "../plugins/replace.js"; +import { RestorePlugin } from "../plugins/restore.js"; +import { SanitizePlugin } from "../plugins/sanitize.js"; +import { SeoPlugin } from "../plugins/seo.js"; +import { UnderlaysPlugin } from "../plugins/underlays.js"; +import { ZoompanPlugin } from "../plugins/zoompan.js"; + +import { CroppingPlugin } from "../plugins/cropping.js"; +import { EnhancePlugin } from "../plugins/enhance.js"; +import { ExtractPlugin } from "../plugins/extract.js"; +import { NamedTransformationsPlugin } from "../plugins/named-transformations.js"; +import { OverlaysPlugin } from "../plugins/overlays.js"; +import { VersionPlugin } from "../plugins/version.js"; import type { - AssetType, - PluginOptions, - PluginResults, - TransformationPlugin, -} from "../types/plugins.js"; - -export const transformationPlugins = [ + BaseAssetOptions, + SupportedAssetTypeInput, +} from "../types/asset.js"; +import type { ImageOptions } from "../types/image.js"; +import type { PluginOptions, PluginResults } from "../types/plugins.js"; +import type { VideoOptions } from "../types/video.js"; +import type { OptionsFor, TransformationPlugin } from "./plugin.js"; +import { entriesOf, throwError } from "./utils.js"; + +const validatePlugins = ( + ...plugins: plugins extends validatePlugins + ? plugins + : validatePlugins +) => plugins; + +export const transformationPlugins = validatePlugins( // Some features *must* be the first transformation applied // thus their plugins *must* come first in the chain - enhancePlugin, - extractPlugin, - recolorPlugin, - removeBackgroundPlugin, - removePlugin, - replacePlugin, - replaceBackgroundPlugin, - restorePlugin, + EnhancePlugin, + ExtractPlugin, + RecolorPlugin, + RemoveBackgroundPlugin, + RemovePlugin, + ReplacePlugin, + ReplaceBackgroundPlugin, + RestorePlugin, // Cropping needs to be before any other general transformations // as it provides the option of 2-step resizing where someone // can resize the "base" canvas as well as the final resize // mechanism commonly used for responsive resizing - croppingPlugin, + CroppingPlugin, // Raw transformations should always come before // other arguments to avoid conflicting with // added options via the component - preserveTransformationsPlugin, - rawTransformationsPlugin, - - abrPlugin, - defaultImagePlugin, - effectsPlugin, - fillBackgroundPlugin, - flagsPlugin, - overlaysPlugin, - sanitizePlugin, - namedTransformationsPlugin, - seoPlugin, - underlaysPlugin, - versionPlugin, - zoompanPlugin, -]; - -const constructUrlOptionsSchema = z - .union([imageOptionsSchema, videoOptionsSchema]) - .describe( - JSON.stringify({ - text: "Asset options (Image or Video) that define delivery URL including public ID and transformations.", - path: "/url-loader/assetoptions", - }), - ); + PreserveTransformationsPlugin, + RawTransformationsPlugin, + + AbrPlugin, + DefaultImagePlugin, + EffectsPlugin, + FillBackgroundPlugin, + FlagsPlugin, + OverlaysPlugin, + SanitizePlugin, + NamedTransformationsPlugin, + SeoPlugin, + UnderlaysPlugin, + VersionPlugin, + ZoompanPlugin +); + +export interface AnalyticsOptions extends IAnalyticsOptions {} + +export interface ConfigOptions extends CloudinaryAssetConfiguration {} + +/** + * @description Asset options (Image or Video) that define delivery URL including public ID and transformations. + * @path /url-loader/assetoptions + */ +export type OptionsInput = ImageOptions | VideoOptions; /** * constructCloudinaryUrl * @description Builds a full Cloudinary URL using transformation plugins specified by options */ -export const constructUrlPropsSchema = z.object({ - analytics: z - .union([analyticsOptionsSchema, z.boolean()]) - .describe( - JSON.stringify({ - text: "Tech, dependency, and feature identifiers for tracking SDK usage related to Cloudinary.", - path: "/url-loader/analyticsoptions", - }), - ) - .optional(), - config: configOptionsSchema - .describe( - JSON.stringify({ - text: "Configuration parameters for environment and Cloudinary account.", - url: "https://cloudinary.com/documentation/cloudinary_sdks#configuration_parameters", - path: "/url-loader/analyticsoptions", - }), - ) - .optional(), - options: constructUrlOptionsSchema, -}); - -export type ConstructUrlProps = z.infer; - -export function constructCloudinaryUrl({ - options, - config = {}, - analytics, -}: ConstructUrlProps): string { +export interface ConstructUrlProps< + assetType extends SupportedAssetTypeInput = SupportedAssetTypeInput, +> { + /** + * @description Tech, dependency, and feature identifiers for tracking SDK usage related to Cloudinary. + * @path /url-loader/analyticsoptions + */ + analytics?: AnalyticsOptions | boolean; + /** + * @description Configuration parameters for environment and Cloudinary account. + * @url https://cloudinary.com/documentation/cloudinary_sdks#configuration_parameters + * @path /url-loader/analyticsoptions + */ + config?: ConfigOptions; + // prioritize inferring assetType so available options can be derived from it + options: { assetType?: assetType } & OptionsFor; +} + +export type CldAsset = CloudinaryImage | CloudinaryVideo; + +export function constructCloudinaryUrl< + // only suggest options applicable to the current + // assetType (defaulting to image) + assetType extends SupportedAssetTypeInput = "image", +>({ options, config = {}, analytics }: ConstructUrlProps): string { // If someone is explicitly passing in undefined for analytics via the analytics option, // ensure that the URL Gen SDK option is being passed in as false as well @@ -139,27 +141,14 @@ export function constructCloudinaryUrl({ if (typeof options?.src !== "string") { throw Error( - `Failed to construct Cloudinary URL: Missing source (src) in options.`, + `Failed to construct Cloudinary URL: Missing source (src) in options.` ); } if (!options?.assetType) { - options.assetType = "image"; + options.assetType = "image" as never; } - const propsCheck: Array = []; - - transformationPlugins.forEach(({ props }) => { - const pluginProps = Object.keys(props); - - pluginProps.forEach((prop) => { - if (propsCheck.includes(prop)) { - throw new Error(`Option ${prop} already exists!`); - } - propsCheck.push(prop); - }); - }); - const parsedOptions = {} as Pick; let publicId; @@ -186,74 +175,54 @@ export function constructCloudinaryUrl({ // Take all the parsed URL parts and apply them to the options configuration // if there isn't an existing override - (Object.keys(parsedOptions) as Array).forEach( - (key) => { - if (objectHasKey(options, key)) return; - options[key] = parsedOptions[key]; - }, - ); + entriesOf(parsedOptions).forEach(([key, value]) => { + if (objectHasKey(options, key)) return; + options[key] = value as never; + }); options.version ??= 1; // Begin creating a new Cloudinary image instance and configure - let cldAsset: any = undefined; + const normalizedAssetType = + options.assetType === "image" || options.assetType === "images" + ? "image" + : options.assetType === "video" || options.assetType === "videos" + ? "video" + : throwError(`${options.assetType} is not a valid assetType`); - if (["image", "images"].includes(options.assetType)) { - cldAsset = cld.image(publicId); - } else if (["video", "videos"].includes(options.assetType)) { - cldAsset = cld.video(publicId); - } - - if (typeof cldAsset === "undefined") { - throw new Error("Invalid asset type."); - } + const cldAsset = cld[normalizedAssetType](publicId); const pluginEffects: PluginOptions = {}; transformationPlugins.forEach( - ({ plugin, assetTypes, props, strict }: TransformationPlugin) => { - const supportedAssetType = - options?.assetType !== undefined && - assetTypes.includes(options.assetType as AssetType); - const pluginProps = Object.keys(props); - const optionsKeys = Object.keys(options); - const attemptedUse = - pluginProps - .map((prop) => optionsKeys.includes(prop)) - .filter((isUsed) => !!isUsed).length > 0; - - if (!supportedAssetType) { - if (attemptedUse) { - console.warn( - `One of the following props [${pluginProps.join( - ", ", - )}] was used with an unsupported asset type [${options?.assetType}]`, - ); - } + ({ name, apply, strict, applyWhen, supports }: TransformationPlugin) => { + const shouldApply = + applyWhen === undefined || + (typeof applyWhen === "string" + ? options[applyWhen as never] !== undefined + : applyWhen(options)); + + if (!shouldApply) return; + + if (normalizedAssetType !== supports && supports !== "all") { + console.warn( + `${name} does not support assetType ${normalizedAssetType}` + ); return; } if (options.strictTransformations && !strict) { - if (attemptedUse) { - console.warn( - `One of the following props [${pluginProps.join( - ", ", - )}] was used that is not supported with Strict Transformations.`, - ); - } + console.warn(`${name} does not support Strict Transformations.`); return; } - const results: PluginResults = plugin({ - cldAsset, - options, - }); + const results: PluginResults = apply(cldAsset, options); - const { options: pluginOptions } = results || { options: undefined }; + const pluginOptions = results?.options ?? {}; Object.assign(pluginEffects, pluginOptions); - }, + } ); // We want to perform any resizing at the end of the end of the transformation @@ -314,7 +283,7 @@ export function constructCloudinaryUrl({ } return cldAsset.toURL({ - trackedAnalytics: analytics, + trackedAnalytics: typeof analytics === "object" ? analytics : undefined, }); } @@ -330,7 +299,7 @@ interface SearchAssetRawTransformationsOptions { export function searchAssetRawTransformations( query: string, asset: CloudinaryImage | CloudinaryVideo, - options?: SearchAssetRawTransformationsOptions, + options?: SearchAssetRawTransformationsOptions ) { if (typeof asset.transformation === "undefined") return; @@ -344,7 +313,7 @@ export function searchAssetRawTransformations( .toString() .split("/") .flatMap((seg) => seg.split(",")); - }, + } ); const matches = transformations.filter((transformation) => { @@ -357,3 +326,29 @@ export function searchAssetRawTransformations( return matches.length > 0; } + +type validatePlugins< + remaining extends ReadonlyArray, + validated extends ReadonlyArray = [], + // initialize opts to the BaseAssetOptions so that if any of those keys are duplicated, + // we'll know right away + opts = BaseAssetOptions, +> = remaining extends readonly [ + infer next extends TransformationPlugin, + ...infer rest extends ReadonlyArray, +] + ? validatePlugins< + rest, + [ + ...validated, + keyof opts & keyof next["inferOwnOptions"] extends never + ? // if the intersection is never, no options duplicate existing so the plugin is valid + next + : { + duplicatePropertiesMustBeRemoved: keyof opts & + keyof next["inferOwnOptions"]; + }, + ], + opts & next["inferOwnOptions"] + > + : validated; diff --git a/packages/url-loader/src/lib/plugin.ts b/packages/url-loader/src/lib/plugin.ts new file mode 100644 index 00000000..03987970 --- /dev/null +++ b/packages/url-loader/src/lib/plugin.ts @@ -0,0 +1,72 @@ +import type { AssetOptions, SupportedAssetTypeInput } from "../types/asset.js"; +import type { ImageOptions } from "../types/image.js"; +import type { PluginResults } from "../types/plugins.js"; +import type { VideoOptions } from "../types/video.js"; +import type { CldAsset } from "./cloudinary.js"; + +interface AllOptions extends AssetOptions, ImageOptions, VideoOptions {} + +export type SupportedAssetType = "image" | "video" | "all"; + +export type OptionName = keyof AllOptions; + +export type ApplyWhen = OptionName | ((opts: AllOptions) => boolean); + +export type AlwaysApply = () => true; + +export interface PluginDefinition< + assetType extends SupportedAssetType, + when extends ApplyWhen, + name extends string, + options extends object, +> { + name: name; + supports: assetType; + apply: PluginApplication; + inferOwnOptions: options; + applyWhen?: when | undefined; + strict?: boolean; +} + +export interface TransformationPlugin< + assetType extends SupportedAssetType = SupportedAssetType, + when extends ApplyWhen = ApplyWhen, + name extends string = string, + options extends object = object, +> { + name: name; + supports: assetType; + apply: PluginApplication; + inferOwnOptions: options; + applyWhen?: when | undefined; + strict?: boolean; +} + +export type OptionsFor< + assetType extends SupportedAssetTypeInput, + when extends ApplyWhen = AlwaysApply, + options = assetType extends "all" + ? AllOptions + : assetType extends "video" | "videos" + ? VideoOptions + : ImageOptions, +> = [when] extends [keyof options] + ? // if the plugin applies based on a single key being defined, we know it will be + // present in the options passed to apply + options & { [k in when]: {} } + : options; + +export type PluginApplication< + assetType extends SupportedAssetType, + when extends ApplyWhen = AlwaysApply, +> = (cldAsset: CldAsset, options: OptionsFor) => PluginResults; + +export const plugin = < + asset extends SupportedAssetType, + when extends ApplyWhen, + name extends string, + options extends object, +>( + def: PluginDefinition +): TransformationPlugin => + ({ strict: false, ...def }) as never; diff --git a/packages/url-loader/src/lib/transformations.ts b/packages/url-loader/src/lib/transformations.ts index 8de210ae..c7a928dc 100644 --- a/packages/url-loader/src/lib/transformations.ts +++ b/packages/url-loader/src/lib/transformations.ts @@ -1,4 +1,4 @@ -import type { QualiferConverters } from "../types/qualifiers.js"; +import type { QualifierConverters } from "../types/qualifiers.js"; /** * constructTransformation @@ -6,11 +6,11 @@ import type { QualiferConverters } from "../types/qualifiers.js"; * @param {object} settings: Configuration including prefix, qualifier, and value */ -interface ConstructTransformationSettings { +export interface ConstructTransformationSettings { prefix?: string; qualifier?: string | boolean; value?: string | number | boolean; - converters?: Array; + converters?: ReadonlyArray; } export function constructTransformation({ @@ -52,16 +52,6 @@ export function constructTransformation({ * promptArrayToString */ -export function promptArrayToString(promptArray: Array) { +export function promptArrayToString(promptArray: ReadonlyArray) { return `(${promptArray.join(";")})`; } - -/** - * normalizeNumberParameter - * @TODO: move into util - */ - -export function normalizeNumberParameter(param: number | string | undefined) { - if (typeof param !== "string") return param; - return parseInt(param); -} diff --git a/packages/url-loader/src/lib/upload-widget.ts b/packages/url-loader/src/lib/upload-widget.ts index 73f3b362..d3cc6eae 100644 --- a/packages/url-loader/src/lib/upload-widget.ts +++ b/packages/url-loader/src/lib/upload-widget.ts @@ -1,6 +1,9 @@ -import type { CloudinaryUploadWidgetError, CloudinaryUploadWidgetOptions, CloudinaryUploadWidgetResults } from '@cloudinary-util/types'; - -import type { ConfigOptions } from '../types/config.js'; +import type { + CloudinaryAssetConfiguration, + CloudinaryUploadWidgetError, + CloudinaryUploadWidgetOptions, + CloudinaryUploadWidgetResults, +} from "@cloudinary-util/types"; /** * getUploadWidgetOptions @@ -10,8 +13,11 @@ export interface GetUploadWidgetOptions extends CloudinaryUploadWidgetOptions { uploadSignature?: CloudinaryUploadWidgetOptions["uploadSignature"]; } -export function getUploadWidgetOptions({ uploadSignature, ...options } : GetUploadWidgetOptions, config: ConfigOptions) { - const signed = typeof uploadSignature === 'function'; +export function getUploadWidgetOptions( + { uploadSignature, ...options }: GetUploadWidgetOptions, + config: CloudinaryAssetConfiguration, +) { + const signed = typeof uploadSignature === "function"; // When creating a signed upload, you need to provide both your Cloudinary API Key // as well as a signature generator function that will sign any paramters @@ -21,15 +27,21 @@ export function getUploadWidgetOptions({ uploadSignature, ...options } : GetUplo const { cloudName, apiKey } = config?.cloud || {}; if (!cloudName) { - throw new Error('A Cloudinary Cloud name is required, please make sure your environment variable is set and configured in your environment.'); + throw new Error( + "A Cloudinary Cloud name is required, please make sure your environment variable is set and configured in your environment.", + ); } if (signed && !apiKey) { - throw new Error('A Cloudinary API Key is required for signed requests, please make sure your environment variable is set and configured in your environment.'); + throw new Error( + "A Cloudinary API Key is required for signed requests, please make sure your environment variable is set and configured in your environment.", + ); } - - if ( !signed && !options.uploadPreset ) { - throw new Error('A Cloudinary Upload Preset is required for unsigned uploads. Please specify an uploadPreset or configure signed uploads.'); + + if (!signed && !options.uploadPreset) { + throw new Error( + "A Cloudinary Upload Preset is required for unsigned uploads. Please specify an uploadPreset or configure signed uploads.", + ); } const uploadOptions: CloudinaryUploadWidgetOptions = { @@ -38,20 +50,24 @@ export function getUploadWidgetOptions({ uploadSignature, ...options } : GetUplo ...options, }; - if ( signed ) { + if (signed) { uploadOptions.uploadSignature = uploadSignature; } return uploadOptions; } - /** * generateUploadWidgetResultCallback */ -export type CloudinaryUploadWidgetResultCallback = (results: CloudinaryUploadWidgetResults) => void; -export type CloudinaryUploadWidgetErrorCallback = (error: CloudinaryUploadWidgetError, results: CloudinaryUploadWidgetResults) => void; +export type CloudinaryUploadWidgetResultCallback = ( + results: CloudinaryUploadWidgetResults, +) => void; +export type CloudinaryUploadWidgetErrorCallback = ( + error: CloudinaryUploadWidgetError, + results: CloudinaryUploadWidgetResults, +) => void; export interface GenerateUploadWidgetResultCallback { onOpen?: CloudinaryUploadWidgetResultCallback; @@ -77,38 +93,50 @@ export interface GenerateUploadWidgetResultCallback { } export const UPLOAD_WIDGET_EVENTS: { [key: string]: string } = { - 'abort': 'onAbort', - 'batch-cancelled': 'onBatchCancelled', - 'close': 'onClose', - 'display-changed': 'onDisplayChanged', - 'publicid': 'onPublicId', - 'queues-end': 'onQueuesEnd', - 'queues-start': 'onQueuesStart', - 'retry': 'onRetry', - 'show-completed': 'onShowCompleted', - 'source-changed': 'onSourceChanged', - 'success': 'onSuccess', - 'tags': 'onTags', - 'upload-added': 'onUploadAdded', -} - -export function generateUploadWidgetResultCallback(options: GenerateUploadWidgetResultCallback) { - return function resultCallback(error: CloudinaryUploadWidgetError, uploadResult: CloudinaryUploadWidgetResults) { - if ( error ) { - if ( typeof options.onError === 'function' ) { + abort: "onAbort", + "batch-cancelled": "onBatchCancelled", + close: "onClose", + "display-changed": "onDisplayChanged", + publicid: "onPublicId", + "queues-end": "onQueuesEnd", + "queues-start": "onQueuesStart", + retry: "onRetry", + "show-completed": "onShowCompleted", + "source-changed": "onSourceChanged", + success: "onSuccess", + tags: "onTags", + "upload-added": "onUploadAdded", +}; + +export function generateUploadWidgetResultCallback( + options: GenerateUploadWidgetResultCallback, +) { + return function resultCallback( + error: CloudinaryUploadWidgetError, + uploadResult: CloudinaryUploadWidgetResults, + ) { + if (error) { + if (typeof options.onError === "function") { options.onError(error, uploadResult); } } - if ( typeof options.onResult === 'function' ) { + if (typeof options.onResult === "function") { options.onResult(uploadResult); } - const widgetEvent = typeof uploadResult?.event === 'string' && UPLOAD_WIDGET_EVENTS[uploadResult.event] as keyof typeof options; - - if ( typeof widgetEvent === 'string' && typeof options[widgetEvent] === 'function' ) { - const callback = options[widgetEvent] as CloudinaryUploadWidgetResultCallback; + const widgetEvent = + typeof uploadResult?.event === "string" && + (UPLOAD_WIDGET_EVENTS[uploadResult.event] as keyof typeof options); + + if ( + typeof widgetEvent === "string" && + typeof options[widgetEvent] === "function" + ) { + const callback = options[ + widgetEvent + ] as CloudinaryUploadWidgetResultCallback; callback(uploadResult); } - } -} \ No newline at end of file + }; +} diff --git a/packages/url-loader/src/lib/upload.ts b/packages/url-loader/src/lib/upload.ts index 4840a878..7c05fc8c 100644 --- a/packages/url-loader/src/lib/upload.ts +++ b/packages/url-loader/src/lib/upload.ts @@ -1,5 +1,3 @@ -import type { CloudinaryUploadWidgetOptions } from '@cloudinary-util/types'; - /** * generateSignature * @description Makes a request to an endpoint to sign Cloudinary parameters as part of widget creation @@ -10,24 +8,32 @@ export interface GenerateSignatureCallback { signatureEndpoint: string; } -export function generateSignatureCallback({ signatureEndpoint, fetch: fetcher }: GenerateSignatureCallback): CloudinaryUploadWidgetOptions["uploadSignature"] { - return function generateSignature(callback: (signature: string | null, error?: unknown) => void, paramsToSign: object) { - if ( typeof signatureEndpoint === 'undefined' ) { - throw Error('Failed to generate signature: signatureEndpoint property undefined.') +export function generateSignatureCallback({ + signatureEndpoint, + fetch: fetcher, +}: GenerateSignatureCallback) { + return function generateSignature( + callback: (signature: string | null, error?: unknown) => void, + paramsToSign: object + ) { + if (typeof signatureEndpoint === "undefined") { + throw Error( + "Failed to generate signature: signatureEndpoint property undefined." + ); } - - if ( typeof fetcher === 'undefined' ) { - throw Error('Failed to generate signature: fetch property undefined.') + + if (typeof fetcher === "undefined") { + throw Error("Failed to generate signature: fetch property undefined."); } fetcher(signatureEndpoint, { - method: 'POST', + method: "POST", body: JSON.stringify({ paramsToSign, }), headers: { - 'Content-Type': 'application/json' - } + "Content-Type": "application/json", + }, }) .then((response: { json: Function }) => response.json()) .then((result: { signature: string }) => { @@ -35,6 +41,6 @@ export function generateSignatureCallback({ signatureEndpoint, fetch: fetcher }: }) .catch((error: unknown) => { callback(null, error); - }) - } -} \ No newline at end of file + }); + }; +} diff --git a/packages/url-loader/src/lib/utils.ts b/packages/url-loader/src/lib/utils.ts new file mode 100644 index 00000000..106f75ca --- /dev/null +++ b/packages/url-loader/src/lib/utils.ts @@ -0,0 +1,44 @@ +/** Safer alternative to Array.isArray that... + * - doesn't narrow to any[] + * - works with readonly arrays + */ +export const isArray: (data: unknown) => data is ReadonlyArray = + Array.isArray; + +/** + * extracts entries mimicking Object.entries, accounting for whether the + * object is an array + */ +export type entryOf = { + [k in keyof o]-?: [k, o[k] & ({} | null)]; +}[o extends ReadonlyArray ? keyof o & number : keyof o] & + unknown; + +/** + * Object.entries wrapper providing narrowed types for objects with known sets + * of keys, e.g. those defined internally as configs + * + * @param o the object to get narrowed entries from + * @returns a narrowed array of entries based on that object's type + */ +export const entriesOf: (o: o) => entryOf[] = + Object.entries as never; + +/** + * Throws an error with the specified message and constructor. + * + * @param {string} message - The error message. + * @param {new (message: string) => Error} [ctor=Error] - The error constructor. Defaults to the built-in Error constructor. + * @throws {Error} Throws an error with the specified message. + */ +export const throwError: ( + message: string, + ctor?: new (message: string) => Error +) => never = (message, ctor = Error) => { + throw new ctor(message); +}; + +/** + * @description A primative value that can be interpolated into a string + */ +export type StringifiablePrimative = string | number | bigint | boolean; diff --git a/packages/url-loader/src/lib/video-player.ts b/packages/url-loader/src/lib/video-player.ts index 32e6f1c3..a95c8d30 100644 --- a/packages/url-loader/src/lib/video-player.ts +++ b/packages/url-loader/src/lib/video-player.ts @@ -1,14 +1,14 @@ import type { + CloudinaryAssetConfiguration, CloudinaryVideoPlayerOptions, CloudinaryVideoPlayerOptionsLogo, } from "@cloudinary-util/types"; import { parseUrl } from "@cloudinary-util/util"; - -import type { ConfigOptions } from "../types/config.js"; import { constructCloudinaryUrl, type ConstructUrlProps, } from "./cloudinary.js"; +import { isArray } from "./utils.js"; /** * getVideoPlayerOptions @@ -25,7 +25,7 @@ export type GetVideoPlayerOptions = Omit< | "logoOnclickUrl" > & { logo?: boolean | GetVideoPlayerOptionsLogo; - poster?: string | ConstructUrlProps["options"]; + poster?: string | Partial; src: string; quality?: string | number; }; @@ -38,7 +38,7 @@ export interface GetVideoPlayerOptionsLogo { export function getVideoPlayerOptions( options: GetVideoPlayerOptions, - config: ConfigOptions + config: CloudinaryAssetConfiguration ) { const { autoplay, @@ -89,21 +89,17 @@ export function getVideoPlayerOptions( ); } - // Normalize player transformations as an array - - const playerTransformations = Array.isArray(transformation) - ? transformation - : [transformation]; - // We want to apply a quality transformation which defaults // to auto, but we want it to be in the beginning of the // transformations array, in the event someone // has already passed some in, giving them the opportunity // to override if desired - playerTransformations.unshift({ - quality, - }); + const playerTransformations = [ + { quality }, + // Normalize player transformations as an array + ...(isArray(transformation) ? transformation : [transformation]), + ]; // Provide an object configuration option for player logos @@ -163,7 +159,11 @@ export function getVideoPlayerOptions( ...otherCldVidPlayerOptions, }; - if ( playerOptions.width && playerOptions.height && !playerOptions.aspectRatio ) { + if ( + playerOptions.width && + playerOptions.height && + !playerOptions.aspectRatio + ) { playerOptions.aspectRatio = `${playerOptions.width}:${playerOptions.height}`; } @@ -184,10 +184,10 @@ export function getVideoPlayerOptions( playerOptions.posterOptions = { publicId: constructCloudinaryUrl({ options: { - ...poster, src: publicId, assetType: "video", format: "auto:image", + ...poster, }, config, }), @@ -195,7 +195,10 @@ export function getVideoPlayerOptions( } else { playerOptions.posterOptions = { publicId: constructCloudinaryUrl({ - options: poster, + options: { + src: publicId, + ...poster, + }, config, }), }; diff --git a/packages/url-loader/src/plugins/abr.ts b/packages/url-loader/src/plugins/abr.ts index 157967ee..ceb07551 100644 --- a/packages/url-loader/src/plugins/abr.ts +++ b/packages/url-loader/src/plugins/abr.ts @@ -1,30 +1,24 @@ -import { z } from "zod"; -import type { TransformationPlugin } from "../types/plugins.js"; -import type { VideoOptions } from "../types/video.js"; +import { plugin } from "../lib/plugin.js"; -export const abrProps = { - streamingProfile: z - .string() - .describe( - JSON.stringify({ - text: "The streaming profile to apply when delivering a video using adaptive bitrate streaming.", - url: "https://cloudinary.com/documentation/transformation_reference#sp_streaming_profile", - }) - ) - .optional(), -}; +export declare namespace AbrPlugin { + export interface Options { + /** + * @description The streaming profile to apply when delivering a video using adaptive bitrate streaming. + * @url https://cloudinary.com/documentation/transformation_reference#sp_streaming_profile + */ + streamingProfile?: string; + } +} -export const abrPlugin = { - props: abrProps, - assetTypes: ["video", "videos"], - plugin: (settings) => { - const { cldAsset, options } = settings; - const { streamingProfile } = options; - - if (typeof streamingProfile === "string") { - cldAsset.addTransformation(`sp_${streamingProfile}`); +export const AbrPlugin = plugin({ + name: "Abr", + supports: "video", + inferOwnOptions: {} as AbrPlugin.Options, + apply: (asset, opts) => { + if (typeof opts.streamingProfile === "string") { + asset.addTransformation(`sp_${opts.streamingProfile}`); } return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/cropping.ts b/packages/url-loader/src/plugins/cropping.ts index e155d958..988c5b91 100644 --- a/packages/url-loader/src/plugins/cropping.ts +++ b/packages/url-loader/src/plugins/cropping.ts @@ -1,7 +1,17 @@ -import { z } from "zod"; -import * as parameters from "../constants/parameters.js"; -import { normalizeNumberParameter } from "../lib/transformations.js"; -import type { PluginResults, TransformationPlugin } from "../types/plugins.js"; +import { normalizeNumberParameter } from "@cloudinary-util/util"; +import type { + AspectRatio, + CropMode, + Gravity, + Height, + Width, + X, + Y, + Zoom, +} from "../constants/parameters.js"; +import { plugin } from "../lib/plugin.js"; +import { isArray } from "../lib/utils.js"; +import type { PluginResults } from "../types/plugins.js"; const cropsAspectRatio = ["auto", "crop", "fill", "lfill", "fill_pad", "thumb"]; const cropsGravityAuto = ["auto", "crop", "fill", "lfill", "fill_pad", "thumb"]; @@ -9,68 +19,55 @@ const cropsWithZoom = ["crop", "thumb"]; const DEFAULT_CROP = "limit"; -const cropOptionsSchema = z.object({ - aspectRatio: parameters.aspectRatio.schema.optional(), - type: parameters.crop.schema, - gravity: parameters.gravity.schema.optional(), - height: parameters.height.schema.optional(), - width: parameters.width.schema.optional(), - x: parameters.x.schema.optional(), - y: parameters.y.schema.optional(), - zoom: parameters.zoom.schema.optional(), - source: z.boolean().optional(), -}); +export declare namespace CroppingPlugin { + export interface Options { + aspectRatio?: AspectRatio; + crop?: CropMode | NestedOptions | ReadonlyArray; + gravity?: Gravity; + zoom?: Zoom; + } + + export interface NestedOptions { + type: CropMode; + aspectRatio?: AspectRatio; + gravity?: Gravity; + height?: Height; + width?: Width; + x?: X; + y?: Y; + zoom?: Zoom; + source?: boolean; + } +} -type CropOptions = z.infer; - -export const croppingProps = { - aspectRatio: parameters.aspectRatio.schema.optional(), - crop: z - .union([ - parameters.crop.schema, - cropOptionsSchema, - z.array(cropOptionsSchema), - ]) - .default(DEFAULT_CROP) - .optional(), - gravity: parameters.gravity.schema.optional(), - zoom: parameters.zoom.schema.optional(), -}; - -export const croppingPlugin = { - props: croppingProps, - assetTypes: ["image", "images", "video", "videos"], - plugin: (settings) => { - const { cldAsset, options } = settings; - - let crops: Array = []; +export const CroppingPlugin = plugin({ + name: "Cropping", + supports: "all", + inferOwnOptions: {} as CroppingPlugin.Options, + // crop is applied even if the crop key is undefined + apply: (asset, opts) => { + let crops: Array = []; // Normalize the data that we're working with for simpler processing - if ( - typeof options.crop === "string" || - typeof options.crop === "undefined" - ) { + if (typeof opts.crop === "string" || typeof opts.crop === "undefined") { // If we have a type of string or we don't explicitly // have a crop set (default is limit) we're using the // default pattern of resizing/cropping after all // of the transformations crops.push({ - aspectRatio: options.aspectRatio, - height: options.height, - gravity: options.gravity, - type: options.crop || DEFAULT_CROP, - width: options.width, - zoom: options.zoom, + aspectRatio: opts.aspectRatio, + height: opts.height, + gravity: opts.gravity, + type: opts.crop || DEFAULT_CROP, + width: opts.width, + zoom: opts.zoom, }); - } else if ( - typeof options.crop === "object" && - !Array.isArray(options.crop) - ) { - crops.push(options.crop); - } else if (Array.isArray(options.crop)) { - crops = options.crop; + } else if (typeof opts.crop === "object" && !isArray(opts.crop)) { + crops.push(opts.crop); + } else if (isArray(opts.crop)) { + crops = [...opts.crop]; } // We always need a post-transformation to resize the image, whether that uses the @@ -79,12 +76,12 @@ export const croppingPlugin = { if (crops.length === 1 && crops[0].source === true) { crops.push({ - aspectRatio: options.aspectRatio, - width: options.width, - height: options.height, - gravity: options.gravity, + aspectRatio: opts.aspectRatio, + width: opts.width, + height: opts.height, + gravity: opts.gravity, type: DEFAULT_CROP, - zoom: options.zoom, + zoom: opts.zoom, }); } @@ -104,13 +101,13 @@ export const croppingPlugin = { typeof cropDimensions.width === "undefined" && typeof crop.aspectRatio === "undefined" ) { - cropDimensions.width = options.width; + cropDimensions.width = opts.width; // We likely don't want to infer one dimension and not the other // so only infer the height if we're already inferring the width if (typeof cropDimensions.height === "undefined") { - cropDimensions.height = options.height; + cropDimensions.height = opts.height; } } @@ -142,7 +139,7 @@ export const croppingPlugin = { sourceTransformations.forEach((transformation) => { if (transformation.length > 0) { - cldAsset.addTransformation(transformation.join(",")); + asset.addTransformation(transformation.join(",")); } }); @@ -160,14 +157,14 @@ export const croppingPlugin = { return results; }, -} satisfies TransformationPlugin; +}); /** * CollectTransformations * @description Given the avialable crop options, returns an array of transformation strings */ -function collectTransformations(collectOptions: CropOptions) { +function collectTransformations(collectOptions: CroppingPlugin.NestedOptions) { // Default the crop to "limit" to avoid upscaling // This avoid further distorting the image since the browser will resize in that case. // If caller wants actual resize, can explicitly pass in "scale". @@ -183,14 +180,17 @@ function collectTransformations(collectOptions: CropOptions) { const hasDefinedDimensions = height || width; const hasValidAspectRatio = aspectRatio && cropsAspectRatio.includes(crop); - const hasXCoordinate = typeof x === 'number' || typeof x === 'string'; - const hasYCoordinate = typeof y === 'number' || typeof y === 'string'; + const hasXCoordinate = typeof x === "number" || typeof x === "string"; + const hasYCoordinate = typeof y === "number" || typeof y === "string"; const hasDefinedCoordinates = hasXCoordinate || hasYCoordinate; // Only apply a crop if we're defining some type of dimension attribute // where the crop would make sense - if (crop && (hasDefinedDimensions || hasValidAspectRatio || hasDefinedCoordinates)) { + if ( + crop && + (hasDefinedDimensions || hasValidAspectRatio || hasDefinedCoordinates) + ) { transformations.push(`c_${crop}`); } @@ -212,11 +212,11 @@ function collectTransformations(collectOptions: CropOptions) { transformations.push(`h_${height}`); } - if ( hasXCoordinate ) { + if (hasXCoordinate) { transformations.push(`x_${x}`); } - if ( hasYCoordinate ) { + if (hasYCoordinate) { transformations.push(`y_${y}`); } @@ -225,7 +225,7 @@ function collectTransformations(collectOptions: CropOptions) { // If the user is providing x or y coordinates, we also don't want // to default to auto, as that will skew the intuitive results - if (!gravity && cropsGravityAuto.includes(crop) && !hasDefinedCoordinates ) { + if (!gravity && cropsGravityAuto.includes(crop) && !hasDefinedCoordinates) { gravity = "auto"; } diff --git a/packages/url-loader/src/plugins/default-image.ts b/packages/url-loader/src/plugins/default-image.ts index 84459726..3f364a93 100644 --- a/packages/url-loader/src/plugins/default-image.ts +++ b/packages/url-loader/src/plugins/default-image.ts @@ -1,38 +1,33 @@ -import { z } from "zod"; - import { getFormat } from "@cloudinary-util/util"; -import type { ImageOptions } from "../types/image.js"; -import type { TransformationPlugin } from "../types/plugins.js"; +import { plugin } from "../lib/plugin.js"; -export const defaultImageProps = { - defaultImage: z - .string() - .describe( - JSON.stringify({ - text: "Configures the default image to use in case the given public ID is not available. Must include file extension.", - url: "https://cloudinary.com/documentation/transformation_reference#d_default_image", - }), - ) - .optional(), -}; +export declare namespace DefaultImagePlugin { + export interface Options { + /** + * @description Configures the default image to use in case the given public ID is not available. Must include file extension. + * @url https://cloudinary.com/documentation/transformation_reference#d_default_image + */ + defaultImage?: string; + } +} -export const defaultImagePlugin = { - props: defaultImageProps, - assetTypes: ["image", "images"], - plugin: (settings) => { - const { cldAsset, options } = settings; - const { defaultImage } = options; +export const DefaultImagePlugin = plugin({ + name: "DefaultImage", + supports: "image", + inferOwnOptions: {} as DefaultImagePlugin.Options, + apply: (asset, opts) => { + const { defaultImage } = opts; if (typeof defaultImage === "string") { if (!getFormat(defaultImage)) { console.warn( - `The defaultImage prop may be missing a format and must include it along with the public ID. (Ex: myimage.jpg)`, + `The defaultImage prop may be missing a format and must include it along with the public ID. (Ex: myimage.jpg)` ); } const defaultImageId = defaultImage.replace(/\//g, ":"); - cldAsset.addTransformation(`d_${defaultImageId}`); + asset.addTransformation(`d_${defaultImageId}`); } return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/effects.ts b/packages/url-loader/src/plugins/effects.ts index 8adaf0ef..7ff81901 100644 --- a/packages/url-loader/src/plugins/effects.ts +++ b/packages/url-loader/src/plugins/effects.ts @@ -1,78 +1,27 @@ -import { z } from "zod"; -import type { TransformationPlugin } from "../types/plugins.js"; -import { effects as qualifiersEffects } from "../constants/qualifiers.js"; +import { + effects as qualifiersEffects, + type QualifierOptions, +} from "../constants/qualifiers.js"; +import { plugin } from "../lib/plugin.js"; import { constructTransformation } from "../lib/transformations.js"; +import { isArray } from "../lib/utils.js"; -const effectProps = { - angle: qualifiersEffects.angle.schema.optional(), - art: qualifiersEffects.art.schema.optional(), - autoBrightness: qualifiersEffects.autoBrightness.schema.optional(), - autoColor: qualifiersEffects.autoColor.schema.optional(), - autoContrast: qualifiersEffects.autoContrast.schema.optional(), - assistColorblind: qualifiersEffects.assistColorblind.schema.optional(), - background: qualifiersEffects.background.schema.optional(), - blackwhite: qualifiersEffects.blackwhite.schema.optional(), - blur: qualifiersEffects.blur.schema.optional(), - blurFaces: qualifiersEffects.blurFaces.schema.optional(), - blurRegion: qualifiersEffects.blurRegion.schema.optional(), - border: qualifiersEffects.border.schema.optional(), - brightness: qualifiersEffects.brightness.schema.optional(), - brightnessHSB: qualifiersEffects.brightnessHSB.schema.optional(), - cartoonify: qualifiersEffects.cartoonify.schema.optional(), - color: qualifiersEffects.color.schema.optional(), - colorize: qualifiersEffects.colorize.schema.optional(), - contrast: qualifiersEffects.contrast.schema.optional(), - distort: qualifiersEffects.distort.schema.optional(), - fillLight: qualifiersEffects.fillLight.schema.optional(), - gamma: qualifiersEffects.gamma.schema.optional(), - gradientFade: qualifiersEffects.gradientFade.schema.optional(), - grayscale: qualifiersEffects.grayscale.schema.optional(), - improve: qualifiersEffects.improve.schema.optional(), - loop: qualifiersEffects.loop.schema.optional(), - multiply: qualifiersEffects.multiply.schema.optional(), - negate: qualifiersEffects.negate.schema.optional(), - oilPaint: qualifiersEffects.oilPaint.schema.optional(), - opacity: qualifiersEffects.opacity.schema.optional(), - outline: qualifiersEffects.outline.schema.optional(), - pixelate: qualifiersEffects.pixelate.schema.optional(), - pixelateFaces: qualifiersEffects.pixelateFaces.schema.optional(), - pixelateRegion: qualifiersEffects.pixelateRegion.schema.optional(), - radius: qualifiersEffects.radius.schema.optional(), - redeye: qualifiersEffects.redeye.schema.optional(), - replaceColor: qualifiersEffects.replaceColor.schema.optional(), - saturation: qualifiersEffects.saturation.schema.optional(), - screen: qualifiersEffects.screen.schema.optional(), - sepia: qualifiersEffects.sepia.schema.optional(), - shadow: qualifiersEffects.shadow.schema.optional(), - sharpen: qualifiersEffects.sharpen.schema.optional(), - shear: qualifiersEffects.shear.schema.optional(), - simulateColorblind: qualifiersEffects.simulateColorblind.schema.optional(), - tint: qualifiersEffects.tint.schema.optional(), - trim: qualifiersEffects.trim.schema.optional(), - unsharpMask: qualifiersEffects.unsharpMask.schema.optional(), - vectorize: qualifiersEffects.vectorize.schema.optional(), - vibrance: qualifiersEffects.vibrance.schema.optional(), - vignette: qualifiersEffects.vignette.schema.optional(), -}; +export declare namespace EffectsPlugin { + export interface NestableOptions extends QualifierOptions {} -export const effectsProps = { - effects: z - .array(z.object(effectProps)) - .describe( - JSON.stringify({ - text: "Array of objects specifying transformations to be applied to asset.", - }), - ) - .optional(), - ...effectProps, -}; - -export const effectsPlugin = { - props: effectsProps, - assetTypes: ["image", "images", "video", "videos"], - plugin: (settings) => { - const { cldAsset, options } = settings; + export interface Options extends NestableOptions { + /** + * @description Array of objects specifying transformations to be applied to asset. + */ + effects?: ReadonlyArray; + } +} +export const EffectsPlugin = plugin({ + name: "Effects", + supports: "all", + inferOwnOptions: {} as EffectsPlugin.Options, + apply: (cldAsset, options) => { // Handle any top-level effect props const transformationStrings = constructTransformationString({ @@ -80,14 +29,16 @@ export const effectsPlugin = { options, }); - transformationStrings - .filter((t) => !!t) - .forEach((transformation) => cldAsset.effect(transformation)); + transformationStrings.forEach((transformation) => { + if (transformation) { + cldAsset.addTransformation(transformation); + } + }); // If we're passing in an effects prop explicitly, treat it as an array of // effects that we need to process - if (Array.isArray(options?.effects)) { + if (isArray(options?.effects)) { options?.effects.forEach((effectsSet) => { const transformationString = constructTransformationString({ effects: qualifiersEffects, @@ -95,7 +46,7 @@ export const effectsPlugin = { }) .filter((t) => !!t) .join(","); - cldAsset.effect(transformationString); + cldAsset.addTransformation(transformationString); }); } @@ -117,10 +68,10 @@ export const effectsPlugin = { value: options?.[key], converters, }); - }, + } ); } return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/enhance.ts b/packages/url-loader/src/plugins/enhance.ts index 683d543e..1a959542 100644 --- a/packages/url-loader/src/plugins/enhance.ts +++ b/packages/url-loader/src/plugins/enhance.ts @@ -1,30 +1,24 @@ -import { z } from "zod"; -import type { ImageOptions } from "../types/image.js"; -import type { TransformationPlugin } from "../types/plugins.js"; +import { plugin } from "../lib/plugin.js"; -export const enhanceProps = { - enhance: z - .boolean() - .describe( - JSON.stringify({ - text: "Uses AI to analyze an image and make adjustments to enhance the appeal of the image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_enhance", - }), - ) - .optional(), -}; +export declare namespace EnhancePlugin { + export interface Options { + /** + * @description Uses AI to analyze an image and make adjustments to enhance the appeal of the image. + * @url https://cloudinary.com/documentation/transformation_reference#e_enhance + */ + enhance?: boolean; + } +} -export const enhancePlugin = { - props: enhanceProps, - assetTypes: ["image", "images"], - plugin: (settings) => { - const { cldAsset, options } = settings; - const { enhance = false } = options; - - if (enhance) { - cldAsset.effect("e_enhance"); +export const EnhancePlugin = plugin({ + name: "Enhance", + supports: "image", + inferOwnOptions: {} as EnhancePlugin.Options, + apply: (cldAsset, options) => { + if (options.enhance) { + cldAsset.addTransformation("e_enhance"); } return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/extract.ts b/packages/url-loader/src/plugins/extract.ts index d2df365e..3f319322 100644 --- a/packages/url-loader/src/plugins/extract.ts +++ b/packages/url-loader/src/plugins/extract.ts @@ -1,83 +1,79 @@ -import { z } from "zod"; -import { extractMode, multiple, prompt } from '../constants/parameters.js'; -import type { ImageOptions } from "../types/image.js"; -import type { TransformationPlugin } from "../types/plugins.js"; +import type { + ExtractMode, + ListablePrompts, + Multiple, +} from "../constants/parameters.js"; +import { plugin } from "../lib/plugin.js"; +import { isArray } from "../lib/utils.js"; -export const extractProps = { - extract: z - .union([ - prompt.schema.optional(), - z.array(prompt.schema).optional(), - z.object({ - invert: z.boolean().default(false).optional(), - mode: extractMode.schema.optional(), - multiple: multiple.schema.default(false).optional(), - prompt: z.union([prompt.schema, z.array(prompt.schema)]).optional(), - }), - ]) - .describe( - JSON.stringify({ - text: "Extracts an area or multiple areas of an image, described in natural language.", - url: "https://cloudinary.com/documentation/transformation_reference#e_extract", - }) - ) - .optional(), -}; - -export const extractPlugin = { - props: extractProps, - assetTypes: ["image", "images"], - plugin: (settings) => { - const { cldAsset, options } = settings; - const { extract } = options; +export declare namespace ExtractPlugin { + export interface Options { + /** + * @description Extracts an area or multiple areas of an image, described in natural language. + * @url https://cloudinary.com/documentation/transformation_reference#e_extract + */ + extract?: ListablePrompts | NestedOptions; + } - if (!extract || typeof extract === "undefined") return {}; + export interface NestedOptions { + prompt?: ListablePrompts; + invert?: boolean; + mode?: ExtractMode; + multiple?: Multiple; + } +} +export const ExtractPlugin = plugin({ + name: "Extract", + supports: "image", + applyWhen: "extract", + inferOwnOptions: {} as ExtractPlugin.Options, + apply: (cldAsset, { extract }) => { const properties = []; - if ( typeof extract === 'string' ) { + if (typeof extract === "string") { properties.push(`prompt_${extract}`); - } else if ( Array.isArray(extract) ) { + } else if (isArray(extract)) { properties.push(`prompt_${formatPrompts(extract)}`); - } else if ( typeof extract === 'object' && !Array.isArray(extract) ) { + } else { const prompt = formatPrompts(extract.prompt); - if ( prompt ) { + if (prompt) { properties.push(`prompt_${prompt}`); } - if ( extract.invert === true ) { - properties.push('invert_true'); + if (extract.invert === true) { + properties.push("invert_true"); } - if ( typeof extract.mode === 'string' ) { + if (typeof extract.mode === "string") { properties.push(`mode_${extract.mode}`); } - if ( extract.multiple === true ) { - properties.push('multiple_true'); + if (extract.multiple === true) { + properties.push("multiple_true"); } } - if ( properties.length > 0 ) { - const transformation = `e_extract:${properties.join(';')}`; + if (properties.length > 0) { + const transformation = `e_extract:${properties.join(";")}`; cldAsset.addTransformation(transformation); } return {}; }, -} satisfies TransformationPlugin; +}); /** * formatPrompts */ -function formatPrompts(prompt: string | Array | undefined) { - if ( typeof prompt === 'string' ) return prompt; +function formatPrompts(prompts: ListablePrompts | undefined) { + if (typeof prompts === "string") return prompts; - if ( Array.isArray(prompt) ) { - return `(${prompt.filter(prompt => typeof prompt === 'string').join(';')})`; + if (isArray(prompts)) { + return `(${prompts.filter((prompt) => typeof prompt === "string").join(";")})`; } return undefined; -} \ No newline at end of file +} diff --git a/packages/url-loader/src/plugins/fill-background.ts b/packages/url-loader/src/plugins/fill-background.ts index 4fc47982..14756580 100644 --- a/packages/url-loader/src/plugins/fill-background.ts +++ b/packages/url-loader/src/plugins/fill-background.ts @@ -1,35 +1,34 @@ -import { z } from "zod"; -import { crop, gravity } from "../constants/parameters.js"; -import { normalizeNumberParameter } from "../lib/transformations.js"; -import type { ImageOptions } from "../types/image.js"; -import type { TransformationPlugin } from "../types/plugins.js"; +import { normalizeNumberParameter } from "@cloudinary-util/util"; +import type { + CropMode, + Gravity, + ListablePrompts, +} from "../constants/parameters.js"; +import { plugin } from "../lib/plugin.js"; const defaultCrop = "pad"; -export const fillBackgroundProps = { - fillBackground: z - .union([ - z.boolean(), - z.object({ - crop: crop.schema.optional(), - gravity: gravity.schema.optional(), - prompt: z.string().optional(), - }), - ]) - .describe( - JSON.stringify({ - text: "Uses Generative Fill to extended padded image with AI", - url: "https://cloudinary.com/documentation/transformation_reference#b_gen_fill", - }) - ) - .optional(), -}; +export declare namespace FillBackgroundPlugin { + export interface Options { + /** + * @description Uses Generative Fill to extended padded image with AI + * @url https://cloudinary.com/documentation/transformation_reference#b_gen_fill + */ + fillBackground?: boolean | NestedOptions; + } -export const fillBackgroundPlugin = { - props: fillBackgroundProps, - assetTypes: ["image", "images"], - plugin: (settings) => { - const { cldAsset, options } = settings; + export interface NestedOptions { + crop?: CropMode; + gravity?: Gravity; + prompt?: ListablePrompts; + } +} + +export const FillBackgroundPlugin = plugin({ + name: "FillBackground", + supports: "image", + inferOwnOptions: {} as FillBackgroundPlugin.Options, + apply: (cldAsset, options) => { const { fillBackground } = options; if (typeof fillBackground === "undefined") return {}; @@ -81,4 +80,4 @@ export const fillBackgroundPlugin = { return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/flags.ts b/packages/url-loader/src/plugins/flags.ts index 3c670d6f..62abb49e 100644 --- a/packages/url-loader/src/plugins/flags.ts +++ b/packages/url-loader/src/plugins/flags.ts @@ -1,50 +1,32 @@ -import * as parameters from "../constants/parameters.js"; - -import type { TransformationPlugin } from "../types/plugins.js"; - -const { flagsEnum } = parameters; - -export const flagsProps = { - flags: parameters.flags.schema.optional(), -}; - -export const flagsPlugin = { - props: flagsProps, - assetTypes: ["image", "images", "video", "videos"], - plugin: (settings) => { - const { cldAsset, options } = settings; - const { flags = [] } = options; - +import type { FlagsDefinition } from "../constants/parameters.js"; +import { plugin } from "../lib/plugin.js"; +import { isArray } from "../lib/utils.js"; + +export declare namespace FlagsPlugin { + export interface Options { + flags?: FlagsDefinition; + } +} + +export const FlagsPlugin = plugin({ + name: "Flags", + supports: "all", + applyWhen: "flags", + inferOwnOptions: {} as FlagsPlugin.Options, + apply: (cldAsset, { flags }) => { // First iteration of adding flags follows the same pattern // as the top level option from Cloudinary URL Gen SDK where // each flag is individually added as its own segment via // the addFlag method. Flags can have additional context and // may warrant case-by-case applications - if (Array.isArray(flags) && flags.length > 0) { - flags.forEach((flag) => { - const { success } = flagsEnum.safeParse(flag); - - if (!success) { - if (process.env.NODE_ENV === "development") { - console.warn(`Invalid flag ${flag}, not applying.`); - } - return; - } - - cldAsset.addFlag(flag); - }); + if (typeof flags === "string") { + flags = [flags]; + } + if (isArray(flags)) { + flags.forEach((flag) => cldAsset.addFlag(flag)); } else if (typeof flags === "object") { Object.entries(flags).forEach(([qualifier, value]) => { - const { success } = flagsEnum.safeParse(qualifier); - - if (!success) { - if (process.env.NODE_ENV === "development") { - console.warn(`Invalid flag ${qualifier}, not applying.`); - } - return; - } - // The addFlag method encodes some characters, specifically // the "." character which breaks some use cases like // du_2.5 @@ -54,4 +36,4 @@ export const flagsPlugin = { return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/named-transformations.ts b/packages/url-loader/src/plugins/named-transformations.ts index f4021500..0e2ad8dc 100644 --- a/packages/url-loader/src/plugins/named-transformations.ts +++ b/packages/url-loader/src/plugins/named-transformations.ts @@ -1,38 +1,28 @@ -import { z } from "zod"; -import type { TransformationPlugin } from "../types/plugins.js"; - -const NamedTransformationSchema = z.string(); -type NamedTransformation = z.infer; - -export const namedTransformationsProps = { - namedTransformations: z - .union([NamedTransformationSchema, z.array(NamedTransformationSchema)]) - .describe( - JSON.stringify({ - text: "Named transformations to apply to asset.", - url: "https://cloudinary.com/documentation/image_transformations#named_transformations", - }) - ) - .optional(), - /** - * @deprecated use {@link `namedTransformations`} instead - */ - transformations: z - .union([NamedTransformationSchema, z.array(NamedTransformationSchema)]) - .describe( - JSON.stringify({ - text: "Deprecated: use namedTransformations instead", - url: "https://cloudinary.com/documentation/image_transformations#named_transformations", - }) - ) - .optional(), -}; - -export const namedTransformationsPlugin = { - props: namedTransformationsProps, +import { plugin } from "../lib/plugin.js"; +import { isArray } from "../lib/utils.js"; + +export declare namespace NamedTransformationsPlugin { + export interface Options { + /** + * @description Named transformations to apply to asset. + * @url https://cloudinary.com/documentation/image_transformations#named_transformations + */ + namedTransformations?: string | ReadonlyArray; + /** + * @deprecated use {@link `namedTransformations`} instead + * @description: Deprecated: use namedTransformations instead + * @url https://cloudinary.com/documentation/image_transformations#named_transformations + */ + transformations?: string | ReadonlyArray; + } +} + +export const NamedTransformationsPlugin = plugin({ + name: "NamedTransformations", strict: true, - assetTypes: ["image", "images", "video", "videos"], - plugin: ({ cldAsset, options }) => { + supports: "all", + inferOwnOptions: {} as NamedTransformationsPlugin.Options, + apply: (cldAsset, options) => { const { transformations, namedTransformations } = options; if (transformations && process.env.NODE_ENVIRONMENT === "development") { @@ -43,14 +33,14 @@ export const namedTransformationsPlugin = { let _namedTransformations = namedTransformations || transformations || []; - if (!Array.isArray(_namedTransformations)) { + if (!isArray(_namedTransformations)) { _namedTransformations = [_namedTransformations]; } - _namedTransformations.forEach((transformation: NamedTransformation) => { + _namedTransformations.forEach((transformation: string) => { cldAsset.addTransformation(`t_${transformation}`); }); return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/overlays.ts b/packages/url-loader/src/plugins/overlays.ts index 729f108d..2fdbc817 100644 --- a/packages/url-loader/src/plugins/overlays.ts +++ b/packages/url-loader/src/plugins/overlays.ts @@ -1,15 +1,10 @@ import { encodeBase64, objectHasKey, sortByKey } from "@cloudinary-util/util"; -import { z } from "zod"; -import { - angle, - crop, - flags, - flagsEnum, - gravity, - height, - width, - x, - y, +import type { + CropMode, + Height, + ListableFlags, + PositionalOptions, + Width, } from "../constants/parameters.js"; import { effects as qualifiersEffects, @@ -17,46 +12,55 @@ import { primary as qualifiersPrimary, text as qualifiersText, } from "../constants/qualifiers.js"; +import { plugin } from "../lib/plugin.js"; import { constructTransformation } from "../lib/transformations.js"; -import type { TransformationPlugin } from "../types/plugins.js"; -import type { Qualifier } from "../types/qualifiers.js"; - -const overlayTextSchema = z.object({ - alignment: z.string().optional(), - antialias: z.string().optional(), - border: z.string().optional(), - color: z.string().optional(), - fontFamily: z.string().optional(), - fontSize: z.number().optional(), - fontStyle: z.union([z.string(), z.number()]).optional(), - fontWeight: z.string().optional(), - hinting: z.union([z.string(), z.number()]).optional(), - letterSpacing: z.union([z.string(), z.number()]).optional(), - lineSpacing: z.union([z.string(), z.number()]).optional(), - stroke: z.string().optional(), - text: z.string(), // Required if using object format -}); - -const overlayPositionSchema = z.object({ - angle: angle.schema.optional(), - gravity: gravity.schema.optional(), - x: x.schema.optional(), - y: y.schema.optional(), -}); +import { entriesOf, isArray } from "../lib/utils.js"; +import type { QualifierConfig } from "../types/qualifiers.js"; -const overlaySchema = z.object({ - appliedEffects: z.array(z.object({})).optional(), - appliedFlags: flags.schema.optional(), - effects: z.array(z.object({})).optional(), - crop: crop.schema.optional(), - flags: flags.schema.optional(), - height: height.schema.optional(), - position: overlayPositionSchema.optional(), - publicId: z.string().optional(), - text: z.union([z.string(), overlayTextSchema]).optional(), - url: z.string().optional(), - width: width.schema.optional(), -}); +export declare namespace OverlaysPlugin { + export interface Options { + /** + * @description Image or text layers that are applied on top of the base image. + * @url https://cloudinary.com/documentation/transformation_reference#l_layer + */ + overlays?: ReadonlyArray; + /** + * @description Text to be overlaid on asset. + * @url https://cloudinary.com/documentation/image_transformations#transformation_url_structure + */ + text?: string | TextOptions; + } + + export interface NestedOptions { + appliedEffects?: object[]; + appliedFlags?: ListableFlags; + effects?: object[]; + crop?: CropMode; + flags?: ListableFlags; + height?: Height; + position?: PositionalOptions; + publicId?: string; + text?: string | TextOptions; + url?: string; + width?: Width; + } + + export interface TextOptions { + text: string; + alignment?: string; + antialias?: string; + border?: string; + color?: string; + fontFamily?: string; + fontSize?: number; + fontStyle?: string | number; + fontWeight?: string; + hinting?: string | number; + letterSpacing?: string | number; + lineSpacing?: string | number; + stroke?: boolean; + } +} export const DEFAULT_TEXT_OPTIONS = { color: "black", @@ -65,45 +69,17 @@ export const DEFAULT_TEXT_OPTIONS = { fontWeight: "bold", }; -export const overlaysProps = { - overlay: overlaySchema - .describe( - JSON.stringify({ - text: "Image or text layer that is applied on top of the base image.", - url: "https://cloudinary.com/documentation/transformation_reference#l_layer", - }) - ) - .optional(), - overlays: z - .array(overlaySchema) - .describe( - JSON.stringify({ - text: "Image or text layers that are applied on top of the base image.", - url: "https://cloudinary.com/documentation/transformation_reference#l_layer", - }) - ) - .optional(), - text: z - .string() - .describe( - JSON.stringify({ - text: "Text to be overlaid on asset.", - url: "https://cloudinary.com/documentation/image_transformations#transformation_url_structure", - }) - ) - .optional(), -}; - -export const overlaysPlugin = { - props: overlaysProps, - assetTypes: ["image", "images", "video", "videos"], - plugin: ({ cldAsset, options }) => { +export const OverlaysPlugin = plugin({ + name: "Overlays", + supports: "all", + inferOwnOptions: {} as OverlaysPlugin.Options, + apply: (cldAsset, options) => { const { text, overlays = [] } = options; const type = "overlay"; const typeQualifier = "l"; - if (Array.isArray(overlays)) { + if (isArray(overlays)) { overlays.forEach(applyOverlay); } @@ -119,12 +95,6 @@ export const overlaysPlugin = { }); } - /** - * applyOverlay - */ - - type ApplyOverlaySettings = z.infer; - function applyOverlay({ publicId, url, @@ -135,7 +105,7 @@ export const overlaysPlugin = { flags: layerFlags = [], appliedFlags = [], ...options - }: ApplyOverlaySettings) { + }: OverlaysPlugin.NestedOptions) { const hasPublicId = typeof publicId === "string"; const hasUrl = typeof url === "string"; const hasText = typeof text === "object" || typeof text === "string"; @@ -168,12 +138,12 @@ export const overlaysPlugin = { const primary: Array = []; const applied: Array = []; - // Gemeral options + // General options (Object.keys(options) as Array).forEach((key) => { if (!objectHasKey(qualifiersPrimary, key)) return; - const { qualifier, converters } = qualifiersPrimary[key]; + const { qualifier, converters } = qualifiersPrimary[key]!; const transformation = constructTransformation({ qualifier, @@ -251,20 +221,9 @@ export const overlaysPlugin = { // Add flags to the primary layer transformation segment // @TODO: accept flag value - const activeLayerFlags = Array.isArray(layerFlags) - ? layerFlags - : [layerFlags]; + const activeLayerFlags = isArray(layerFlags) ? layerFlags : [layerFlags]; activeLayerFlags.forEach((flag) => { - const { success } = flagsEnum.safeParse(flag); - - if (!success) { - if (process.env.NODE_ENV === "development") { - console.warn(`Invalid flag ${flag}, not applying.`); - } - return; - } - primary.push(`fl_${flag}`); }); @@ -272,20 +231,11 @@ export const overlaysPlugin = { // Add flags to the fl_layer_apply transformation segment // @TODO: accept flag value - const activeAppliedFlags = Array.isArray(appliedFlags) + const activeAppliedFlags = isArray(appliedFlags) ? appliedFlags : [appliedFlags]; activeAppliedFlags.forEach((flag) => { - const { success } = flagsEnum.safeParse(flag); - - if (!success) { - if (process.env.NODE_ENV === "development") { - console.warn(`Invalid flag ${flag}, not applying.`); - } - return; - } - applied.push(`fl_${flag}`); }); @@ -302,23 +252,23 @@ export const overlaysPlugin = { const textTransformations: Array = []; if (typeof text === "object") { - interface TextOption extends Qualifier { + interface TextOption extends QualifierConfig { key: string; value: any; order: number; } - const textOptions: Array = Object.keys(text) - .filter((key) => objectHasKey(qualifiersText, key)) - .map((key) => { - const value = text && objectHasKey(text, key) && text[key]; + const textOptions: Array = entriesOf(text).flatMap( + ([key, value]) => { + if (!qualifiersText[key]) return []; return { ...qualifiersText[key], key, value, order: qualifiersText[key].order || 99, }; - }); + } + ); const sortedTextOptions = sortByKey(textOptions, "order"); @@ -373,18 +323,14 @@ export const overlaysPlugin = { // Positioning if (hasPosition) { - Object.keys(position).forEach((key) => { - if ( - !objectHasKey(qualifiersPosition, key) || - !objectHasKey(position, key) - ) - return; + Object.entries(position).forEach(([key, value]) => { + if (!objectHasKey(qualifiersPosition, key)) return; const { qualifier, converters } = qualifiersPosition[key]; const transformation = constructTransformation({ qualifier, - value: position[key], + value, converters, }); @@ -415,4 +361,4 @@ export const overlaysPlugin = { return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/preserve-transformations.ts b/packages/url-loader/src/plugins/preserve-transformations.ts index 284c4e90..8adb53f4 100644 --- a/packages/url-loader/src/plugins/preserve-transformations.ts +++ b/packages/url-loader/src/plugins/preserve-transformations.ts @@ -1,22 +1,20 @@ import { getTransformations } from "@cloudinary-util/util"; -import { z } from "zod"; -import type { TransformationPlugin } from "../types/plugins.js"; +import { plugin } from "../lib/plugin.js"; -export const preserveTransformationsProps = { - preserveTransformations: z - .boolean() - .describe( - JSON.stringify({ - text: "Preserves transformations from a Cloudinary URL when using using a Cloudinary URL as the asset source (src).", - }) - ) - .optional(), -}; +export declare namespace PreserveTransformationsPlugin { + export interface Options { + /** + * @description Preserves transformations from a Cloudinary URL when using using a Cloudinary URL as the asset source (src). + */ + preserveTransformations?: boolean; + } +} -export const preserveTransformationsPlugin = { - props: preserveTransformationsProps, - assetTypes: ["image", "images", "video", "videos"], - plugin: ({ cldAsset, options }) => { +export const PreserveTransformationsPlugin = plugin({ + name: "PreserveTransformations", + supports: "all", + inferOwnOptions: {} as PreserveTransformationsPlugin.Options, + apply: (cldAsset, options) => { const { preserveTransformations = false } = options; // Try to preserve the original transformations from the Cloudinary URL passed in @@ -25,15 +23,22 @@ export const preserveTransformationsPlugin = { if (preserveTransformations) { try { - const transformations = getTransformations(options.src).map(t => t.join(',')); + if (options.src === undefined) { + throw new Error("options.src was undefined"); + } + const transformations = getTransformations(options.src).map((t) => + t.join(",") + ); transformations.flat().forEach((transformation) => { cldAsset.addTransformation(transformation); }); - } catch(e) { - console.warn(`Failed to preserve transformations: ${(e as Error).message}`) + } catch (e) { + console.warn( + `Failed to preserve transformations: ${(e as Error).message}` + ); } } return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/raw-transformations.ts b/packages/url-loader/src/plugins/raw-transformations.ts index 6b707425..a7e61036 100644 --- a/packages/url-loader/src/plugins/raw-transformations.ts +++ b/packages/url-loader/src/plugins/raw-transformations.ts @@ -1,35 +1,31 @@ -import { z } from "zod"; -import type { TransformationPlugin } from "../types/plugins.js"; +import { plugin } from "../lib/plugin.js"; +import { isArray } from "../lib/utils.js"; -const RawTransformationSchema = z.string(); -type RawTransformation = z.infer; +export declare namespace RawTransformationsPlugin { + export interface Options { + /** + * @description Array of transformation parameters using the Cloudinary URL API to apply to an asset. + * @url https://cloudinary.com/documentation/transformation_reference + */ + rawTransformations?: string | ReadonlyArray; + } +} -export const rawTransformationsProps = { - rawTransformations: z - .union([RawTransformationSchema, z.array(RawTransformationSchema)]) - .describe( - JSON.stringify({ - text: "Array of transformation parameters using the Cloudinary URL API to apply to an asset.", - url: "https://cloudinary.com/documentation/transformation_reference", - }) - ) - .optional(), -}; - -export const rawTransformationsPlugin = { - props: rawTransformationsProps, - assetTypes: ["image", "images", "video", "videos"], - plugin: ({ cldAsset, options }) => { +export const RawTransformationsPlugin = plugin({ + name: "RawTransformations", + supports: "all", + inferOwnOptions: {} as RawTransformationsPlugin.Options, + apply: (cldAsset, options) => { let { rawTransformations = [] } = options; - if (!Array.isArray(rawTransformations)) { + if (!isArray(rawTransformations)) { rawTransformations = [rawTransformations]; } - rawTransformations.forEach((transformation: RawTransformation) => { + rawTransformations.forEach((transformation) => { cldAsset.addTransformation(transformation); }); return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/recolor.ts b/packages/url-loader/src/plugins/recolor.ts index 78df7a01..c11a9512 100644 --- a/packages/url-loader/src/plugins/recolor.ts +++ b/packages/url-loader/src/plugins/recolor.ts @@ -1,36 +1,33 @@ -import { z } from "zod"; +import type { ListablePrompts } from "../constants/parameters.js"; +import { plugin } from "../lib/plugin.js"; import { promptArrayToString } from "../lib/transformations.js"; -import type { ImageOptions } from "../types/image.js"; -import type { TransformationPlugin } from "../types/plugins.js"; +import { isArray } from "../lib/utils.js"; -const imageOptionsRecolorPromptSchema = z.union([ - z.string(), - z.array(z.string()), -]); +export declare namespace RecolorPlugin { + export interface Options { + /** + * @description Uses generative AI to recolor parts of your image, maintaining the relative shading. + * @url https://cloudinary.com/documentation/transformation_reference#e_gen_recolor + */ + recolor?: + | string + | ReadonlyArray + | readonly [ReadonlyArray, ...Array] + | NestedOptions; + } -const imageOptionsRecolorSchema = z.object({ - prompt: imageOptionsRecolorPromptSchema.optional(), - to: z.string().optional(), - multiple: z.boolean().optional(), -}); - -export const recolorProps = { - recolor: z - .union([imageOptionsRecolorPromptSchema, imageOptionsRecolorSchema]) - .describe( - JSON.stringify({ - text: "Uses generative AI to recolor parts of your image, maintaining the relative shading.", - url: "https://cloudinary.com/documentation/transformation_reference#e_gen_recolor", - }) - ) - .optional(), -}; + export interface NestedOptions { + prompt?: ListablePrompts; + to?: string; + multiple?: boolean; + } +} -export const recolorPlugin = { - props: recolorProps, - assetTypes: ["image", "images"], - plugin: (settings) => { - const { cldAsset, options } = settings; +export const RecolorPlugin = plugin({ + name: "Recolor", + supports: "image", + inferOwnOptions: {} as RecolorPlugin.Options, + apply: (cldAsset, options) => { const { recolor } = options; const recolorOptions: Record = { @@ -39,8 +36,8 @@ export const recolorPlugin = { multiple: undefined, }; - if (Array.isArray(recolor)) { - if (Array.isArray(recolor[0])) { + if (isArray(recolor)) { + if (isArray(recolor[0])) { recolorOptions.prompt = promptArrayToString(recolor[0]); } else { recolorOptions.prompt = recolor[0]; @@ -54,7 +51,7 @@ export const recolorPlugin = { if (typeof recolor.prompt === "string") { recolorOptions.prompt = recolor.prompt; - } else if (Array.isArray(recolor.prompt)) { + } else if (isArray(recolor.prompt)) { recolorOptions.prompt = promptArrayToString(recolor.prompt); } @@ -78,4 +75,4 @@ export const recolorPlugin = { return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/remove-background.ts b/packages/url-loader/src/plugins/remove-background.ts index e976a47d..5a626809 100644 --- a/packages/url-loader/src/plugins/remove-background.ts +++ b/packages/url-loader/src/plugins/remove-background.ts @@ -1,28 +1,23 @@ -import { z } from "zod"; -import type { ImageOptions } from "../types/image.js"; -import type { TransformationPlugin } from "../types/plugins.js"; +import { plugin } from "../lib/plugin.js"; -export const removeBackgroundProps = { - removeBackground: z - .boolean() - .describe( - JSON.stringify({ - text: "Removes the background of an image using the Cloudinary AI Background Removal Add-On (Required).", - url: "https://cloudinary.com/documentation/cloudinary_ai_background_removal_addon", - }) - ) - .optional(), -}; +export declare namespace RemoveBackgroundPlugin { + export interface Options { + /** + * @description Removes the background of an image using the Cloudinary AI Background Removal Add-On (Required). + * @url https://cloudinary.com/documentation/cloudinary_ai_background_removal_addon + */ + removeBackground?: boolean; + } +} -export const removeBackgroundPlugin = { - props: removeBackgroundProps, - assetTypes: ["image", "images"], - plugin: (settings) => { - const { cldAsset, options } = settings; - const { removeBackground = false } = options; - if (removeBackground) { - cldAsset.effect("e_background_removal"); +export const RemoveBackgroundPlugin = plugin({ + name: "RemoveBackground", + supports: "image", + inferOwnOptions: {} as RemoveBackgroundPlugin.Options, + apply: (cldAsset, options) => { + if (options.removeBackground) { + cldAsset.addTransformation("e_background_removal"); } return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/remove.ts b/packages/url-loader/src/plugins/remove.ts index 94e5de48..e6ef69e3 100644 --- a/packages/url-loader/src/plugins/remove.ts +++ b/packages/url-loader/src/plugins/remove.ts @@ -1,38 +1,30 @@ -import { z } from "zod"; +import type { ListablePrompts } from "../constants/parameters.js"; +import { plugin } from "../lib/plugin.js"; import { promptArrayToString } from "../lib/transformations.js"; -import type { ImageOptions } from "../types/image.js"; -import type { TransformationPlugin } from "../types/plugins.js"; - -const imageOptionsRemovePromptSchema = z.union([ - z.string(), - z.array(z.string()), -]); - -const imageOptionsRemoveSchema = z.object({ - prompt: imageOptionsRemovePromptSchema.optional(), - region: z - .union([z.array(z.number()), z.array(z.array(z.number()))]) - .optional(), - multiple: z.boolean().optional(), - removeShadow: z.boolean().optional(), -}); +import { isArray } from "../lib/utils.js"; + +export declare namespace RemovePlugin { + export interface Options { + /** + * @description Applies zooming and/or panning to an image, resulting in a video or animated image. + * @url https://cloudinary.com/documentation/transformation_reference#e_zoompan + */ + remove?: ListablePrompts | NestedOptions; + } + + export interface NestedOptions { + prompt?: ListablePrompts; + region?: number[] | number[][]; + multiple?: boolean; + removeShadow?: boolean; + } +} -export const removeProps = { - remove: z - .union([imageOptionsRemovePromptSchema, imageOptionsRemoveSchema]) - .describe( - JSON.stringify({ - text: "Applies zooming and/or panning to an image, resulting in a video or animated image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_zoompan", - }) - ) - .optional(), -}; - -export const removePlugin = { - props: removeProps, - assetTypes: ["image", "images"], - plugin: ({ cldAsset, options }) => { +export const RemovePlugin = plugin({ + name: "Remove", + supports: "image", + inferOwnOptions: {} as RemovePlugin.Options, + apply: (cldAsset, options) => { const { remove } = options; const removeOptions: Record = { @@ -44,12 +36,12 @@ export const removePlugin = { if (typeof remove === "string") { removeOptions.prompt = remove; - } else if (Array.isArray(remove)) { + } else if (isArray(remove)) { removeOptions.prompt = promptArrayToString(remove); } else if (typeof remove === "object") { const hasPrompt = - typeof remove.prompt === "string" || Array.isArray(remove.prompt); - const hasRegion = Array.isArray(remove.region); + typeof remove.prompt === "string" || isArray(remove.prompt); + const hasRegion = isArray(remove.region); if (hasPrompt && hasRegion) { throw new Error( @@ -61,13 +53,13 @@ export const removePlugin = { if (typeof remove.prompt === "string") { removeOptions.prompt = remove.prompt; - } else if (Array.isArray(remove.prompt)) { + } else if (isArray(remove.prompt)) { removeOptions.prompt = promptArrayToString(remove.prompt); } // Region can be an array of numbers, or an array with 1+ arrays of numbers - if (Array.isArray(remove.region)) { + if (isArray(remove.region)) { removeOptions.region = regionArrayToString(remove.region); } @@ -91,7 +83,7 @@ export const removePlugin = { return {}; }, -} satisfies TransformationPlugin; +}); /** * regionArrayToString @@ -109,7 +101,7 @@ function regionArrayToString( const regionString = regionArray .map((region, index) => { - if (Array.isArray(region)) { + if (isArray(region)) { return regionArrayToString(region); } diff --git a/packages/url-loader/src/plugins/replace-background.ts b/packages/url-loader/src/plugins/replace-background.ts index b574e8f0..b038cdb6 100644 --- a/packages/url-loader/src/plugins/replace-background.ts +++ b/packages/url-loader/src/plugins/replace-background.ts @@ -1,58 +1,52 @@ -import { z } from "zod"; -import type { ImageOptions } from "../types/image.js"; -import type { TransformationPlugin } from "../types/plugins.js"; - -export const replaceBackgroundProps = { - replaceBackground: z - .union([ - z.boolean(), - z.string(), - z.object({ - seed: z.number().optional(), - prompt: z.string().optional(), - }), - ]) - .describe( - JSON.stringify({ - text: "Replaces the background of an image with an AI-generated background.", - url: "https://cloudinary.com/documentation/transformation_reference#e_gen_background_replace", - }) - ) - .optional(), -}; - -export const replaceBackgroundPlugin = { - props: replaceBackgroundProps, - assetTypes: ["image", "images"], - plugin: (settings) => { - const { cldAsset, options } = settings; +import { plugin } from "../lib/plugin.js"; + +export declare namespace ReplaceBackgroundPlugin { + export interface Options { + /** + * @description Replaces the background of an image with an AI-generated background. + * @url https://cloudinary.com/documentation/transformation_reference#e_gen_background_replace + */ + replaceBackground?: NestedOptions; + } + + export interface NestedOptions { + prompt?: string; + seed?: number; + } +} + +export const ReplaceBackgroundPlugin = plugin({ + name: "ReplaceBackground", + supports: "image", + inferOwnOptions: {} as ReplaceBackgroundPlugin.Options, + apply: (cldAsset, options) => { const { replaceBackground } = options; - if (!replaceBackground || typeof replaceBackground === "undefined") return {}; + if (!replaceBackground || typeof replaceBackground === "undefined") + return {}; const properties = []; - if ( typeof replaceBackground === 'object' ) { - - if ( typeof replaceBackground.prompt !== 'undefined' ) { + if (typeof replaceBackground === "object") { + if (typeof replaceBackground.prompt !== "undefined") { properties.push(`prompt_${replaceBackground.prompt}`); } - if ( typeof replaceBackground.seed === 'number' ) { + if (typeof replaceBackground.seed === "number") { properties.push(`seed_${replaceBackground.seed}`); - } - } else if ( typeof replaceBackground === 'string' ) { + } + } else if (typeof replaceBackground === "string") { properties.push(`prompt_${replaceBackground}`); } - let transformation = 'e_gen_background_replace'; + let transformation = "e_gen_background_replace"; - if ( properties.length > 0 ) { - transformation = `${transformation}:${properties.join(';')}`; + if (properties.length > 0) { + transformation = `${transformation}:${properties.join(";")}`; } cldAsset.addTransformation(transformation); return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/replace.ts b/packages/url-loader/src/plugins/replace.ts index e8e39e23..e883e8b9 100644 --- a/packages/url-loader/src/plugins/replace.ts +++ b/packages/url-loader/src/plugins/replace.ts @@ -1,31 +1,27 @@ -import { z } from "zod"; -import type { ImageOptions } from "../types/image.js"; -import type { TransformationPlugin } from "../types/plugins.js"; - -export const replaceProps = { - replace: z - .union([ - z.array(z.string()), - z.array(z.boolean()), - z.object({ - to: z.string(), - from: z.string(), - preserveGeometry: z.boolean().optional(), - }), - ]) - .describe( - JSON.stringify({ - text: "Uses generative AI to replace parts of your image with something else.", - url: "https://cloudinary.com/documentation/transformation_reference#e_gen_replace", - }) - ) - .optional(), -}; - -export const replacePlugin = { - props: replaceProps, - assetTypes: ["image", "images"], - plugin: ({ cldAsset, options }) => { +import { plugin } from "../lib/plugin.js"; +import { isArray } from "../lib/utils.js"; + +export declare namespace ReplacePlugin { + export interface Options { + /** + * @description Uses generative AI to replace parts of your image with something else. + * @url https://cloudinary.com/documentation/transformation_reference#e_gen_replace + */ + replace?: NestedOptions | ReadonlyArray | ReadonlyArray; + } + + export interface NestedOptions { + from: string; + to: string; + preserveGeometry?: boolean; + } +} + +export const ReplacePlugin = plugin({ + name: "Replace", + supports: "image", + inferOwnOptions: {} as ReplacePlugin.Options, + apply: (cldAsset, options) => { const { replace = null } = options; if (replace) { @@ -33,7 +29,7 @@ export const replacePlugin = { to: string, preserveGeometry: boolean = false; - if (Array.isArray(replace)) { + if (isArray(replace)) { from = replace[0] as string; to = replace[1] as string; preserveGeometry = (replace[2] as boolean) || false; @@ -50,9 +46,9 @@ export const replacePlugin = { properties.push(`preserve-geometry_${preserveGeometry}`); } - cldAsset.effect(properties.join(";")); + cldAsset.addTransformation(properties.join(";")); } return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/restore.ts b/packages/url-loader/src/plugins/restore.ts index a0754145..0b0d6160 100644 --- a/packages/url-loader/src/plugins/restore.ts +++ b/packages/url-loader/src/plugins/restore.ts @@ -1,29 +1,26 @@ -import { z } from "zod"; -import type { ImageOptions } from "../types/image.js"; -import type { TransformationPlugin } from "../types/plugins.js"; +import { plugin } from "../lib/plugin.js"; -export const restoreProps = { - restore: z - .boolean() - .describe( - JSON.stringify({ - text: "Uses generative AI to restore details in poor quality images or images that may have become degraded through repeated processing and compression.", - url: "https://cloudinary.com/documentation/transformation_reference#e_gen_restore", - }) - ) - .optional(), -}; +export declare namespace RestorePlugin { + export interface Options { + /** + * @description Uses generative AI to restore details in poor quality images or images that may have become degraded through repeated processing and compression. + * @url https://cloudinary.com/documentation/transformation_reference#e_gen_restore + */ + restore?: boolean; + } +} -export const restorePlugin = { - props: restoreProps, - assetTypes: ["image", "images"], - plugin: ({ cldAsset, options }) => { +export const RestorePlugin = plugin({ + name: "Restore", + supports: "image", + inferOwnOptions: {} as RestorePlugin.Options, + apply: (cldAsset, options) => { const { restore = false } = options; if (restore) { - cldAsset.effect("e_gen_restore"); + cldAsset.addTransformation("e_gen_restore"); } return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/sanitize.ts b/packages/url-loader/src/plugins/sanitize.ts index bea85dc8..63bd8145 100644 --- a/packages/url-loader/src/plugins/sanitize.ts +++ b/packages/url-loader/src/plugins/sanitize.ts @@ -1,33 +1,31 @@ -import { z } from "zod"; -import type { ImageOptions } from "../types/image.js"; -import type { TransformationPlugin } from "../types/plugins.js"; +import { plugin } from "../lib/plugin.js"; -export const sanitizeProps = { - sanitize: z - .boolean() - .describe( - JSON.stringify({ - text: "Runs a sanitizer on SVG images.", - url: "https://cloudinary.com/documentation/transformation_reference#fl_sanitize", - }) - ) - .optional(), -}; +export declare namespace SanitizePlugin { + export interface Options { + /** + * @description Runs a sanitizer on SVG images. + * @url https://cloudinary.com/documentation/transformation_reference#fl_sanitize + */ + sanitize?: boolean; + } +} -export const sanitizePlugin = { - props: sanitizeProps, - assetTypes: ["image", "images"], - plugin: ({ cldAsset, options }) => { +export const SanitizePlugin = plugin({ + name: "Sanitize", + supports: "image", + inferOwnOptions: {} as SanitizePlugin.Options, + apply: (cldAsset, options) => { const { sanitize = true } = options; const shouldApplySanitizer: boolean = sanitize && - (options.format === "svg" || cldAsset.publicID.endsWith(".svg")); + (options.format === "svg" || + (cldAsset as {} as { publicID: string }).publicID.endsWith(".svg")); if (shouldApplySanitizer) { - cldAsset.effect("fl_sanitize"); + cldAsset.addTransformation("fl_sanitize"); } return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/seo.ts b/packages/url-loader/src/plugins/seo.ts index cdb71bbd..afceea67 100644 --- a/packages/url-loader/src/plugins/seo.ts +++ b/packages/url-loader/src/plugins/seo.ts @@ -1,22 +1,20 @@ -import { z } from "zod"; -import type { TransformationPlugin } from "../types/plugins.js"; +import { plugin } from "../lib/plugin.js"; -export const seoProps = { - seoSuffix: z - .string() - .describe( - JSON.stringify({ - text: "Configures the URL to include an SEO-friendly suffix in the URL", - url: "https://cloudinary.com/documentation/advanced_url_delivery_options#seo_friendly_media_asset_urls", - }) - ) - .optional(), -}; +export declare namespace SeoPlugin { + export interface Options { + /** + * @description Configures the URL to include an SEO-friendly suffix in the URL + * @url https://cloudinary.com/documentation/advanced_url_delivery_options#seo_friendly_media_asset_urls + */ + seoSuffix?: string; + } +} -export const seoPlugin = { - props: seoProps, - assetTypes: ["image", "images", "video", "videos"], - plugin: ({ cldAsset, options }) => { +export const SeoPlugin = plugin({ + name: "Seo", + supports: "all", + inferOwnOptions: {} as SeoPlugin.Options, + apply: (cldAsset, options) => { const { seoSuffix } = options; if (typeof seoSuffix === "string") { @@ -31,4 +29,4 @@ export const seoPlugin = { return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/underlays.ts b/packages/url-loader/src/plugins/underlays.ts index ee9b96d3..fec4745f 100644 --- a/packages/url-loader/src/plugins/underlays.ts +++ b/packages/url-loader/src/plugins/underlays.ts @@ -1,78 +1,62 @@ import { objectHasKey } from "@cloudinary-util/util"; -import { z } from "zod"; -import { - angle, - crop, - flags, - flagsEnum, - gravity, - height, - width, - x, - y, +import type { + CropMode, + Height, + ListableFlags, + PositionalOptions, + Width, } from "../constants/parameters.js"; import { position as qualifiersPosition, primary as qualifiersPrimary, } from "../constants/qualifiers.js"; -import type { TransformationPlugin } from "../types/plugins.js"; - -const underlayPositionSchema = z.object({ - angle: angle.schema.optional(), - gravity: gravity.schema.optional(), - x: x.schema.optional(), - y: y.schema.optional(), -}); - -const underlaySchema = z.object({ - appliedEffects: z.array(z.object({})).optional(), - appliedFlags: flags.schema.optional(), - effects: z.array(z.object({})).optional(), - crop: crop.schema.optional(), - flags: flags.schema.optional(), - height: height.schema.optional(), - position: underlayPositionSchema.optional(), - publicId: z.string().optional(), - type: z.string().optional(), - url: z.string().optional(), - width: width.schema.optional(), -}); +import { plugin } from "../lib/plugin.js"; +import { entriesOf, isArray } from "../lib/utils.js"; -export const underlaysProps = { - underlay: z - .string() - .describe( - JSON.stringify({ - text: "Public ID of image that is applied under the base image.", - url: "https://cloudinary.com/documentation/transformation_reference#l_layer", - }) - ) - .optional(), - underlays: z - .array(underlaySchema) - .describe( - JSON.stringify({ - text: "Image layers that are applied under the base image.", - url: "https://cloudinary.com/documentation/transformation_reference#l_layer", - }) - ) - .optional(), -}; - -export const underlaysPlugin = { - props: underlaysProps, - assetTypes: ["image", "images", "video", "videos"], - plugin: ({ cldAsset, options }) => { +export declare namespace UnderlaysPlugin { + export interface Options { + /** + * @description Public ID of image that is applied under the base image. + * @url https://cloudinary.com/documentation/transformation_reference#l_layer + */ + underlay?: string; + /** + * @description Image layers that are applied under the base image. + * @url https://cloudinary.com/documentation/transformation_reference#l_layer + */ + underlays?: ReadonlyArray; + } + + export interface NestedOptions { + appliedEffects?: ReadonlyArray; + appliedFlags?: ListableFlags; + effects?: ReadonlyArray; + crop?: CropMode; + flags?: ListableFlags; + height?: Height; + position?: PositionalOptions; + publicId?: string; + type?: string; + url?: string; + width?: Width; + } +} + +export const UnderlaysPlugin = plugin({ + name: "Underlays", + supports: "all", + inferOwnOptions: {} as UnderlaysPlugin.Options, + apply: (cldAsset, options) => { const { underlay, underlays = [] } = options; const typeQualifier = "u"; - if (Array.isArray(underlays)) { + if (isArray(underlays)) { underlays.forEach(applyUnderlay); } if (typeof underlay === "string") { - const underlayOptions: ApplyUnderlaySettings = { + const underlayOptions: UnderlaysPlugin.NestedOptions = { publicId: underlay, crop: "fill", width: "1.0", @@ -87,8 +71,6 @@ export const underlaysPlugin = { * applyUnderlay */ - type ApplyUnderlaySettings = z.infer; - function applyUnderlay({ publicId, type, @@ -97,7 +79,7 @@ export const underlaysPlugin = { flags: layerFlags = [], appliedFlags = [], ...options - }: ApplyUnderlaySettings) { + }: UnderlaysPlugin.NestedOptions) { const hasPublicId = typeof publicId === "string"; const hasPosition = typeof position === "object"; @@ -121,10 +103,10 @@ export const underlaysPlugin = { // Gemeral options - (Object.keys(options) as Array).forEach((key) => { + entriesOf(options).forEach(([key, value]) => { if (!objectHasKey(qualifiersPrimary, key)) return; - const { qualifier } = qualifiersPrimary[key]; - primary.push(`${qualifier}_${options[key]}`); + const { qualifier } = qualifiersPrimary[key]!; + primary.push(`${qualifier}_${value}`); }); // Layer effects @@ -140,56 +122,30 @@ export const underlaysPlugin = { // Positioning if (hasPosition) { - (Object.keys(position) as Array).forEach( - (key) => { - if (!objectHasKey(qualifiersPosition, key)) return; - const { qualifier } = qualifiersPosition[key as string]; - applied.push(`${qualifier}_${position[key]}`); - } - ); + entriesOf(position).forEach(([key, value]) => { + if (!objectHasKey(qualifiersPosition, key)) return; + const { qualifier } = qualifiersPosition[key]!; + applied.push(`${qualifier}_${value}`); + }); } // Layer Flags // Add flags to the primary layer transformation segment // @TODO: accept flag value - const activeLayerFlags = Array.isArray(layerFlags) - ? layerFlags - : [layerFlags]; - - activeLayerFlags.forEach((flag) => { - const { success } = flagsEnum.safeParse(flag); + const activeLayerFlags = isArray(layerFlags) ? layerFlags : [layerFlags]; - if (!success) { - if (process.env.NODE_ENV === "development") { - console.warn(`Invalid flag ${flag}, not applying.`); - } - return; - } - - primary.push(`fl_${flag}`); - }); + activeLayerFlags.forEach((flag) => primary.push(`fl_${flag}`)); // Applied Flags // Add flags to the fl_layer_apply transformation segment // @TODO: accept flag value - const activeAppliedFlags = Array.isArray(appliedFlags) + const activeAppliedFlags = isArray(appliedFlags) ? appliedFlags : [appliedFlags]; - activeAppliedFlags.forEach((flag) => { - const { success } = flagsEnum.safeParse(flag); - - if (!success) { - if (process.env.NODE_ENV === "development") { - console.warn(`Invalid flag ${flag}, not applying.`); - } - return; - } - - applied.push(`fl_${flag}`); - }); + activeAppliedFlags.forEach((flag) => applied.push(`fl_${flag}`)); // Add all primary transformations @@ -210,4 +166,4 @@ export const underlaysPlugin = { return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/version.ts b/packages/url-loader/src/plugins/version.ts index a8a9b10b..79584c6e 100644 --- a/packages/url-loader/src/plugins/version.ts +++ b/packages/url-loader/src/plugins/version.ts @@ -1,22 +1,20 @@ -import { z } from "zod"; -import type { TransformationPlugin } from "../types/plugins.js"; +import { plugin } from "../lib/plugin.js"; -export const versionProps = { - version: z - .union([z.number(), z.string()]) - .describe( - JSON.stringify({ - text: "Custom version number to apply to asset URL.", - url: "https://cloudinary.com/documentation/advanced_url_delivery_options#asset_versions", - }) - ) - .optional(), -}; +export declare namespace VersionPlugin { + export interface Options { + /** + * @description Custom version number to apply to asset URL. + * @url https://cloudinary.com/documentation/advanced_url_delivery_options#asset_versions + */ + version?: number | string; + } +} -export const versionPlugin = { - props: versionProps, - assetTypes: ["image", "images", "video", "videos"], - plugin: ({ cldAsset, options }) => { +export const VersionPlugin = plugin({ + name: "Version", + supports: "all", + inferOwnOptions: {} as VersionPlugin.Options, + apply: (cldAsset, options) => { const { version } = options; if (typeof version === "string" || typeof version === "number") { @@ -27,4 +25,4 @@ export const versionPlugin = { return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/zoompan.ts b/packages/url-loader/src/plugins/zoompan.ts index f13b377e..899316ee 100644 --- a/packages/url-loader/src/plugins/zoompan.ts +++ b/packages/url-loader/src/plugins/zoompan.ts @@ -1,31 +1,27 @@ -import { z } from "zod"; -import { effects as qualifiersEffects } from "../constants/qualifiers.js"; -import type { ImageOptions } from "../types/image.js"; -import type { PluginOptions, TransformationPlugin } from "../types/plugins.js"; +import type { QualifierOptions } from "../constants/qualifiers.js"; +import { plugin } from "../lib/plugin.js"; +import type { PluginOptions } from "../types/plugins.js"; -export const zoompanProps = { - zoompan: z - .union([ - z.string(), - z.boolean(), - z.object({ - loop: qualifiersEffects.loop.schema.optional(), - options: z.string(), - }), - ]) - .describe( - JSON.stringify({ - text: "Applies zooming and/or panning to an image, resulting in a video or animated image.", - url: "https://cloudinary.com/documentation/transformation_reference#e_zoompan", - }), - ) - .optional(), -}; +export declare namespace ZoompanPlugin { + export interface Options { + /** + * @description Applies zooming and/or panning to an image, resulting in a video or animated image. + * @url https://cloudinary.com/documentation/transformation_reference#e_zoompan + */ + zoompan?: string | boolean | NestedOptions; + } -export const zoompanPlugin = { - props: zoompanProps, - assetTypes: ["image", "images"], - plugin: ({ cldAsset, options }) => { + export interface NestedOptions { + loop?: QualifierOptions["loop"]; + options: string; + } +} + +export const ZoompanPlugin = plugin({ + name: "Zoompan", + supports: "image", + inferOwnOptions: {} as ZoompanPlugin.Options, + apply: (cldAsset, options) => { const { zoompan = false } = options; const overrides: PluginOptions = { @@ -33,13 +29,13 @@ export const zoompanPlugin = { }; if (zoompan === true) { - cldAsset.effect("e_zoompan"); + cldAsset.addTransformation("e_zoompan"); } else if (typeof zoompan === "string") { if (zoompan === "loop") { - cldAsset.effect("e_zoompan"); - cldAsset.effect("e_loop"); + cldAsset.addTransformation("e_zoompan"); + cldAsset.addTransformation("e_loop"); } else { - cldAsset.effect(`e_zoompan:${zoompan}`); + cldAsset.addTransformation(`e_zoompan:${zoompan}`); } } else if (typeof zoompan === "object") { let zoompanEffect = "e_zoompan"; @@ -48,7 +44,7 @@ export const zoompanPlugin = { zoompanEffect = `${zoompanEffect}:${zoompan.options}`; } - cldAsset.effect(zoompanEffect); + cldAsset.addTransformation(zoompanEffect); let loopEffect; @@ -62,7 +58,7 @@ export const zoompanPlugin = { } if (loopEffect) { - cldAsset.effect(loopEffect); + cldAsset.addTransformation(loopEffect); } } @@ -74,4 +70,4 @@ export const zoompanPlugin = { options: overrides, }; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/schema.ts b/packages/url-loader/src/schema.ts deleted file mode 100644 index 05a00f1f..00000000 --- a/packages/url-loader/src/schema.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { constructUrlPropsSchema } from "./lib/cloudinary.js"; -export { assetOptionsSchema } from "./types/asset.js"; -export { imageOptionsSchema } from "./types/image.js"; -export { videoOptionsSchema } from "./types/video.js"; diff --git a/packages/url-loader/src/types/analytics.ts b/packages/url-loader/src/types/analytics.ts deleted file mode 100644 index 87df9e53..00000000 --- a/packages/url-loader/src/types/analytics.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { z } from "zod"; -import type { IAnalyticsOptions } from "@cloudinary/url-gen/sdkAnalytics/interfaces/IAnalyticsOptions"; - -export interface CloudinaryAnalyticsOptions extends IAnalyticsOptions {} - -export const analyticsOptionsSchema: z.ZodType = - z.any(); - -export type AnalyticsOptions = z.TypeOf | false; diff --git a/packages/url-loader/src/types/asset.ts b/packages/url-loader/src/types/asset.ts index 420474fc..b7d4f280 100644 --- a/packages/url-loader/src/types/asset.ts +++ b/packages/url-loader/src/types/asset.ts @@ -1,116 +1,80 @@ -import { z } from "zod"; -import { croppingProps } from "../plugins/cropping.js"; -import { effectsProps } from "../plugins/effects.js"; -import { flagsProps } from "../plugins/flags.js"; -import { namedTransformationsProps } from "../plugins/named-transformations.js"; -import { overlaysProps } from "../plugins/overlays.js"; -import { preserveTransformationsProps } from "../plugins/preserve-transformations.js"; -import { rawTransformationsProps } from "../plugins/raw-transformations.js"; -import { removeBackgroundProps } from "../plugins/remove-background.js"; -import { sanitizeProps } from "../plugins/sanitize.js"; -import { seoProps } from "../plugins/seo.js"; -import { underlaysProps } from "../plugins/underlays.js"; -import { versionProps } from "../plugins/version.js"; +import type { SupportedAssetType } from "../lib/plugin.js"; +import type { CroppingPlugin } from "../plugins/cropping.js"; +import type { EffectsPlugin } from "../plugins/effects.js"; +import type { FlagsPlugin } from "../plugins/flags.js"; +import type { NamedTransformationsPlugin } from "../plugins/named-transformations.js"; +import type { OverlaysPlugin } from "../plugins/overlays.js"; +import type { PreserveTransformationsPlugin } from "../plugins/preserve-transformations.js"; +import type { RawTransformationsPlugin } from "../plugins/raw-transformations.js"; +import type { RemoveBackgroundPlugin } from "../plugins/remove-background.js"; +import type { SanitizePlugin } from "../plugins/sanitize.js"; +import type { SeoPlugin } from "../plugins/seo.js"; +import type { UnderlaysPlugin } from "../plugins/underlays.js"; +import type { VersionPlugin } from "../plugins/version.js"; +import type { ZoompanPlugin } from "../plugins/zoompan.js"; -// Asset Options +export type SupportedAssetTypeInput = SupportedAssetType | "videos" | "images"; -export const assetOptionsSchema = z.object({ - assetType: z - .string() - .default("image") - .describe( - JSON.stringify({ - text: "The type of asset to deliver.", - url: "https://cloudinary.com/documentation/image_transformations#transformation_url_structure", - }), - ) - .optional(), - deliveryType: z - .string() - .default("upload") - .describe( - JSON.stringify({ - text: "Delivery method of the asset.", - url: "https://cloudinary.com/documentation/image_transformations#delivery_types", - }), - ) - .optional(), - dpr: z - .union([z.string(), z.number()]) - .describe( - JSON.stringify({ - text: "Delivery method of the asset.", - url: "https://cloudinary.com/documentation/image_transformations#delivery_types", - }), - ) - .optional(), - format: z - .string() - .default("auto") - .describe( - JSON.stringify({ - text: "Converts (if necessary) and delivers an asset in the specified format.", - url: "https://cloudinary.com/documentation/transformation_reference#f_format", - }), - ) - .optional(), - height: z - .union([z.string(), z.number()]) - .describe( - JSON.stringify({ - text: "Height of the given asset.", - }), - ) - .optional(), - quality: z - .union([z.string(), z.number(), z.string()]) - .default("auto") - .describe( - JSON.stringify({ - text: "Quality of the delivered asset", - url: "https://cloudinary.com/documentation/transformation_reference#q_quality", - }), - ) - .optional(), - src: z.string().describe( - JSON.stringify({ - text: "Cloudinary Public ID or versioned Cloudinary URL (/v1234/)", - }), - ), - strictTransformations: z - .boolean() - .describe( - JSON.stringify({ - text: "Gives you the ability to have more control over what transformations are permitted to be used from your Cloudinary account.", - url: "https://cloudinary.com/documentation/control_access_to_media#strict_transformations", - }), - ) - .optional(), - width: z - .union([z.string(), z.number()]) - .describe( - JSON.stringify({ - text: "Width of the given asset.", - }), - ) - .optional(), +export interface BaseAssetOptions< + assetType extends SupportedAssetTypeInput = SupportedAssetTypeInput, +> { + /** + * @description Cloudinary Public ID or versioned Cloudinary URL (/v1234/) + */ + src: string; + /** + * @description The type of asset to deliver. + * @url https://cloudinary.com/documentation/image_transformations#transformation_url_structure + */ + assetType?: assetType; + /** + * @description Delivery method of the asset. + * @url https://cloudinary.com/documentation/image_transformations#delivery_types + */ + deliveryType?: string; + /** + * @description Delivery method of the asset. + * @url https://cloudinary.com/documentation/image_transformations#delivery_types + */ + dpr?: string | number; + /** + * @description Converts (if necessary) and delivers an asset in the specified format. + * @url https://cloudinary.com/documentation/transformation_reference#f_format + */ + format?: string; + /** + * @description Height of the given asset. + */ + height?: string | number; + /** + * @description Quality of the delivered asset + * @url https://cloudinary.com/documentation/transformation_reference#q_quality + */ + quality?: string | number | string; + /** + * @description Gives you the ability to have more control over what transformations are permitted to be used from your Cloudinary account. + * @url https://cloudinary.com/documentation/control_access_to_media#strict_transformations + */ + strictTransformations?: boolean; + /** + * @description Width of the given asset. + */ + width?: string | number; +} - // Spreading plugins instead of extend or merge to avoid excessive schema warning - // https://github.com/microsoft/TypeScript/issues/34933#issuecomment-1772787785 - ...croppingProps, - ...effectsProps, - ...flagsProps, - ...namedTransformationsProps, - ...overlaysProps, - ...preserveTransformationsProps, - ...rawTransformationsProps, - ...removeBackgroundProps, - ...sanitizeProps, - ...seoProps, - ...underlaysProps, - ...versionProps, -}); - -type _AssetOptions = z.infer; - -export interface AssetOptions extends _AssetOptions {} +export interface AssetOptions< + assetType extends SupportedAssetTypeInput = SupportedAssetTypeInput, +> extends BaseAssetOptions, + CroppingPlugin.Options, + EffectsPlugin.Options, + FlagsPlugin.Options, + NamedTransformationsPlugin.Options, + OverlaysPlugin.Options, + PreserveTransformationsPlugin.Options, + RawTransformationsPlugin.Options, + RemoveBackgroundPlugin.Options, + SanitizePlugin.Options, + SeoPlugin.Options, + UnderlaysPlugin.Options, + VersionPlugin.Options, + ZoompanPlugin.Options {} diff --git a/packages/url-loader/src/types/config.ts b/packages/url-loader/src/types/config.ts deleted file mode 100644 index 56561301..00000000 --- a/packages/url-loader/src/types/config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { CloudinaryAssetConfiguration } from "@cloudinary-util/types"; -import { z } from "zod"; - -export interface CloudinaryConfigurationOptions extends CloudinaryAssetConfiguration {} - -export const configOptionsSchema: z.ZodType = - z.any(); - -export type ConfigOptions = z.TypeOf; \ No newline at end of file diff --git a/packages/url-loader/src/types/image.ts b/packages/url-loader/src/types/image.ts index f08fa573..430ea715 100644 --- a/packages/url-loader/src/types/image.ts +++ b/packages/url-loader/src/types/image.ts @@ -1,33 +1,24 @@ -import { z } from "zod"; -import { defaultImageProps } from "../plugins/default-image.js"; -import { enhanceProps } from "../plugins/enhance.js"; -import { extractProps } from "../plugins/extract.js"; -import { fillBackgroundProps } from "../plugins/fill-background.js"; -import { recolorProps } from "../plugins/recolor.js"; -import { removeProps } from "../plugins/remove.js"; -import { replaceBackgroundProps } from "../plugins/replace-background.js"; -import { replaceProps } from "../plugins/replace.js"; -import { restoreProps } from "../plugins/restore.js"; -import { zoompanProps } from "../plugins/zoompan.js"; -import { assetOptionsSchema } from "./asset.js"; +import type { DefaultImagePlugin } from "../plugins/default-image.js"; +import type { EnhancePlugin } from "../plugins/enhance.js"; +import type { ExtractPlugin } from "../plugins/extract.js"; +import type { FillBackgroundPlugin } from "../plugins/fill-background.js"; +import type { RecolorPlugin } from "../plugins/recolor.js"; +import type { RemovePlugin } from "../plugins/remove.js"; +import type { ReplaceBackgroundPlugin } from "../plugins/replace-background.js"; +import type { ReplacePlugin } from "../plugins/replace.js"; +import type { RestorePlugin } from "../plugins/restore.js"; +import type { ZoompanPlugin } from "../plugins/zoompan.js"; +import type { AssetOptions } from "./asset.js"; -export const imageOptionsSchema = assetOptionsSchema.merge( - z.object({ - // Spreading plugins instead of extend or merge to avoid excessive schema warning - // https://github.com/microsoft/TypeScript/issues/34933#issuecomment-1772787785 - ...defaultImageProps, - ...enhanceProps, - ...extractProps, - ...fillBackgroundProps, - ...recolorProps, - ...removeProps, - ...replaceProps, - ...replaceBackgroundProps, - ...restoreProps, - ...zoompanProps, - }) -); - -type _ImageOptions = z.infer; - -export interface ImageOptions extends _ImageOptions {} +export interface ImageOptions + extends AssetOptions, + DefaultImagePlugin.Options, + EnhancePlugin.Options, + ExtractPlugin.Options, + FillBackgroundPlugin.Options, + RecolorPlugin.Options, + RemovePlugin.Options, + ReplacePlugin.Options, + ReplaceBackgroundPlugin.Options, + RestorePlugin.Options, + ZoompanPlugin.Options {} diff --git a/packages/url-loader/src/types/plugins.ts b/packages/url-loader/src/types/plugins.ts index 2b656292..9f3d466a 100644 --- a/packages/url-loader/src/types/plugins.ts +++ b/packages/url-loader/src/types/plugins.ts @@ -1,54 +1,28 @@ -import { z } from "zod"; -import { - aspectRatio, - crop, - format, - gravity, - height, - width, - x, - y, - zoom, +import type { + AspectRatio, + CropMode, + Format, + Gravity, + Height, + Width, + X, + Y, + Zoom, } from "../constants/parameters.js"; -import type { AssetOptions } from "./asset.js"; -import type { ImageOptions } from "./image.js"; -import type { VideoOptions } from "./video.js"; -type AllOptions = AssetOptions | ImageOptions | VideoOptions; - -export interface PluginSettings { - cldAsset: any; - options: Options; +export interface PluginOptions { + aspectRatio?: AspectRatio; + crop?: CropMode; + gravity?: Gravity; + height?: Height; + format?: Format; + resize?: string; + x?: X; + y?: Y; + width?: Width; + zoom?: Zoom; } -export type PluginFunction = ( - settings: PluginSettings -) => PluginResults; - -export type AssetType = "image" | "images" | "video" | "videos"; - -export interface TransformationPlugin { - assetTypes: Array; - plugin: PluginFunction; - strict?: boolean; - props: object; -} - -export const pluginOptionsSchema = z.object({ - aspectRatio: aspectRatio.schema.optional(), - crop: crop.schema.optional(), - gravity: gravity.schema.optional(), - height: height.schema.optional(), - format: format.schema.optional(), - resize: z.string().optional(), - x: x.schema.optional(), - y: y.schema.optional(), - width: width.schema.optional(), - zoom: zoom.schema.optional(), -}); - -export type PluginOptions = z.infer; - export interface PluginResults { options?: PluginOptions; } diff --git a/packages/url-loader/src/types/qualifiers.ts b/packages/url-loader/src/types/qualifiers.ts index fb566046..e23f53c2 100644 --- a/packages/url-loader/src/types/qualifiers.ts +++ b/packages/url-loader/src/types/qualifiers.ts @@ -1,19 +1,14 @@ -import { z } from "zod"; - -export const qualifierConvertersSchema = z.object({ - convert: z.function().args(z.any()).returns(z.any()), - test: z.function().args(z.any()).returns(z.boolean()), -}); - -export type QualiferConverters = z.infer; - -export const qualifierSchema = z.object({ - location: z.string().optional(), - order: z.number().optional(), - prefix: z.string().optional(), - qualifier: z.union([z.string(), z.boolean()]).optional(), - converters: z.array(qualifierConvertersSchema).optional(), - schema: z.any(), -}); - -export type Qualifier = z.infer; +import type { ConstructTransformationSettings } from "../lib/transformations.js"; + +export interface QualifierConverters { + convert: (value: any) => ConstructTransformationSettings["value"]; + test: (value: any) => boolean; +} + +export interface QualifierConfig { + location?: string; + order?: number; + prefix?: string; + qualifier?: string | boolean; + converters?: ReadonlyArray; +} diff --git a/packages/url-loader/src/types/video.ts b/packages/url-loader/src/types/video.ts index 5e393f7e..179374bd 100644 --- a/packages/url-loader/src/types/video.ts +++ b/packages/url-loader/src/types/video.ts @@ -1,15 +1,4 @@ -import { z } from "zod"; -import { assetOptionsSchema } from "./asset.js"; -import { abrProps } from "../plugins/abr.js"; +import type { AbrPlugin } from "../plugins/abr.js"; +import type { AssetOptions } from "./asset.js"; -export const videoOptionsSchema = assetOptionsSchema.merge( - z.object({ - // Spreading plugins instead of extend or merge to avoid excessive schema warning - // https://github.com/microsoft/TypeScript/issues/34933#issuecomment-1772787785 - ...abrProps, - }), -); - -type _VideoOptions = z.infer; - -export interface VideoOptions extends _VideoOptions {} +export interface VideoOptions extends AssetOptions, AbrPlugin.Options {} diff --git a/packages/url-loader/tests/lib/cloudinary.spec.js b/packages/url-loader/tests/lib/cloudinary.spec.js deleted file mode 100644 index 6db61909..00000000 --- a/packages/url-loader/tests/lib/cloudinary.spec.js +++ /dev/null @@ -1,985 +0,0 @@ -import { afterEach, describe, expect, it, vi } from 'vitest'; - -import { constructCloudinaryUrl } from '../../src/lib/cloudinary'; - -// Mock console.warn() so we can see when it's called -global.console = { - ...global.console, - warn: vi.fn() -} - -describe('Cloudinary', () => { - afterEach(() => { - // Clears the state of console.warn, in case multiple tests want to monitor it - vi.restoreAllMocks() - }); - - describe('constructCloudinaryUrl', () => { - - it('should create a Cloudinary image URL', () => { - const cloudName = 'customtestcloud'; - const url = constructCloudinaryUrl({ - options: { - src: 'turtle', - width: 100, - height: 100 - }, - config: { - cloud: { - cloudName - } - } - }); - expect(url).toContain(`https://res.cloudinary.com/${cloudName}/image/upload/c_limit,w_100/f_auto/q_auto/v1/turtle`); - }); - - it('should create a Cloudinary video URL', () => { - const cloudName = 'customtestcloud'; - const assetType = 'video'; - const url = constructCloudinaryUrl({ - options: { - assetType, - src: 'turtle', - width: 100, - height: 100 - }, - config: { - cloud: { - cloudName - } - } - }); - expect(url).toContain(`https://res.cloudinary.com/${cloudName}/${assetType}/upload/c_limit,w_100/f_auto/q_auto/v1/turtle`); - }); - - /* Optimization */ - - describe('format, quality, dpr', () => { - - it('should create a Cloudinary URL with custom quality and format options', () => { - const format = 'png'; - const quality = 75; - const cloudName = 'customtestcloud'; - const url = constructCloudinaryUrl({ - options: { - src: 'turtle', - width: 100, - height: 100, - format, - quality - }, - config: { - cloud: { - cloudName - } - } - }); - expect(url).toContain(`https://res.cloudinary.com/${cloudName}/image/upload/c_limit,w_100/f_${format}/q_${quality}/v1/turtle`); - }); - - it('should not include quality or format in URL', () => { - const cloudName = 'customtestcloud'; - const deliveryType = 'upload'; - const publicId = 'myimage'; - - const src = `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/v1234/${publicId}?_a=`; - - const url = constructCloudinaryUrl({ - options: { - src, - width: 100, - height: 100, - quality: 'default', - format: 'default' - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(src); - }); - - it('should include custom DPR as a string', () => { - const cloudName = 'customtestcloud'; - const deliveryType = 'upload'; - const publicId = 'myimage'; - const dpr = '2.0'; - - const src = `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/dpr_${dpr}/f_auto/q_auto/v1/${publicId}?_a=`; - - const url = constructCloudinaryUrl({ - options: { - src: publicId, - width: 100, - height: 100, - dpr - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(src); - }); - - it('should include custom DPR as number', () => { - const cloudName = 'customtestcloud'; - const deliveryType = 'upload'; - const publicId = 'myimage'; - const dpr = 2; - - const src = `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/dpr_${dpr.toFixed(1)}/f_auto/q_auto/v1/${publicId}?_a=`; - - const url = constructCloudinaryUrl({ - options: { - src: publicId, - width: 100, - height: 100, - dpr - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(src); - }); - it('should include DPR auto', () => { - const cloudName = 'customtestcloud'; - const deliveryType = 'upload'; - const publicId = 'myimage'; - const dpr = 'auto'; - - const src = `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/dpr_${dpr}/f_auto/q_auto/v1/${publicId}?_a=`; - - const url = constructCloudinaryUrl({ - options: { - src: publicId, - width: 100, - height: 100, - dpr - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(src); - }); - - }); - - /* Cropping & Resizing */ - - describe('cropping, resizing', () => { - - it('should create a Cloudinary URL with a width, height, and custom crop', () => { - const cloudName = 'customtestcloud'; - const deliveryType = 'upload'; - const publicId = 'myimage'; - const width = 900; - const height = 900; - const crop = 'auto'; - - const url = constructCloudinaryUrl({ - options: { - src: publicId, - width, - height, - crop - }, - config: { - cloud: { - cloudName - } - } - }); - expect(url).toContain(`https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_${crop},w_${width},h_${height},g_auto/f_auto/q_auto/v1/${publicId}`); - }); - - it('should create a Cloudinary URL with a aspect ratio, custom crop, zoom, and default gravity', () => { - const cloudName = 'customtestcloud'; - const deliveryType = 'upload'; - const publicId = 'myimage'; - const aspectRatio = '16:9'; - const crop = 'fill'; - const zoom = '1.2'; - - const url = constructCloudinaryUrl({ - options: { - src: publicId, - aspectRatio, - crop, - zoom - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(`https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_${crop},ar_${aspectRatio},g_auto,z_${zoom}/f_auto/q_auto/v1/${publicId}`); - }); - - }); - - /* Delivery */ - - describe('deliveryType', () => { - - it('should create a Cloudinary URL with a remote source', () => { - const cloudName = 'customtestcloud'; - const deliveryType = 'fetch'; - const src = 'https://upload.wikimedia.org/wikipedia/commons/4/44/Jelly_cc11.jpg'; - const url = constructCloudinaryUrl({ - options: { - src, - width: 100, - height: 100, - deliveryType - }, - config: { - cloud: { - cloudName - } - } - }); - expect(url).toContain(`https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/f_auto/q_auto/v1/${src}`); - }); - - it('should create a Cloudinary URL from a Cloudinary source', () => { - const cloudName = 'customtestcloud'; - const deliveryType = 'fetch'; - const publicId = 'myimage'; - - const src = `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/f_auto/q_auto/v1234/${publicId}?_a=`; - - const url = constructCloudinaryUrl({ - options: { - src, - width: 100, - height: 100, - deliveryType - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(src); - }); - - it('should create a Cloudinary URL from a non-HTTPS Cloudinary source', () => { - const cloudName = 'customtestcloud'; - const deliveryType = 'fetch'; - const publicId = 'myimage'; - - const src = `res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/f_auto/q_auto/v1234/${publicId}?_a=`; - - const url = constructCloudinaryUrl({ - options: { - src: `http://${src}`, - width: 100, - height: 100, - deliveryType - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(`https://${src}`); - }); - - it('should create a Cloudinary URL from a Cloudinary source with existing URL encoding', () => { - const cloudName = 'customtestcloud'; - const deliveryType = 'upload'; - const publicId = 'my%20pug%20v2'; - - const src = `res.cloudinary.com/${cloudName}/image/${deliveryType}/f_auto/q_auto/v1234/${publicId}?_a=`; - - const url = constructCloudinaryUrl({ - options: { - src: `http://${src}`, - deliveryType - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(`https://${src}`); - }); - - it('should create a Cloudinary URL from a Cloudinary source with spaces and commas', () => { - const cloudName = 'customtestcloud'; - const deliveryType = 'upload'; - const publicId = 'cancun/Lucha libre, Tacos and Beer4'; - const expectedId = 'cancun/Lucha%20libre%2C%20Tacos%20and%20Beer4' - - const url = constructCloudinaryUrl({ - options: { - src: publicId, - deliveryType - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(`https://res.cloudinary.com/${cloudName}/image/${deliveryType}/f_auto/q_auto/v1/${expectedId}?_a`); - }); - }) - - /* SEO */ - - describe('seoSuffix', () => { - - it('should create a Cloudinary URL with an SEO suffix', () => { - const cloudName = 'customtestcloud'; - const publicId = 'myimage'; - const seoSuffix = 'test-image'; - - const src = `https://res.cloudinary.com/${cloudName}/images/c_limit,w_100/f_auto/q_auto/v1234/${publicId}/${seoSuffix}?_a=`; - - const url = constructCloudinaryUrl({ - options: { - src, - width: 100, - height: 100, - seoSuffix - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(src); - }); - - it('should create a Cloudinary URL from a Cloudinary source with SEO prefixes', () => { - const cloudName = 'customtestcloud'; - const assetType = 'images'; - const publicId = 'myimage/my-image'; - const width = 1234; - const height = 1234; - - const src = `https://res.cloudinary.com/${cloudName}/${assetType}/c_limit,w_${width}/f_auto/q_auto/v1234/${publicId}?_a=`; - - const url = constructCloudinaryUrl({ - options: { - src, - width, - height, - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(src); - }); - - it('should create a NON-SEO prefixed Cloudinary URL from a Cloudinary source with SEO prefixes when delivery type is fetch', () => { - const cloudName = 'customtestcloud'; - const assetType = 'images'; - const publicId = 'colby-hug'; - const seoSuffix = 'colby-hug'; - const format = '.jpg'; - const width = 1234; - const height = 1234; - - const src = `https://res.cloudinary.com/${cloudName}/${assetType}/c_limit,w_${width}/f_auto/q_auto/v1234/${publicId}/${seoSuffix}${format}?_i=A`; - const exepectedSrc = `https://res.cloudinary.com/${cloudName}/image/fetch/c_limit,w_${width}/f_auto/q_auto/v1234/${publicId}?_a=` - - const url = constructCloudinaryUrl({ - options: { - src, - width, - height, - deliveryType: 'fetch' - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(exepectedSrc); - }); - - it('should create a Cloudinary URL from a Cloudinary source with SEO prefixes and overriding', () => { - const cloudName = 'customtestcloud'; - const assetType = 'images'; - const publicId = 'myimage'; - const originalSeoSuffix = 'my-image' - const seoSuffix = 'test-image'; - - const src = `https://res.cloudinary.com/${cloudName}/${assetType}/c_limit,w_100/f_auto/q_auto/v1234/${publicId}/${originalSeoSuffix}?_a=`; - - const url = constructCloudinaryUrl({ - options: { - src, - width: 100, - height: 100, - seoSuffix - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(src.replace(originalSeoSuffix, seoSuffix)); - }); - - }); - - /* Versioning */ - - describe('version', () => { - it('should add a custom version to a URL', () => { - const cloudName = 'customtestcloud'; - const version = 1029384756; - - const url = constructCloudinaryUrl({ - options: { - src: 'turtle', - version - }, - config: { - cloud: { - cloudName - } - } - }); - // Only match the analytics version (A) and the ID as the rest is determined - // dynamically by SDK and Next.js version - expect(url).toContain(`/v${version}/`); - }); - - it('should add a default version to a URL', () => { - const cloudName = 'customtestcloud'; - - const url = constructCloudinaryUrl({ - options: { - src: 'turtle', - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(`/v1/`); - }) - }); - - /* Analytics */ - - describe('analytics', () => { - - it('should include an analytics ID at the end of the URL', () => { - const cloudName = 'customtestcloud'; - const expectedId = 'BBAAABDJ0'; - const url = constructCloudinaryUrl({ - options: { - src: 'turtle', - }, - config: { - cloud: { - cloudName - } - }, - analytics: { - sdkCode: 'A', - sdkSemver: '1.0.0', - techVersion: '1.2.3', - product: 'B' - } - }); - expect(url).toContain(`?_a=${expectedId}`); - }); - - it('should include an analytics ID at the end of the URL when using a custom config', () => { - const cloudName = 'customtestcloud'; - const secureDistribution = 'spacejelly.dev'; - const url = constructCloudinaryUrl({ - options: { - src: 'turtle', - }, - config: { - cloud: { - cloudName - }, - url: { - secureDistribution - } - } - }); - expect(url).toContain(`https://${secureDistribution}/${cloudName}`); - }); - - it('should not include an analytics ID with config.url.analytics set to false', () => { - const cloudName = 'customtestcloud'; - const url = constructCloudinaryUrl({ - options: { - src: 'turtle', - }, - config: { - cloud: { - cloudName - }, - url: { - analytics: false - } - }, - analytics: { - sdkCode: 'A', - sdkSemver: '1.0.0', - techVersion: '1.2.3', - product: 'B' - } - }); - expect(url).not.toContain(`?_a`); - }); - - it('should not include an analytics ID with analytics set to false', () => { - const cloudName = 'customtestcloud'; - const url = constructCloudinaryUrl({ - options: { - src: 'turtle', - }, - config: { - cloud: { - cloudName - } - }, - analytics: false - }); - expect(url).not.toContain(`?_a`); - }); - - }); - - /* Raw Transformations */ - - describe('preserveTransformations', () => { - it('should preserve transformations with additional properties', () => { - const cloudName = 'customtestcloud'; - const publicId = 'turtle'; - const version = 1234; - const transformations = ['c_limit,w_100', 'f_auto', 'q_auto']; - const existingUrl = `https://res.cloudinary.com/${cloudName}/image/upload/${transformations.join('/')}/v${version}/${publicId}`; - - const opacity = 12; - const shear = '40:10'; - - const url = constructCloudinaryUrl({ - options: { - src: existingUrl, - opacity, - effects: [{ shear }], - preserveTransformations: true - }, - config: { - cloud: { - cloudName - } - } - }); - expect(url).toContain(`image/upload/${transformations.join('/')}/o_${opacity}/e_shear:${shear}/v${version}/${publicId}`); - }); - }); - - /* Raw Transformations */ - - describe('rawTransformations', () => { - - it('should apply rawTransformations to the beginning of the URL', () => { - const cloudName = 'customtestcloud'; - const src = 'turtle'; - const rawTransformations = ['c_crop,h_359,w_517,x_1483,y_0/c_scale,h_359,w_517']; - const url = constructCloudinaryUrl({ - options: { - src, - rawTransformations - }, - config: { - cloud: { - cloudName - } - } - }); - expect(url).toContain(`image/upload/${rawTransformations.join('/')}/f_auto/q_auto/v1/${src}`); - }); - - it('should not apply f_auto,q_auto if exists in raw transformations', () => { - const cloudName = 'customtestcloud'; - const src = 'turtle'; - const rawTransformations = ['f_auto:animated,q_10']; - - const url = constructCloudinaryUrl({ - options: { - src, - rawTransformations - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(`image/upload/${rawTransformations.join('/')}/v1/${src}`); - }); - - it('should not apply f_auto if exists in raw transformations with / joined segments', () => { - const cloudName = 'customtestcloud'; - const src = 'turtle'; - const width = 960; - const quality = 75; - const rawTransformations = ['c_crop,h_359,w_517,x_1483,y_0/c_scale,h_359,w_517/f_auto,q_auto']; - - const url = constructCloudinaryUrl({ - options: { - src, - width, - quality, - rawTransformations - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain(`image/upload/${rawTransformations.join('/')}/c_limit,w_${width}/q_${quality}/v1/${src}`); - }); - - }) - - /* Strict Transformations */ - - describe('strictTransformations', () => { - - it('should not add any transformations when strict transformations is enabled', () => { - const cloudName = 'customtestcloud'; - const src = 'turtle'; - const url = constructCloudinaryUrl({ - options: { - src, - strictTransformations: true - }, - config: { - cloud: { - cloudName - } - } - }); - expect(url).toContain(`image/upload/${src}`); - }); - - it('should add named transformations when strict transformations is enabled', () => { - const cloudName = 'customtestcloud'; - const src = 'turtle'; - const namedTransformation = 'my-transformation'; - const url = constructCloudinaryUrl({ - options: { - src, - strictTransformations: true, - transformations: [namedTransformation] - }, - config: { - cloud: { - cloudName - } - } - }); - expect(url).toContain(`image/upload/t_${namedTransformation}/${src}`); - }); - - it('should not add any transformations when strict transformations is enabled', () => { - const cloudName = 'customtestcloud'; - const src = 'turtle'; - const url = constructCloudinaryUrl({ - options: { - src, - strictTransformations: true, - removeBackground: true, - effects: [{ - opacity: .5 - }], - version: 2, - width: 960, - height: 600, - widthResize: 1920, - heightResize: 1200 - }, - config: { - cloud: { - cloudName - } - } - }); - expect(url).toContain(`image/upload/${src}?_a=`); - }); - - }) - - /* General Plugins */ - - describe('Plugins', () => { - - it('should not apply an image-only plugin to a video asset', () => { - const cloudName = 'customtestcloud'; - const assetType = 'video'; - const src = 'turtle'; - const zoompan = 'loop'; - const url = constructCloudinaryUrl({ - options: { - src, - assetType, - zoompan - }, - config: { - cloud: { - cloudName - } - } - }); - expect(url).toContain(`${assetType}/upload/f_auto/q_auto/v1/${src}`); - }); - - }) - - /* Effects */ - - it('should apply effects by array', () => { - const cloudName = 'customtestcloud'; - const assetType = 'video'; - const src = 'turtle'; - const shear = '40:0'; - const gradientFade = true; - const opacity = '50'; - const cartoonify = '50'; - const radius = '150'; - const url = constructCloudinaryUrl({ - options: { - src, - assetType, - effects: [ - { - shear, - opacity, - }, - { - gradientFade, - cartoonify, - radius - } - ] - }, - config: { - cloud: { - cloudName - } - } - }); - expect(url).toContain(`${assetType}/upload/o_${opacity},e_shear:${shear}/e_cartoonify:${cartoonify},e_gradient_fade,r_${radius}/f_auto/q_auto/v1/${src}`); - }); - - - /* Kitchen Sink */ - - it('Kitchen Sink - Image', () => { - const cloudName = 'customtestcloud'; - const assetType = 'image'; - - const angle = 15; - const background = 'blue'; - const crop = 'auto'; - const defaultImage = 'my-image.jpg'; - const height = 321; - const src = 'turtle'; - const width = 123; - const zoom = '2.0'; - - const cartoonify = '50'; - const gradientFade = true; - const opacity = '50'; - const radius = '150'; - const shear = '40:0'; - - const overlaySrc = src; - const overlayColor = 'blue'; - const overlayShadow = 100; - const overlayX = 0; - const overlayY = 0; - - const effectsAngle = 'vflip'; - const effectsLoop = 15; - - const url = constructCloudinaryUrl({ - options: { - assetType, - src, - - angle, - background, - defaultImage, - height, - loop: true, - width, - zoom, - - crop: [ - { - type: crop, - height, - width, - zoom, - }, - { - type: crop, - height, - width, - zoom, - source: true - }, - ], - - effects: [ - { - shear, - opacity, - }, - { - gradientFade, - cartoonify, - radius - }, - { - angle: effectsAngle - }, - { - loop: effectsLoop - } - ], - - overlays: [ - { - publicId: overlaySrc, - effects: [ - { - color: overlayColor, - shadow: overlayShadow, - x: overlayX, - y: overlayY - } - ], - appliedEffects: [ - { - color: overlayColor, - shadow: overlayShadow, - x: overlayX, - y: overlayY - } - ], - } - ], - - // Note: removeBackground and restore can't actually be used together - // in practice, but this is simply testing that it works applies correctly - - enhance: true, - extract: { - prompt: 'the woman on the left', - multiple: true, - mode: 'mask', - invert: true - }, - recolor: { - prompt: 'duck', - to: 'blue', - multiple: true - }, - remove: { - prompt: 'apple', - multiple: true, - removeShadow: true - }, - removeBackground: true, - replaceBackground: { - prompt: 'space jellyfish', - seed: 2 - }, - restore: true, - zoompan: true, - }, - config: { - cloud: { - cloudName - } - } - }); - - expect(url).toContain([ - assetType, - `upload`, - 'e_enhance', - 'e_extract:prompt_the%20woman%20on%20the%20left;invert_true;mode_mask;multiple_true', - 'e_gen_recolor:prompt_duck;to-color_blue;multiple_true', - `e_background_removal`, - `e_gen_remove:prompt_apple;multiple_true;remove-shadow_true`, - `e_gen_background_replace:prompt_space%20jellyfish;seed_2`, - `e_gen_restore`, - `c_${crop},w_${width},h_${height},g_auto,z_${zoom}`, - `d_${defaultImage}`, - `a_${angle}`, - `b_${background}`, - `e_loop`, - `o_${opacity},e_shear:${shear}`, - `e_cartoonify:${cartoonify},e_gradient_fade,r_${radius}`, - `a_${effectsAngle}`, - `e_loop:${effectsLoop}`, - `l_${overlaySrc},co_${overlayColor},e_shadow:${overlayShadow},x_${overlayX},y_${overlayY}`, - `fl_layer_apply,fl_no_overflow,co_${overlayColor},e_shadow:${overlayShadow},x_${overlayX},y_${overlayY}`, - `e_zoompan`, - `c_${crop},w_${width},h_${height},g_auto,z_${zoom}`, - `f_auto:animated`, // Effect of zoompan - `q_auto`, - 'v1', - src - ].join('/')); - }); - - - }); -}); diff --git a/packages/url-loader/tests/lib/cloudinary.spec.ts b/packages/url-loader/tests/lib/cloudinary.spec.ts new file mode 100644 index 00000000..0c73f228 --- /dev/null +++ b/packages/url-loader/tests/lib/cloudinary.spec.ts @@ -0,0 +1,1006 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +import { constructCloudinaryUrl } from "../../src/lib/cloudinary.js"; + +// Mock console.warn() so we can see when it's called +global.console = { + ...global.console, + warn: vi.fn(), +}; + +describe("Cloudinary", () => { + afterEach(() => { + // Clears the state of console.warn, in case multiple tests want to monitor it + vi.restoreAllMocks(); + }); + + describe("constructCloudinaryUrl", () => { + it("should create a Cloudinary image URL", () => { + const cloudName = "customtestcloud"; + const url = constructCloudinaryUrl({ + options: { + src: "turtle", + width: 100, + height: 100, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + expect(url).toContain( + `https://res.cloudinary.com/${cloudName}/image/upload/c_limit,w_100/f_auto/q_auto/v1/turtle`, + ); + }); + + it("should create a Cloudinary video URL", () => { + const cloudName = "customtestcloud"; + const assetType = "video"; + const url = constructCloudinaryUrl({ + options: { + assetType, + src: "turtle", + width: 100, + height: 100, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + expect(url).toContain( + `https://res.cloudinary.com/${cloudName}/${assetType}/upload/c_limit,w_100/f_auto/q_auto/v1/turtle`, + ); + }); + + /* Optimization */ + + describe("format, quality, dpr", () => { + it("should create a Cloudinary URL with custom quality and format options", () => { + const format = "png"; + const quality = 75; + const cloudName = "customtestcloud"; + const url = constructCloudinaryUrl({ + options: { + src: "turtle", + width: 100, + height: 100, + format, + quality, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + expect(url).toContain( + `https://res.cloudinary.com/${cloudName}/image/upload/c_limit,w_100/f_${format}/q_${quality}/v1/turtle`, + ); + }); + + it("should not include quality or format in URL", () => { + const cloudName = "customtestcloud"; + const deliveryType = "upload"; + const publicId = "myimage"; + + const src = `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/v1234/${publicId}?_a=`; + + const url = constructCloudinaryUrl({ + options: { + src, + width: 100, + height: 100, + quality: "default", + format: "default", + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain(src); + }); + + it("should include custom DPR as a string", () => { + const cloudName = "customtestcloud"; + const deliveryType = "upload"; + const publicId = "myimage"; + const dpr = "2.0"; + + const src = `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/dpr_${dpr}/f_auto/q_auto/v1/${publicId}?_a=`; + + const url = constructCloudinaryUrl({ + options: { + src: publicId, + width: 100, + height: 100, + dpr, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain(src); + }); + + it("should include custom DPR as number", () => { + const cloudName = "customtestcloud"; + const deliveryType = "upload"; + const publicId = "myimage"; + const dpr = 2; + + const src = `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/dpr_${dpr.toFixed(1)}/f_auto/q_auto/v1/${publicId}?_a=`; + + const url = constructCloudinaryUrl({ + options: { + src: publicId, + width: 100, + height: 100, + dpr, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain(src); + }); + it("should include DPR auto", () => { + const cloudName = "customtestcloud"; + const deliveryType = "upload"; + const publicId = "myimage"; + const dpr = "auto"; + + const src = `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/dpr_${dpr}/f_auto/q_auto/v1/${publicId}?_a=`; + + const url = constructCloudinaryUrl({ + options: { + src: publicId, + width: 100, + height: 100, + dpr, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain(src); + }); + }); + + /* Cropping & Resizing */ + + describe("cropping, resizing", () => { + it("should create a Cloudinary URL with a width, height, and custom crop", () => { + const cloudName = "customtestcloud"; + const deliveryType = "upload"; + const publicId = "myimage"; + const width = 900; + const height = 900; + const crop = "auto"; + + const url = constructCloudinaryUrl({ + options: { + src: publicId, + width, + height, + crop, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + expect(url).toContain( + `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_${crop},w_${width},h_${height},g_auto/f_auto/q_auto/v1/${publicId}`, + ); + }); + + it("should create a Cloudinary URL with a aspect ratio, custom crop, zoom, and default gravity", () => { + const cloudName = "customtestcloud"; + const deliveryType = "upload"; + const publicId = "myimage"; + const aspectRatio = "16:9"; + const crop = "fill"; + const zoom = "1.2"; + + const url = constructCloudinaryUrl({ + options: { + src: publicId, + aspectRatio, + crop, + zoom, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain( + `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_${crop},ar_${aspectRatio},g_auto,z_${zoom}/f_auto/q_auto/v1/${publicId}`, + ); + }); + }); + + /* Delivery */ + + describe("deliveryType", () => { + it("should create a Cloudinary URL with a remote source", () => { + const cloudName = "customtestcloud"; + const deliveryType = "fetch"; + const src = + "https://upload.wikimedia.org/wikipedia/commons/4/44/Jelly_cc11.jpg"; + const url = constructCloudinaryUrl({ + options: { + src, + width: 100, + height: 100, + deliveryType, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + expect(url).toContain( + `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/f_auto/q_auto/v1/${src}`, + ); + }); + + it("should create a Cloudinary URL from a Cloudinary source", () => { + const cloudName = "customtestcloud"; + const deliveryType = "fetch"; + const publicId = "myimage"; + + const src = `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/f_auto/q_auto/v1234/${publicId}?_a=`; + + const url = constructCloudinaryUrl({ + options: { + src, + width: 100, + height: 100, + deliveryType, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain(src); + }); + + it("should create a Cloudinary URL from a non-HTTPS Cloudinary source", () => { + const cloudName = "customtestcloud"; + const deliveryType = "fetch"; + const publicId = "myimage"; + + const src = `res.cloudinary.com/${cloudName}/image/${deliveryType}/c_limit,w_100/f_auto/q_auto/v1234/${publicId}?_a=`; + + const url = constructCloudinaryUrl({ + options: { + src: `http://${src}`, + width: 100, + height: 100, + deliveryType, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain(`https://${src}`); + }); + + it("should create a Cloudinary URL from a Cloudinary source with existing URL encoding", () => { + const cloudName = "customtestcloud"; + const deliveryType = "upload"; + const publicId = "my%20pug%20v2"; + + const src = `res.cloudinary.com/${cloudName}/image/${deliveryType}/f_auto/q_auto/v1234/${publicId}?_a=`; + + const url = constructCloudinaryUrl({ + options: { + src: `http://${src}`, + deliveryType, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain(`https://${src}`); + }); + + it("should create a Cloudinary URL from a Cloudinary source with spaces and commas", () => { + const cloudName = "customtestcloud"; + const deliveryType = "upload"; + const publicId = "cancun/Lucha libre, Tacos and Beer4"; + const expectedId = "cancun/Lucha%20libre%2C%20Tacos%20and%20Beer4"; + + const url = constructCloudinaryUrl({ + options: { + src: publicId, + deliveryType, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain( + `https://res.cloudinary.com/${cloudName}/image/${deliveryType}/f_auto/q_auto/v1/${expectedId}?_a`, + ); + }); + }); + + /* SEO */ + + describe("seoSuffix", () => { + it("should create a Cloudinary URL with an SEO suffix", () => { + const cloudName = "customtestcloud"; + const publicId = "myimage"; + const seoSuffix = "test-image"; + + const src = `https://res.cloudinary.com/${cloudName}/images/c_limit,w_100/f_auto/q_auto/v1234/${publicId}/${seoSuffix}?_a=`; + + const url = constructCloudinaryUrl({ + options: { + src, + width: 100, + height: 100, + seoSuffix, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain(src); + }); + + it("should create a Cloudinary URL from a Cloudinary source with SEO prefixes", () => { + const cloudName = "customtestcloud"; + const assetType = "images"; + const publicId = "myimage/my-image"; + const width = 1234; + const height = 1234; + + const src = `https://res.cloudinary.com/${cloudName}/${assetType}/c_limit,w_${width}/f_auto/q_auto/v1234/${publicId}?_a=`; + + const url = constructCloudinaryUrl({ + options: { + src, + width, + height, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain(src); + }); + + it("should create a NON-SEO prefixed Cloudinary URL from a Cloudinary source with SEO prefixes when delivery type is fetch", () => { + const cloudName = "customtestcloud"; + const assetType = "images"; + const publicId = "colby-hug"; + const seoSuffix = "colby-hug"; + const format = ".jpg"; + const width = 1234; + const height = 1234; + + const src = `https://res.cloudinary.com/${cloudName}/${assetType}/c_limit,w_${width}/f_auto/q_auto/v1234/${publicId}/${seoSuffix}${format}?_i=A`; + const exepectedSrc = `https://res.cloudinary.com/${cloudName}/image/fetch/c_limit,w_${width}/f_auto/q_auto/v1234/${publicId}?_a=`; + + const url = constructCloudinaryUrl({ + options: { + src, + width, + height, + deliveryType: "fetch", + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain(exepectedSrc); + }); + + it("should create a Cloudinary URL from a Cloudinary source with SEO prefixes and overriding", () => { + const cloudName = "customtestcloud"; + const assetType = "images"; + const publicId = "myimage"; + const originalSeoSuffix = "my-image"; + const seoSuffix = "test-image"; + + const src = `https://res.cloudinary.com/${cloudName}/${assetType}/c_limit,w_100/f_auto/q_auto/v1234/${publicId}/${originalSeoSuffix}?_a=`; + + const url = constructCloudinaryUrl({ + options: { + src, + width: 100, + height: 100, + seoSuffix, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain(src.replace(originalSeoSuffix, seoSuffix)); + }); + }); + + /* Versioning */ + + describe("version", () => { + it("should add a custom version to a URL", () => { + const cloudName = "customtestcloud"; + const version = 1029384756; + + const url = constructCloudinaryUrl({ + options: { + src: "turtle", + version, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + // Only match the analytics version (A) and the ID as the rest is determined + // dynamically by SDK and Next.js version + expect(url).toContain(`/v${version}/`); + }); + + it("should add a default version to a URL", () => { + const cloudName = "customtestcloud"; + + const url = constructCloudinaryUrl({ + options: { + src: "turtle", + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain(`/v1/`); + }); + }); + + /* Analytics */ + + describe("analytics", () => { + it("should include an analytics ID at the end of the URL", () => { + const cloudName = "customtestcloud"; + const expectedId = "BBAAABDJ0"; + const url = constructCloudinaryUrl({ + options: { + src: "turtle", + }, + config: { + cloud: { + cloudName, + }, + }, + analytics: { + sdkCode: "A", + sdkSemver: "1.0.0", + techVersion: "1.2.3", + product: "B", + // TODO: Colby IAnalyticsOptions requires feature but was not present + feature: "", + }, + }); + expect(url).toContain(`?_a=${expectedId}`); + }); + + it("should include an analytics ID at the end of the URL when using a custom config", () => { + const cloudName = "customtestcloud"; + const secureDistribution = "spacejelly.dev"; + const url = constructCloudinaryUrl({ + options: { + src: "turtle", + }, + config: { + cloud: { + cloudName, + }, + url: { + secureDistribution, + }, + }, + }); + expect(url).toContain(`https://${secureDistribution}/${cloudName}`); + }); + + it("should not include an analytics ID with config.url.analytics set to false", () => { + const cloudName = "customtestcloud"; + const url = constructCloudinaryUrl({ + options: { + src: "turtle", + }, + config: { + cloud: { + cloudName, + }, + url: { + analytics: false, + }, + }, + analytics: { + sdkCode: "A", + sdkSemver: "1.0.0", + techVersion: "1.2.3", + product: "B", + // TODO: Colby IAnalyticsOptions requires feature but was not present + feature: "", + }, + }); + expect(url).not.toContain(`?_a`); + }); + + it("should not include an analytics ID with analytics set to false", () => { + const cloudName = "customtestcloud"; + const url = constructCloudinaryUrl({ + options: { + src: "turtle", + }, + config: { + cloud: { + cloudName, + }, + }, + analytics: false, + }); + expect(url).not.toContain(`?_a`); + }); + }); + + /* Raw Transformations */ + + describe("preserveTransformations", () => { + it("should preserve transformations with additional properties", () => { + const cloudName = "customtestcloud"; + const publicId = "turtle"; + const version = 1234; + const transformations = ["c_limit,w_100", "f_auto", "q_auto"]; + const existingUrl = `https://res.cloudinary.com/${cloudName}/image/upload/${transformations.join("/")}/v${version}/${publicId}`; + + const opacity = 12; + const shear = "40:10"; + + const url = constructCloudinaryUrl({ + options: { + src: existingUrl, + opacity, + effects: [{ shear }], + preserveTransformations: true, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + expect(url).toContain( + `image/upload/${transformations.join("/")}/o_${opacity}/e_shear:${shear}/v${version}/${publicId}`, + ); + }); + }); + + /* Raw Transformations */ + + describe("rawTransformations", () => { + it("should apply rawTransformations to the beginning of the URL", () => { + const cloudName = "customtestcloud"; + const src = "turtle"; + const rawTransformations = [ + "c_crop,h_359,w_517,x_1483,y_0/c_scale,h_359,w_517", + ]; + const url = constructCloudinaryUrl({ + options: { + src, + rawTransformations, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + expect(url).toContain( + `image/upload/${rawTransformations.join("/")}/f_auto/q_auto/v1/${src}`, + ); + }); + + it("should not apply f_auto,q_auto if exists in raw transformations", () => { + const cloudName = "customtestcloud"; + const src = "turtle"; + const rawTransformations = ["f_auto:animated,q_10"]; + + const url = constructCloudinaryUrl({ + options: { + src, + rawTransformations, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain( + `image/upload/${rawTransformations.join("/")}/v1/${src}`, + ); + }); + + it("should not apply f_auto if exists in raw transformations with / joined segments", () => { + const cloudName = "customtestcloud"; + const src = "turtle"; + const width = 960; + const quality = 75; + const rawTransformations = [ + "c_crop,h_359,w_517,x_1483,y_0/c_scale,h_359,w_517/f_auto,q_auto", + ]; + + const url = constructCloudinaryUrl({ + options: { + src, + width, + quality, + rawTransformations, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain( + `image/upload/${rawTransformations.join("/")}/c_limit,w_${width}/q_${quality}/v1/${src}`, + ); + }); + }); + + /* Strict Transformations */ + + describe("strictTransformations", () => { + it("should not add any transformations when strict transformations is enabled", () => { + const cloudName = "customtestcloud"; + const src = "turtle"; + const url = constructCloudinaryUrl({ + options: { + src, + strictTransformations: true, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + expect(url).toContain(`image/upload/${src}`); + }); + + it("should add named transformations when strict transformations is enabled", () => { + const cloudName = "customtestcloud"; + const src = "turtle"; + const namedTransformation = "my-transformation"; + const url = constructCloudinaryUrl({ + options: { + src, + strictTransformations: true, + transformations: [namedTransformation], + }, + config: { + cloud: { + cloudName, + }, + }, + }); + expect(url).toContain(`image/upload/t_${namedTransformation}/${src}`); + }); + + it("should not add any transformations when strict transformations is enabled", () => { + const cloudName = "customtestcloud"; + const src = "turtle"; + const url = constructCloudinaryUrl({ + options: { + src, + strictTransformations: true, + removeBackground: true, + effects: [ + { + opacity: 0.5, + }, + ], + version: 2, + width: 960, + height: 600, + crop: { + type: "auto", + width: 1920, + height: 1200, + }, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + expect(url).toContain(`image/upload/${src}?_a=`); + }); + }); + + /* General Plugins */ + + describe("Plugins", () => { + it("should not apply an image-only plugin to a video asset", () => { + const cloudName = "customtestcloud"; + const assetType = "video"; + const src = "turtle"; + const zoompan = "loop"; + const url = constructCloudinaryUrl({ + options: { + src, + assetType, + zoompan, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + expect(url).toContain(`${assetType}/upload/f_auto/q_auto/v1/${src}`); + }); + }); + + /* Effects */ + + it("should apply effects by array", () => { + const cloudName = "customtestcloud"; + const assetType = "video"; + const src = "turtle"; + const shear = "40:0"; + const gradientFade = true; + const opacity = "50"; + const cartoonify = "50"; + const radius = "150"; + const url = constructCloudinaryUrl({ + options: { + src, + assetType, + effects: [ + { + shear, + opacity, + }, + { + gradientFade, + cartoonify, + radius, + }, + ], + }, + config: { + cloud: { + cloudName, + }, + }, + }); + expect(url).toContain( + `${assetType}/upload/o_${opacity},e_shear:${shear}/e_cartoonify:${cartoonify},e_gradient_fade,r_${radius}/f_auto/q_auto/v1/${src}`, + ); + }); + + /* Kitchen Sink */ + + it("Kitchen Sink - Image", () => { + const cloudName = "customtestcloud"; + const assetType = "image"; + + const angle = 15; + const background = "blue"; + const crop = "auto"; + const defaultImage = "my-image.jpg"; + const height = 321; + const src = "turtle"; + const width = 123; + const zoom = "2.0"; + + const cartoonify = "50"; + const gradientFade = true; + const opacity = "50"; + const radius = "150"; + const shear = "40:0"; + + const overlaySrc = src; + const overlayColor = "blue"; + const overlayShadow = 100; + const overlayX = 0; + const overlayY = 0; + + const effectsAngle = "vflip"; + const effectsLoop = 15; + + const url = constructCloudinaryUrl({ + options: { + assetType, + src, + + angle, + background, + defaultImage, + height, + loop: true, + width, + zoom, + + crop: [ + { + type: crop, + height, + width, + zoom, + }, + { + type: crop, + height, + width, + zoom, + source: true, + }, + ], + + effects: [ + { + shear, + opacity, + }, + { + gradientFade, + cartoonify, + radius, + }, + { + angle: effectsAngle, + }, + { + loop: effectsLoop, + }, + ], + + overlays: [ + { + publicId: overlaySrc, + effects: [ + { + color: overlayColor, + shadow: overlayShadow, + x: overlayX, + y: overlayY, + }, + ], + appliedEffects: [ + { + color: overlayColor, + shadow: overlayShadow, + x: overlayX, + y: overlayY, + }, + ], + }, + ], + + // Note: removeBackground and restore can't actually be used together + // in practice, but this is simply testing that it works applies correctly + + enhance: true, + extract: { + prompt: "the woman on the left", + multiple: true, + mode: "mask", + invert: true, + }, + recolor: { + prompt: "duck", + to: "blue", + multiple: true, + }, + remove: { + prompt: "apple", + multiple: true, + removeShadow: true, + }, + removeBackground: true, + replaceBackground: { + prompt: "space jellyfish", + seed: 2, + }, + restore: true, + zoompan: true, + }, + config: { + cloud: { + cloudName, + }, + }, + }); + + expect(url).toContain( + [ + assetType, + `upload`, + "e_enhance", + "e_extract:prompt_the%20woman%20on%20the%20left;invert_true;mode_mask;multiple_true", + "e_gen_recolor:prompt_duck;to-color_blue;multiple_true", + `e_background_removal`, + `e_gen_remove:prompt_apple;multiple_true;remove-shadow_true`, + `e_gen_background_replace:prompt_space%20jellyfish;seed_2`, + `e_gen_restore`, + `c_${crop},w_${width},h_${height},g_auto,z_${zoom}`, + `d_${defaultImage}`, + `a_${angle}`, + `b_${background}`, + `e_loop`, + `o_${opacity},e_shear:${shear}`, + `e_cartoonify:${cartoonify},e_gradient_fade,r_${radius}`, + `a_${effectsAngle}`, + `e_loop:${effectsLoop}`, + `l_${overlaySrc},co_${overlayColor},e_shadow:${overlayShadow},x_${overlayX},y_${overlayY}`, + `fl_layer_apply,fl_no_overflow,co_${overlayColor},e_shadow:${overlayShadow},x_${overlayX},y_${overlayY}`, + `e_zoompan`, + `c_${crop},w_${width},h_${height},g_auto,z_${zoom}`, + `f_auto:animated`, // Effect of zoompan + `q_auto`, + "v1", + src, + ].join("/"), + ); + }); + }); +}); diff --git a/packages/url-loader/tests/lib/upload-widget.spec.js b/packages/url-loader/tests/lib/upload-widget.spec.js deleted file mode 100644 index 6a1e1c5f..00000000 --- a/packages/url-loader/tests/lib/upload-widget.spec.js +++ /dev/null @@ -1,117 +0,0 @@ -import { describe, it, expect, vi } from 'vitest'; - -import { getUploadWidgetOptions, generateUploadWidgetResultCallback } from '../../src/lib/upload-widget'; -import { generateSignatureCallback } from '../../src/lib/upload'; - -describe('upload-widget', () => { - describe('getUploadWidgetOptions', () => { - it('should return create an options object for unsigned requests', () => { - const options = { - uploadPreset: 'mypreset' - } - - const config = { - cloud: { - cloudName: 'testcloud', - apiKey: 'abcd1234' - } - }; - - const expectedOptions = { - cloudName: config.cloud.cloudName, - apiKey: config.cloud.apiKey, - uploadPreset: options.uploadPreset - } - - expect(getUploadWidgetOptions(options, config)).toMatchObject(expectedOptions) - }); - - it('should return create an options object with minimal config for signed requests', () => { - const options = { - uploadSignature: generateSignatureCallback({ - signatureEndpoint: '/asdf', - fetch - }) - } - - const config = { - cloud: { - cloudName: 'testcloud', - apiKey: 'abcd1234' - } - }; - - const expectedOptions = { - cloudName: config.cloud.cloudName, - apiKey: config.cloud.apiKey, - uploadSignature: options.uploadSignature - } - - expect(getUploadWidgetOptions(options, config)).toMatchObject(expectedOptions) - }); - }); - - - describe('getUploadWidgetOptions', () => { - it('should generate a callback function and invoke an error', () => { - function onError() {} - - function onResult() {} - - function onSuccess() {} - - const options = { - onError, - onResult, - onSuccess - } - - const spyError = vi.spyOn(options, 'onError'); - const spyResult = vi.spyOn(options, 'onResult'); - const spySuccess = vi.spyOn(options, 'onSuccess'); - - const resultCallback = generateUploadWidgetResultCallback(options); - - const error = 'Error'; - const result = {}; - - resultCallback(error, result); - - expect(spyError).toHaveBeenCalledWith(error, result); - expect(spyResult).toHaveBeenCalledWith(result); - expect(spySuccess).not.toHaveBeenCalled(result); - }); - - it('should generate a callback function and invoke results on success', () => { - function onError() {} - - function onResult() {} - - function onSuccess() {} - - const options = { - onError, - onResult, - onSuccess - } - - const spyError = vi.spyOn(options, 'onError'); - const spyResult = vi.spyOn(options, 'onResult'); - const spySuccess = vi.spyOn(options, 'onSuccess'); - - const resultCallback = generateUploadWidgetResultCallback(options); - - const result = { - event: 'success', - info: {} - }; - - resultCallback(null, result); - - expect(spyError).not.toHaveBeenCalled(result); - expect(spyResult).toHaveBeenCalledWith(result); - expect(spySuccess).toHaveBeenCalledWith(result); - }); - }); - -}); \ No newline at end of file diff --git a/packages/url-loader/tests/lib/upload-widget.spec.ts b/packages/url-loader/tests/lib/upload-widget.spec.ts new file mode 100644 index 00000000..5ac20aa7 --- /dev/null +++ b/packages/url-loader/tests/lib/upload-widget.spec.ts @@ -0,0 +1,121 @@ +import { describe, expect, it, vi } from "vitest"; + +import { + generateUploadWidgetResultCallback, + getUploadWidgetOptions, +} from "../../src/lib/upload-widget.js"; +import { generateSignatureCallback } from "../../src/lib/upload.js"; + +describe("upload-widget", () => { + describe("getUploadWidgetOptions", () => { + it("should return create an options object for unsigned requests", () => { + const options = { + uploadPreset: "mypreset", + }; + + const config = { + cloud: { + cloudName: "testcloud", + apiKey: "abcd1234", + }, + }; + + const expectedOptions = { + cloudName: config.cloud.cloudName, + apiKey: config.cloud.apiKey, + uploadPreset: options.uploadPreset, + }; + + expect(getUploadWidgetOptions(options, config)).toMatchObject( + expectedOptions, + ); + }); + + it("should return create an options object with minimal config for signed requests", () => { + const options = { + uploadSignature: generateSignatureCallback({ + signatureEndpoint: "/asdf", + fetch, + }), + }; + + const config = { + cloud: { + cloudName: "testcloud", + apiKey: "abcd1234", + }, + }; + + const expectedOptions = { + cloudName: config.cloud.cloudName, + apiKey: config.cloud.apiKey, + uploadSignature: options.uploadSignature, + }; + + expect(getUploadWidgetOptions(options, config)).toMatchObject( + expectedOptions, + ); + }); + }); + + describe("getUploadWidgetOptions", () => { + it("should generate a callback function and invoke an error", () => { + function onError() {} + + function onResult() {} + + function onSuccess() {} + + const options = { + onError, + onResult, + onSuccess, + }; + + const spyError = vi.spyOn(options, "onError"); + const spyResult = vi.spyOn(options, "onResult"); + const spySuccess = vi.spyOn(options, "onSuccess"); + + const resultCallback = generateUploadWidgetResultCallback(options); + + const error = "Error"; + const result = {}; + + resultCallback(error, result); + + expect(spyError).toHaveBeenCalledWith(error, result); + expect(spyResult).toHaveBeenCalledWith(result); + expect(spySuccess).not.toHaveBeenCalled(); + }); + + it("should generate a callback function and invoke results on success", () => { + function onError() {} + + function onResult() {} + + function onSuccess() {} + + const options = { + onError, + onResult, + onSuccess, + }; + + const spyError = vi.spyOn(options, "onError"); + const spyResult = vi.spyOn(options, "onResult"); + const spySuccess = vi.spyOn(options, "onSuccess"); + + const resultCallback = generateUploadWidgetResultCallback(options); + + const result = { + event: "success", + }; + + resultCallback(null, result); + + expect(spyError).not.toHaveBeenCalled(); + expect(spyResult).toHaveBeenCalledWith(result); + expect(spySuccess).toHaveBeenCalledWith(result); + }); + }); +}); diff --git a/packages/url-loader/tests/lib/upload.spec.js b/packages/url-loader/tests/lib/upload.spec.js deleted file mode 100644 index 0339bfee..00000000 --- a/packages/url-loader/tests/lib/upload.spec.js +++ /dev/null @@ -1,47 +0,0 @@ -import { describe, it, expect } from 'vitest'; - -import { generateSignatureCallback } from '../../src/lib/upload'; - -describe('upload', () => { - describe('generateSignatureCallback', () => { - it('should generate a signature callback function', async () => { - let results = undefined; - - const paramsToSign = { - uploadPreset: 'mypreset', - timestamp: Date.now() - } - - // this isn't really the signature's signature, just an easy way to test as a string - - const signature = JSON.stringify(paramsToSign); - - async function fetcher() { - return { - json: async () => { - return { - signature - } - } - } - } - - const signatureCallback = generateSignatureCallback({ - signatureEndpoint: '/asdf', - fetch: fetcher - }) - - function callback(signature) { - results = signature; - } - - const options = { - callback - } - - signatureCallback(options.callback, paramsToSign) - - await expect.poll(() => results).toBe(signature); - }); - }); -}); \ No newline at end of file diff --git a/packages/url-loader/tests/lib/upload.spec.ts b/packages/url-loader/tests/lib/upload.spec.ts new file mode 100644 index 00000000..faa3ef0e --- /dev/null +++ b/packages/url-loader/tests/lib/upload.spec.ts @@ -0,0 +1,47 @@ +import { describe, expect, it } from "vitest"; + +import { generateSignatureCallback } from "../../src/lib/upload.js"; + +describe("upload", () => { + describe("generateSignatureCallback", () => { + it("should generate a signature callback function", async () => { + let results: unknown = undefined; + + const paramsToSign = { + uploadPreset: "mypreset", + timestamp: Date.now(), + }; + + // this isn't really the signature's signature, just an easy way to test as a string + + const signature = JSON.stringify(paramsToSign); + + async function fetcher() { + return { + json: async () => { + return { + signature, + }; + }, + }; + } + + const signatureCallback = generateSignatureCallback({ + signatureEndpoint: "/asdf", + fetch: fetcher, + }); + + function callback(signature: unknown) { + results = signature; + } + + const options = { + callback, + }; + + signatureCallback(options.callback, paramsToSign); + + await expect.poll(() => results).toBe(signature); + }); + }); +}); diff --git a/packages/url-loader/tests/lib/video-player.spec.js b/packages/url-loader/tests/lib/video-player.spec.js deleted file mode 100644 index 8f8f9657..00000000 --- a/packages/url-loader/tests/lib/video-player.spec.js +++ /dev/null @@ -1,270 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { getVideoPlayerOptions } from '../../src/lib/video-player'; - -describe('video-player', () => { - describe('getVideoPlayerOptions', () => { - describe('Basic', () => { - it('should return create an options object with minimal config', () => { - const options = { - width: '1620', - height: '1080', - src: 'videos/mountain-stars', - } - - const config = { - cloud: { - cloudName: 'testcloud' - } - }; - - const expectedOptions = { - aspectRatio: '1620:1080', - autoplay: false, - autoplayMode: undefined, - cloud_name: 'testcloud', - controls: true, - height: '1080', - language: undefined, - languages: undefined, - loop: false, - muted: false, - privateCdn: undefined, - publicId: 'videos/mountain-stars', - secureDistribution: undefined, - showLogo: true, - transformation: [ - { quality: 'auto' }, - undefined - ], - width: '1620', - } - - expect(getVideoPlayerOptions(options, config)).toMatchObject(expectedOptions) - }); - - it('should return create an options object without a width or height', () => { - const options = { - src: 'videos/mountain-stars', - } - - const config = { - cloud: { - cloudName: 'testcloud' - } - }; - - const expectedOptions = { - autoplay: false, - autoplayMode: undefined, - cloud_name: 'testcloud', - controls: true, - language: undefined, - languages: undefined, - loop: false, - muted: false, - privateCdn: undefined, - publicId: 'videos/mountain-stars', - secureDistribution: undefined, - showLogo: true, - transformation: [ - { quality: 'auto' }, - undefined - ], - } - - const playerOptions = getVideoPlayerOptions(options, config); - - expect(playerOptions).toMatchObject(expectedOptions); - expect(playerOptions.width).toBeUndefined(); - expect(playerOptions.height).toBeUndefined(); - expect(playerOptions.aspectRatio).toBeUndefined(); - }); - - it('should return create an options object with only an aspect ratio', () => { - const options = { - src: 'videos/mountain-stars', - aspectRatio: '16:9' - } - - const config = { - cloud: { - cloudName: 'testcloud' - } - }; - - const expectedOptions = { - aspectRatio: options.aspectRatio, - autoplay: false, - autoplayMode: undefined, - cloud_name: 'testcloud', - controls: true, - language: undefined, - languages: undefined, - loop: false, - muted: false, - privateCdn: undefined, - publicId: 'videos/mountain-stars', - secureDistribution: undefined, - showLogo: true, - transformation: [ - { quality: 'auto' }, - undefined - ], - } - - const playerOptions = getVideoPlayerOptions(options, config); - - expect(playerOptions).toMatchObject(expectedOptions); - expect(playerOptions.width).toBeUndefined(); - expect(playerOptions.height).toBeUndefined(); - }); - - it('should configure custom quality', () => { - const options = { - width: '1620', - height: '1080', - src: 'videos/mountain-stars', - quality: 50, - } - - const config = { - cloud: { - cloudName: 'testcloud' - } - }; - - expect(getVideoPlayerOptions(options, config)).toMatchObject({ - transformation: [ - { quality: options.quality }, - undefined - ], - }) - }); - }) - - describe('Playback', () => { - it('should configure ABR via source types', () => { - const options = { - width: '1620', - height: '1080', - src: 'videos/mountain-stars', - transformation: { - streaming_profile: 'hd', - }, - sourceTypes: ['hls'], - } - - const config = { - cloud: { - cloudName: 'testcloud' - } - }; - - expect(getVideoPlayerOptions(options, config)).toMatchObject({ - transformation: [ - { quality: 'auto' }, - { streaming_profile: 'hd' } - ], - sourceTypes: ['hls'], - }); - }); - }) - - describe('Customization', () => { - it('should configure custom logo and colors', () => { - const options = { - width: '1620', - height: '1080', - src: 'videos/mountain-stars', - fontFace: 'Colby', - logo: { - imageUrl: 'https://image.com', - onClickUrl: 'https://spacejelly.dev' - }, - colors: { - accent: '#ff0000', - base: '#00ff00', - text: '#0000ff' - } - } - - const config = { - cloud: { - cloudName: 'testcloud' - } - }; - - expect(getVideoPlayerOptions(options, config)).toMatchObject({ - fontFace: options.fontFace, - logoImageUrl: options.logo.imageUrl, - logoOnclickUrl: options.logo.onClickUrl, - showLogo: true, - colors: options.colors - }); - }); - - it('should set a custom poster using a string', () => { - const options = { - width: '1620', - height: '1080', - src: 'videos/mountain-stars', - poster: 'string' - } - - const config = { - cloud: { - cloudName: 'testcloud' - } - }; - - const playerOptions = getVideoPlayerOptions(options, config); - - expect(playerOptions.posterOptions.publicId).toContain(options.poster) - }); - - it('should set a custom poster using constructCloudinaryUrl options syntax with public ID inherited', () => { - const options = { - width: '1620', - height: '1080', - src: 'videos/mountain-stars', - poster: { - tint: 'equalize:80:blue:blueviolet' - } - } - - const config = { - cloud: { - cloudName: 'testcloud' - } - }; - - const playerOptions = getVideoPlayerOptions(options, config); - - expect(playerOptions.posterOptions.publicId).toContain(`https://res.cloudinary.com/${config.cloud.cloudName}/video/upload/e_tint:${options.poster.tint}/f_auto:image/q_auto/v1/${options.src}`); - }); - - it('should set a custom poster using constructCloudinaryUrl options syntax with custom thumb public ID', () => { - const options = { - width: '1620', - height: '1080', - src: 'videos/mountain-stars', - poster: { - src: 'my-custom-public-id', - tint: 'equalize:80:blue:blueviolet' - } - } - - const config = { - cloud: { - cloudName: 'testcloud' - } - }; - - const playerOptions = getVideoPlayerOptions(options, config); - - expect(playerOptions.posterOptions.publicId).toContain(`https://res.cloudinary.com/${config.cloud.cloudName}/image/upload/e_tint:${options.poster.tint}/f_auto/q_auto/v1/${options.poster.src}`); - }); - }) - }); -}); \ No newline at end of file diff --git a/packages/url-loader/tests/lib/video-player.spec.ts b/packages/url-loader/tests/lib/video-player.spec.ts new file mode 100644 index 00000000..e2a689d6 --- /dev/null +++ b/packages/url-loader/tests/lib/video-player.spec.ts @@ -0,0 +1,261 @@ +import { describe, expect, it } from "vitest"; + +import { getVideoPlayerOptions } from "../../src/lib/video-player.js"; + +describe("video-player", () => { + describe("getVideoPlayerOptions", () => { + describe("Basic", () => { + it("should return create an options object with minimal config", () => { + const options = { + width: "1620", + height: "1080", + src: "videos/mountain-stars", + }; + + const config = { + cloud: { + cloudName: "testcloud", + }, + }; + + const expectedOptions = { + aspectRatio: "1620:1080", + autoplay: false, + autoplayMode: undefined, + cloud_name: "testcloud", + controls: true, + height: "1080", + language: undefined, + languages: undefined, + loop: false, + muted: false, + privateCdn: undefined, + publicId: "videos/mountain-stars", + secureDistribution: undefined, + showLogo: true, + transformation: [{ quality: "auto" }, undefined], + width: "1620", + }; + + expect(getVideoPlayerOptions(options, config)).toMatchObject( + expectedOptions, + ); + }); + + it("should return create an options object without a width or height", () => { + const options = { + src: "videos/mountain-stars", + }; + + const config = { + cloud: { + cloudName: "testcloud", + }, + }; + + const expectedOptions = { + autoplay: false, + autoplayMode: undefined, + cloud_name: "testcloud", + controls: true, + language: undefined, + languages: undefined, + loop: false, + muted: false, + privateCdn: undefined, + publicId: "videos/mountain-stars", + secureDistribution: undefined, + showLogo: true, + transformation: [{ quality: "auto" }, undefined], + }; + + const playerOptions = getVideoPlayerOptions(options, config); + + expect(playerOptions).toMatchObject(expectedOptions); + expect(playerOptions.width).toBeUndefined(); + expect(playerOptions.height).toBeUndefined(); + expect(playerOptions.aspectRatio).toBeUndefined(); + }); + + it("should return create an options object with only an aspect ratio", () => { + const options = { + src: "videos/mountain-stars", + aspectRatio: "16:9", + }; + + const config = { + cloud: { + cloudName: "testcloud", + }, + }; + + const expectedOptions = { + aspectRatio: options.aspectRatio, + autoplay: false, + autoplayMode: undefined, + cloud_name: "testcloud", + controls: true, + language: undefined, + languages: undefined, + loop: false, + muted: false, + privateCdn: undefined, + publicId: "videos/mountain-stars", + secureDistribution: undefined, + showLogo: true, + transformation: [{ quality: "auto" }, undefined], + }; + + const playerOptions = getVideoPlayerOptions(options, config); + + expect(playerOptions).toMatchObject(expectedOptions); + expect(playerOptions.width).toBeUndefined(); + expect(playerOptions.height).toBeUndefined(); + }); + + it("should configure custom quality", () => { + const options = { + width: "1620", + height: "1080", + src: "videos/mountain-stars", + quality: 50, + }; + + const config = { + cloud: { + cloudName: "testcloud", + }, + }; + + expect(getVideoPlayerOptions(options, config)).toMatchObject({ + transformation: [{ quality: options.quality }, undefined], + }); + }); + }); + + describe("Playback", () => { + it("should configure ABR via source types", () => { + const options = { + width: "1620", + height: "1080", + src: "videos/mountain-stars", + transformation: { + streaming_profile: "hd", + }, + sourceTypes: ["hls"], + }; + + const config = { + cloud: { + cloudName: "testcloud", + }, + }; + + expect(getVideoPlayerOptions(options, config)).toMatchObject({ + transformation: [{ quality: "auto" }, { streaming_profile: "hd" }], + sourceTypes: ["hls"], + }); + }); + }); + + describe("Customization", () => { + it("should configure custom logo and colors", () => { + const options = { + width: "1620", + height: "1080", + src: "videos/mountain-stars", + fontFace: "Colby", + logo: { + imageUrl: "https://image.com", + onClickUrl: "https://spacejelly.dev", + }, + colors: { + accent: "#ff0000", + base: "#00ff00", + text: "#0000ff", + }, + }; + + const config = { + cloud: { + cloudName: "testcloud", + }, + }; + + expect(getVideoPlayerOptions(options, config)).toMatchObject({ + fontFace: options.fontFace, + logoImageUrl: options.logo.imageUrl, + logoOnclickUrl: options.logo.onClickUrl, + showLogo: true, + colors: options.colors, + }); + }); + + it("should set a custom poster using a string", () => { + const options = { + width: "1620", + height: "1080", + src: "videos/mountain-stars", + poster: "string", + }; + + const config = { + cloud: { + cloudName: "testcloud", + }, + }; + + const playerOptions = getVideoPlayerOptions(options, config); + + expect(playerOptions.posterOptions?.publicId).toContain(options.poster); + }); + + it("should set a custom poster using constructCloudinaryUrl options syntax with public ID inherited", () => { + const options = { + width: "1620", + height: "1080", + src: "videos/mountain-stars", + poster: { + tint: "equalize:80:blue:blueviolet", + }, + }; + + const config = { + cloud: { + cloudName: "testcloud", + }, + }; + + const playerOptions = getVideoPlayerOptions(options, config); + + expect(playerOptions.posterOptions?.publicId).toContain( + `https://res.cloudinary.com/${config.cloud.cloudName}/video/upload/e_tint:${options.poster.tint}/f_auto:image/q_auto/v1/${options.src}`, + ); + }); + + it("should set a custom poster using constructCloudinaryUrl options syntax with custom thumb public ID", () => { + const options = { + width: "1620", + height: "1080", + src: "videos/mountain-stars", + poster: { + src: "my-custom-public-id", + tint: "equalize:80:blue:blueviolet", + }, + }; + + const config = { + cloud: { + cloudName: "testcloud", + }, + }; + + const playerOptions = getVideoPlayerOptions(options, config); + + expect(playerOptions.posterOptions?.publicId).toContain( + `https://res.cloudinary.com/${config.cloud.cloudName}/image/upload/e_tint:${options.poster.tint}/f_auto/q_auto/v1/${options.poster.src}`, + ); + }); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/abr.spec.js b/packages/url-loader/tests/plugins/abr.spec.js deleted file mode 100644 index 696ccda1..00000000 --- a/packages/url-loader/tests/plugins/abr.spec.js +++ /dev/null @@ -1,40 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; - -import { abrPlugin } from '../../src/plugins/abr'; - -const { plugin } = abrPlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -describe('Plugins', () => { - describe('ABR', () => { - it('should include sp_auto on a video with streamingProfile of auto', () => { - const src = 'turtle.mp4'; - const cldVideo = cld.video(src); - const streamingProfile = 'auto'; - plugin({ cldAsset: cldVideo, options: { - assetType: 'video', - src, - streamingProfile - } }); - expect(cldVideo.toURL()).toContain(`video/upload/sp_${streamingProfile}/${src}`); - }); - - it('should include streamingProfile with subtitles', () => { - const src = 'turtle.mp4'; - const streamingProfile = 'sd:subtitles_((code_en-US;file_outdoors.vtt);(code_es-ES;file_outdoors-es.vtt))'; - const cldVideo = cld.video(src); - plugin({ cldAsset: cldVideo, options: { - assetType: 'video', - src, - streamingProfile - } }); - expect(cldVideo.toURL()).toContain(`video/upload/sp_${streamingProfile}/${src}`); - }); - }); -}); diff --git a/packages/url-loader/tests/plugins/abr.spec.ts b/packages/url-loader/tests/plugins/abr.spec.ts new file mode 100644 index 00000000..977c159e --- /dev/null +++ b/packages/url-loader/tests/plugins/abr.spec.ts @@ -0,0 +1,43 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { AbrPlugin } from "../../src/plugins/abr.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +describe("Plugins", () => { + describe("ABR", () => { + it("should include sp_auto on a video with streamingProfile of auto", () => { + const src = "turtle.mp4"; + const cldVideo = cld.video(src); + const streamingProfile = "auto"; + AbrPlugin.apply(cldVideo, { + assetType: "video", + src, + streamingProfile, + }); + expect(cldVideo.toURL()).toContain( + `video/upload/sp_${streamingProfile}/${src}`, + ); + }); + + it("should include streamingProfile with subtitles", () => { + const src = "turtle.mp4"; + const streamingProfile = + "sd:subtitles_((code_en-US;file_outdoors.vtt);(code_es-ES;file_outdoors-es.vtt))"; + const cldVideo = cld.video(src); + AbrPlugin.apply(cldVideo, { + assetType: "video", + src, + streamingProfile, + }); + expect(cldVideo.toURL()).toContain( + `video/upload/sp_${streamingProfile}/${src}`, + ); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/cropping.spec.js b/packages/url-loader/tests/plugins/cropping.spec.js deleted file mode 100644 index e67c5aa0..00000000 --- a/packages/url-loader/tests/plugins/cropping.spec.js +++ /dev/null @@ -1,304 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; - -import { croppingPlugin } from '../../src/plugins/cropping'; - -const { plugin } = croppingPlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -const TEST_PUBLIC_ID = 'test-public-id'; - -describe('Cropping plugin', () => { - it('should apply a crop and gravity to a URL', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 100, - height: 100, - crop: 'crop', - gravity: 'auto' - }; - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toContain(`c_${options.crop},w_${options.width},h_${options.height},g_${options.gravity}`); - }); - - it('should apply a gravity of auto by default if not set explicitly', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 100, - height: 100, - crop: 'fill' - }; - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toContain(`c_${options.crop},w_${options.width},h_${options.height},g_auto`); - }); - - it('should apply a zoom if set explicitly', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 100, - height: 100, - crop: 'fill', - zoom: 0.5 - }; - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toContain(`c_${options.crop},w_${options.width},h_${options.height},g_auto,z_${options.zoom}`); - }); - - it('should not include a width if not set', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = {}; - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toBeUndefined(); - }); - - it('should crop as thumb instead of default with object syntax, width, and height', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 900, - crop: { - width: 100, - height: 200, - type: 'thumb' - } - }; - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toContain(`c_${options.crop.type},w_${options.crop.width},h_${options.crop.height},g_auto`); - }); - - it('should crop as thumb instead of default with object syntax with width inferred', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 900, - height: 600, - crop: { - type: 'thumb' - } - }; - - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toContain(`c_${options.crop.type},w_${options.width},h_${options.height},g_auto`); - }); - - it('should crop as thumb in 2 stages with width inferred', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 900, - height: 600, - crop: { - type: 'thumb', - source: true - } - }; - - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toContain(`c_limit,w_${options.width}`); - expect(cldImage.toURL()).toContain(`image/upload/c_${options.crop.type},w_${options.width},h_${options.height},g_auto`); - }); - - it('should crop as thumb in 2 stages with aspect ratio', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 900, - height: 600, - crop: { - type: 'thumb', - aspectRatio: '16:9', - source: true - } - }; - - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - - expect(resize).toContain(`c_limit,w_${options.width}`); - expect(cldImage.toURL()).toContain(`image/upload/c_${options.crop.type},ar_${options.crop.aspectRatio},g_auto`); - }); - - it('should resize based on crop parameter', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 900, - crop: { - width: 600 - } - }; - - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - - expect(resize).toContain(`c_limit,w_${options.crop.width}`); - }); - - it('should resize in two stages', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 900, - crop: { - width: 600, - height: 500, - type: 'thumb', - source: true - } - }; - - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - - expect(resize).toContain(`c_limit,w_${options.width}`); - expect(cldImage.toURL()).toContain(`image/upload/c_${options.crop.type},w_${options.crop.width},h_${options.crop.height},g_auto`); - }); - - it('should crop in two stages with array of single configuration', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - height: 5678, - width: 1234, - crop: [{ - type: 'auto', - height: 8765, - width: 4321, - zoom: 3, - gravity: 'center' - }] - }; - - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - - expect(resize).toContain(`c_${options.crop[0].type},w_${options.crop[0].width},h_${options.crop[0].height},g_${options.crop[0].gravity},z_${options.crop[0].zoom}`); - }); - - it('should crop in two stages with array configurations inferring width/height', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - height: 5678, - width: 1234, - crop: [ - { - type: 'thumb', - source: true - }, - { - type: 'scale' - } - ] - }; - - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - - expect(resize).toContain(`c_${options.crop[1].type},w_${options.width},h_${options.height}`); - - expect(cldImage.toURL()).toContain(`image/upload/c_${options.crop[0].type},w_${options.width},h_${options.height},g_auto`); - }); - - it('should not apply a height when crop is fill if isnt set', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 100, - crop: 'fill', - }; - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toContain(`c_${options.crop},w_${options.width},g_auto`); - }); - - it('should apply aspect ratio as a string and valid crop', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - aspectRatio: '16:9', - crop: 'fill' - }; - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toContain(`c_fill,ar_16:9,g_auto`); - }); - - it('should apply aspect ratio as a float and valid crop', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - aspectRatio: .5, - crop: 'fill' - }; - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - // for my own sanity that float => string will add the leading 0 - expect(`${options.aspectRatio}`).toMatch('0.5'); - expect(resize).toContain(`c_fill,ar_${options.aspectRatio},g_auto`); - }); - - it('should not apply aspect ratio if not a valid crop', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - aspectRatio: '16:9', - crop: 'fit' - }; - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toBeUndefined(); - }); - - it('should apply coordinates-based cropping with x and y with no default gravity', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 123, - height: 321, - crop: { - type: 'crop', - x: 50, - y: 100 - } - }; - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toBe(`c_${options.crop.type},w_${options.width},h_${options.height},x_${options.crop.x},y_${options.crop.y}`); - }); - - it('should apply coordinates-based cropping with custom gravity', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 123, - height: 321, - crop: { - type: 'crop', - x: 4321, - y: 1234, - gravity: 'south' - } - }; - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toBe(`c_${options.crop.type},w_${options.width},h_${options.height},x_${options.crop.x},y_${options.crop.y},g_${options.crop.gravity}`); - }); - - it('should apply coordinates-based cropping with custom width and height', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 123, - height: 321, - crop: { - type: 'crop', - x: 100, - y: 100, - width: 567, - height: 765, - gravity: 'south' - } - }; - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toBe(`c_${options.crop.type},w_${options.crop.width},h_${options.crop.height},x_${options.crop.x},y_${options.crop.y},g_${options.crop.gravity}`); - }); - - it('should crop by coordinates in 2 stages with width', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 900, - height: 600, - crop: { - type: 'fill', - x: 5687, - y: 6543, - source: true - } - }; - - const { options: { resize } } = plugin({ cldAsset: cldImage, options }); - expect(resize).toContain(`c_limit,w_${options.width}`); - expect(cldImage.toURL()).toContain(`image/upload/c_${options.crop.type},w_${options.width},h_${options.height},x_${options.crop.x},y_${options.crop.y}`); - }); -}); - diff --git a/packages/url-loader/tests/plugins/cropping.spec.ts b/packages/url-loader/tests/plugins/cropping.spec.ts new file mode 100644 index 00000000..45c4a482 --- /dev/null +++ b/packages/url-loader/tests/plugins/cropping.spec.ts @@ -0,0 +1,414 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { CroppingPlugin } from "../../src/plugins/cropping.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Cropping plugin", () => { + it("should apply a crop and gravity to a URL", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 100, + height: 100, + crop: "crop", + gravity: "auto", + } as const; + const result = CroppingPlugin.apply(cldImage, options); + expect(result.options?.resize).toContain( + `c_${options.crop},w_${options.width},h_${options.height},g_${options.gravity}`, + ); + }); + + it("should apply a gravity of auto by default if not set explicitly", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 100, + height: 100, + crop: "fill", + } as const; + const result = CroppingPlugin.apply(cldImage, options); + expect(result.options?.resize).toContain( + `c_${options.crop},w_${options.width},h_${options.height},g_auto`, + ); + }); + + it("should apply a zoom if set explicitly", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 100, + height: 100, + crop: "fill", + zoom: 0.5, + } as const; + const result = CroppingPlugin.apply(cldImage, options); + expect(result.options?.resize).toContain( + `c_${options.crop},w_${options.width},h_${options.height},g_auto,z_${options.zoom}`, + ); + }); + + it("should not include a width if not set", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + } as const; + const result = CroppingPlugin.apply(cldImage, options); + expect(result.options?.resize).toBeUndefined(); + }); + + it("should crop as thumb instead of default with object syntax, width, and height", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 900, + crop: { + width: 100, + height: 200, + type: "thumb", + }, + } as const; + + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options?.resize).toContain( + `c_${options.crop.type},w_${options.crop.width},h_${options.crop.height},g_auto`, + ); + }); + + it("should crop as thumb instead of default with object syntax with width inferred", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 900, + height: 600, + crop: { + type: "thumb", + }, + } as const; + + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options?.resize as string).toContain( + `c_${options.crop.type},w_${options.width},h_${options.height},g_auto`, + ); + }); + + it("should crop as thumb in 2 stages with width inferred", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 900, + height: 600, + crop: { + type: "thumb", + source: true, + }, + } as const; + + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options.resize).toContain(`c_limit,w_${options.width}`); + expect(cldImage.toURL()).toContain( + `image/upload/c_${options.crop.type},w_${options.width},h_${options.height},g_auto`, + ); + }); + + it("should crop as thumb in 2 stages with aspect ratio", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 900, + height: 600, + crop: { + type: "thumb", + aspectRatio: "16:9", + source: true, + }, + } as const; + + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options.resize).toContain(`c_limit,w_${options.width}`); + expect(cldImage.toURL()).toContain( + `image/upload/c_${options.crop.type},ar_${options.crop.aspectRatio},g_auto`, + ); + }); + + it("should resize based on crop parameter", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 900, + crop: { + type: "limit", + width: 600, + }, + } as const; + + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options?.resize).toContain(`c_limit,w_${options.crop.width}`); + }); + + it("should resize in two stages", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 900, + crop: { + width: 600, + height: 500, + type: "thumb", + source: true, + }, + } as const; + + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options?.resize).toContain(`c_limit,w_${options.width}`); + expect(cldImage.toURL()).toContain( + `image/upload/c_${options.crop.type},w_${options.crop.width},h_${options.crop.height},g_auto`, + ); + }); + + it("should crop in two stages with array of single configuration", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + height: 5678, + width: 1234, + crop: [ + { + type: "auto", + height: 8765, + width: 4321, + zoom: 3, + gravity: "center", + }, + ], + } as const; + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options.resize).toContain( + `c_${options.crop[0].type},w_${options.crop[0].width},h_${options.crop[0].height},g_${options.crop[0].gravity},z_${options.crop[0].zoom}`, + ); + }); + + it("should crop in two stages with array configurations inferring width/height", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + height: 5678, + width: 1234, + crop: [ + { + type: "thumb", + source: true, + }, + { + type: "scale", + }, + ], + } as const; + + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options.resize).toContain( + `c_${options.crop[1].type},w_${options.width},h_${options.height}`, + ); + expect(cldImage.toURL()).toContain( + `image/upload/c_${options.crop[0].type},w_${options.width},h_${options.height},g_auto`, + ); + }); + + it("should not apply a height when crop is fill if isnt set", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 100, + crop: "fill", + } as const; + + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options?.resize).toContain( + `c_${options.crop},w_${options.width},g_auto`, + ); + }); + + it("should apply aspect ratio as a string and valid crop", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + aspectRatio: "16:9", + crop: "fill", + } as const; + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options?.resize).toContain(`c_fill,ar_16:9,g_auto`); + }); + + it("should apply aspect ratio as a float and valid crop", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + aspectRatio: 0.5, + crop: "fill", + } as const; + const result = CroppingPlugin.apply(cldImage, options); + // for my own sanity that float => string will add the leading 0 + expect(`${options.aspectRatio}`).toMatch("0.5"); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options?.resize).toContain( + `c_fill,ar_${options.aspectRatio},g_auto`, + ); + }); + + it("should not apply aspect ratio if not a valid crop", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + aspectRatio: "16:9", + crop: "fit", + } as const; + const result = CroppingPlugin.apply(cldImage, options); + + expect(result.options?.resize).toBeUndefined(); + }); + + it("should apply coordinates-based cropping with x and y with no default gravity", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 123, + height: 321, + crop: { + type: "crop", + x: 50, + y: 100, + }, + } as const; + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options?.resize).toBe( + `c_${options.crop.type},w_${options.width},h_${options.height},x_${options.crop.x},y_${options.crop.y}`, + ); + }); + + it("should apply coordinates-based cropping with custom gravity", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 123, + height: 321, + crop: { + type: "crop", + x: 4321, + y: 1234, + gravity: "south", + }, + } as const; + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options?.resize).toBe( + `c_${options.crop.type},w_${options.width},h_${options.height},x_${options.crop.x},y_${options.crop.y},g_${options.crop.gravity}`, + ); + }); + + it("should apply coordinates-based cropping with custom width and height", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 123, + height: 321, + crop: { + type: "crop", + x: 100, + y: 100, + width: 567, + height: 765, + gravity: "south", + }, + } as const; + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options?.resize).toBe( + `c_${options.crop.type},w_${options.crop.width},h_${options.crop.height},x_${options.crop.x},y_${options.crop.y},g_${options.crop.gravity}`, + ); + }); + + it("should crop by coordinates in 2 stages with width", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 900, + height: 600, + crop: { + type: "fill", + x: 5687, + y: 6543, + source: true, + }, + } as const; + const result = CroppingPlugin.apply(cldImage, options); + + if (result.options?.resize === undefined) + throw new Error(`Expected result.options.resize to not be undefined`); + + expect(result.options?.resize).toContain(`c_limit,w_${options.width}`); + expect(cldImage.toURL()).toContain( + `image/upload/c_${options.crop.type},w_${options.width},h_${options.height},x_${options.crop.x},y_${options.crop.y}`, + ); + }); +}); diff --git a/packages/url-loader/tests/plugins/default.spec.js b/packages/url-loader/tests/plugins/default.spec.js deleted file mode 100644 index 486fa5de..00000000 --- a/packages/url-loader/tests/plugins/default.spec.js +++ /dev/null @@ -1,48 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { afterEach, describe, expect, it, vi } from 'vitest'; - -import { defaultImagePlugin } from '../../src/plugins/default-image'; - -const { plugin } = defaultImagePlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -const TEST_PUBLIC_ID = 'test-public-id'; - -global.console = { - ...global.console, - warn: vi.fn() -} - -describe('Default Image plugin', () => { - afterEach(() => { - // Clears the state of console.warn, in case multiple tests want to monitor it - vi.restoreAllMocks() - }); - - it('should add a default image', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 100, - height: 100, - defaultImage: 'my-image.jpg' - }; - plugin({ cldAsset: cldImage, options }); - expect(cldImage.toURL()).toContain(`d_${options.defaultImage}/${TEST_PUBLIC_ID}`); - }); - it('should warn if no format', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - const options = { - width: 100, - height: 100, - defaultImage: 'my-image' - }; - plugin({ cldAsset: cldImage, options }); - expect(console.warn.mock.calls[0][0]).toContain('The defaultImage prop may be missing'); - expect(cldImage.toURL()).toContain(`d_${options.defaultImage}/${TEST_PUBLIC_ID}`); - }); -}); diff --git a/packages/url-loader/tests/plugins/default.spec.ts b/packages/url-loader/tests/plugins/default.spec.ts new file mode 100644 index 00000000..ceee5ebe --- /dev/null +++ b/packages/url-loader/tests/plugins/default.spec.ts @@ -0,0 +1,54 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +import { DefaultImagePlugin } from "../../src/plugins/default-image.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +global.console = { + ...global.console, + warn: vi.fn(), +}; + +describe("Default Image plugin", () => { + afterEach(() => { + // Clears the state of console.warn, in case multiple tests want to monitor it + vi.restoreAllMocks(); + }); + + it("should add a default image", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 100, + height: 100, + defaultImage: "my-image.jpg", + }; + DefaultImagePlugin.apply(cldImage, options); + expect(cldImage.toURL()).toContain( + `d_${options.defaultImage}/${TEST_PUBLIC_ID}` + ); + }); + it("should warn if no format", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + const options = { + src: TEST_PUBLIC_ID, + width: 100, + height: 100, + defaultImage: "my-image", + }; + DefaultImagePlugin.apply(cldImage, options); + expect((console.warn as any).mock.calls[0][0]).toContain( + "The defaultImage prop may be missing" + ); + expect(cldImage.toURL()).toContain( + `d_${options.defaultImage}/${TEST_PUBLIC_ID}` + ); + }); +}); diff --git a/packages/url-loader/tests/plugins/effects.spec.js b/packages/url-loader/tests/plugins/effects.spec.js deleted file mode 100644 index 99f1233b..00000000 --- a/packages/url-loader/tests/plugins/effects.spec.js +++ /dev/null @@ -1,90 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; - -import { effectsPlugin } from '../../src/plugins/effects'; - -const { plugin } = effectsPlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -const TEST_PUBLIC_ID = 'test-public-id'; - -describe('Plugins', () => { - it('should apply effects ', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const shear = '40:0'; - const opacity = '50'; - - const options = { - shear, - opacity, - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`/o_${opacity}/e_shear:${shear}/`); - }); - it('should apply effects by array', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const shear = '40:0'; - const gradientFade = true; - const opacity = '50'; - const cartoonify = '50'; - const radius = '150'; - - const options = { - effects: [ - { - shear, - opacity, - }, - { - gradientFade, - cartoonify, - radius - } - ] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`/o_${opacity},e_shear:${shear}/e_cartoonify:${cartoonify},e_gradient_fade,r_${radius}/`); - }); - - it('should colorize with a hex color value', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const color = '#ff00ff'; - const colorExpected = 'rgb:ff00ff'; - const colorize = 50; - - - const options = { - effects: [ - { - color, - colorize - }, - ] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`/co_${colorExpected},e_colorize:${colorize}/`); - }); -}); \ No newline at end of file diff --git a/packages/url-loader/tests/plugins/effects.spec.ts b/packages/url-loader/tests/plugins/effects.spec.ts new file mode 100644 index 00000000..d028095e --- /dev/null +++ b/packages/url-loader/tests/plugins/effects.spec.ts @@ -0,0 +1,85 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { EffectsPlugin } from "../../src/plugins/effects.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + it("should apply effects ", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const shear = "40:0"; + const opacity = "50"; + + const options = { + src: TEST_PUBLIC_ID, + shear, + opacity, + }; + + EffectsPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain(`/o_${opacity}/e_shear:${shear}/`); + }); + it("should apply effects by array", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const shear = "40:0"; + const gradientFade = true; + const opacity = "50"; + const cartoonify = "50"; + const radius = "150"; + + const options = { + src: TEST_PUBLIC_ID, + effects: [ + { + shear, + opacity, + }, + { + gradientFade, + cartoonify, + radius, + }, + ], + }; + + EffectsPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `/o_${opacity},e_shear:${shear}/e_cartoonify:${cartoonify},e_gradient_fade,r_${radius}/`, + ); + }); + + it("should colorize with a hex color value", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const color = "#ff00ff"; + const colorExpected = "rgb:ff00ff"; + const colorize = 50; + + const options = { + src: TEST_PUBLIC_ID, + effects: [ + { + color, + colorize, + }, + ], + }; + + EffectsPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `/co_${colorExpected},e_colorize:${colorize}/`, + ); + }); +}); diff --git a/packages/url-loader/tests/plugins/extract.spec.js b/packages/url-loader/tests/plugins/extract.spec.js deleted file mode 100644 index 7dd27635..00000000 --- a/packages/url-loader/tests/plugins/extract.spec.js +++ /dev/null @@ -1,101 +0,0 @@ -import { Cloudinary } from "@cloudinary/url-gen"; -import { describe, expect, it } from 'vitest'; - -import { extractPlugin } from "../../src/plugins/extract"; - -const { plugin } = extractPlugin; - -const cld = new Cloudinary({ - cloud: { - cloudName: "test-cloud-name", - }, -}); - -const TEST_PUBLIC_ID = "test-public-id"; - -describe("Plugins", () => { - describe("Extract", () => { - it("should extract by single prompt", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - extract: 'space jellyfish', - }; - - plugin({ - cldAsset: cldImage, - options, - }); - - expect(cldImage.toURL()).toContain(`/e_extract:prompt_${encodeURIComponent(options.extract)}/`); - }); - - it("should not add extract if no options detected", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - extract: true, - }; - - plugin({ - cldAsset: cldImage, - options, - }); - - expect(cldImage.toURL()).not.toContain(`/e_extract/`); - }); - - it("should extract by array of prompts", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - extract: ['space jellyfish', 'octocat'], - }; - - plugin({ - cldAsset: cldImage, - options, - }); - - expect(cldImage.toURL()).toContain(`/e_extract:prompt_(${options.extract.map(p => encodeURIComponent(p)).join(';')})/`); - }); - - it("should extract by object", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - extract: { - prompt: 'space jellyfish', - multiple: true, - mode: 'mask', - invert: true - }, - }; - - plugin({ - cldAsset: cldImage, - options, - }); - - expect(cldImage.toURL()).toContain(`/e_extract:prompt_${encodeURIComponent(options.extract.prompt)};invert_${options.extract.invert};mode_${options.extract.mode};multiple_${options.extract.multiple}/`); - }); - - it("should extract by object with array of prompts", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - extract: { - prompt: ['space jellyfish', 'octocat'], - mode: 'mask', - }, - }; - - plugin({ - cldAsset: cldImage, - options, - }); - - expect(cldImage.toURL()).toContain(`/e_extract:prompt_(${options.extract.prompt.map(p => encodeURIComponent(p)).join(';')});mode_${options.extract.mode}/`); - }); - }); -}); diff --git a/packages/url-loader/tests/plugins/extract.spec.ts b/packages/url-loader/tests/plugins/extract.spec.ts new file mode 100644 index 00000000..f81bb1ee --- /dev/null +++ b/packages/url-loader/tests/plugins/extract.spec.ts @@ -0,0 +1,97 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { ExtractPlugin } from "../../src/plugins/extract.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + describe("Extract", () => { + it("should extract by single prompt", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + extract: "space jellyfish", + }; + + ExtractPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `/e_extract:prompt_${encodeURIComponent(options.extract)}/`, + ); + }); + + it("should not add extract if no options detected", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + extract: {}, + }; + + ExtractPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).not.toContain(`/e_extract/`); + }); + + it("should extract by array of prompts", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + extract: ["space jellyfish", "octocat"], + }; + + ExtractPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `/e_extract:prompt_(${options.extract.map((p) => encodeURIComponent(p)).join(";")})/`, + ); + }); + + it("should extract by object", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + extract: { + prompt: "space jellyfish", + multiple: true, + mode: "mask", + invert: true, + }, + } as const; + + ExtractPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `/e_extract:prompt_${encodeURIComponent(options.extract.prompt)};invert_${options.extract.invert};mode_${options.extract.mode};multiple_${options.extract.multiple}/`, + ); + }); + + it("should extract by object with array of prompts", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + extract: { + prompt: ["space jellyfish", "octocat"], + mode: "mask", + }, + } as const; + + ExtractPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `/e_extract:prompt_(${options.extract.prompt.map((p) => encodeURIComponent(p)).join(";")});mode_${options.extract.mode}/`, + ); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/fill-background.spec.js b/packages/url-loader/tests/plugins/fill-background.spec.js deleted file mode 100644 index 8bfb643a..00000000 --- a/packages/url-loader/tests/plugins/fill-background.spec.js +++ /dev/null @@ -1,71 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; - -import { fillBackgroundPlugin } from '../../src/plugins/fill-background'; - -const { plugin } = fillBackgroundPlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -const TEST_PUBLIC_ID = 'test-public-id'; - -describe('Plugins', () => { - describe('Fill Background', () => { - it('should generate a background with basic settings', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - width: 800, - height: 600, - fillBackground: true - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`b_gen_fill,ar_${options.width}:${options.height},c_pad/${TEST_PUBLIC_ID}`); - }); - - it('should generate with custom options', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - width: 800, - height: 600, - fillBackground: { - gravity: 'east', - prompt: 'pink and purple flowers', - crop: 'mpad' - } - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`b_gen_fill:${encodeURIComponent(options.fillBackground.prompt)},ar_${options.width}:${options.height},c_${options.fillBackground.crop},g_${options.fillBackground.gravity}/${TEST_PUBLIC_ID}`); - }); - - it('should not add generative fill if does not include aspect ratio', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - fillBackground: true - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`image/upload/${TEST_PUBLIC_ID}`); - }); - }); -}); diff --git a/packages/url-loader/tests/plugins/fill-background.spec.ts b/packages/url-loader/tests/plugins/fill-background.spec.ts new file mode 100644 index 00000000..cf5fc479 --- /dev/null +++ b/packages/url-loader/tests/plugins/fill-background.spec.ts @@ -0,0 +1,67 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { FillBackgroundPlugin } from "../../src/plugins/fill-background.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + describe("Fill Background", () => { + it("should generate a background with basic settings", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + width: 800, + height: 600, + fillBackground: true, + }; + + FillBackgroundPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `b_gen_fill,ar_${options.width}:${options.height},c_pad/${TEST_PUBLIC_ID}`, + ); + }); + + it("should generate with custom options", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + width: 800, + height: 600, + fillBackground: { + gravity: "east", + prompt: "pink and purple flowers", + crop: "mpad", + }, + } as const; + + FillBackgroundPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `b_gen_fill:${encodeURIComponent(options.fillBackground.prompt)},ar_${options.width}:${options.height},c_${options.fillBackground.crop},g_${options.fillBackground.gravity}/${TEST_PUBLIC_ID}`, + ); + }); + + it("should not add generative fill if does not include aspect ratio", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + fillBackground: true, + }; + + FillBackgroundPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain(`image/upload/${TEST_PUBLIC_ID}`); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/flags.spec.js b/packages/url-loader/tests/plugins/flags.spec.js deleted file mode 100644 index 700b9a0c..00000000 --- a/packages/url-loader/tests/plugins/flags.spec.js +++ /dev/null @@ -1,59 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; - -import { flagsPlugin } from '../../src/plugins/flags'; - -const { plugin } = flagsPlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -describe('Plugins', () => { - describe('Flags', () => { - it('should include a flag on an image', () => { - const src = 'turtle'; - const assetType = 'image'; - const cldVideo = cld.image(src); - const flags = ['keep_iptc']; - plugin({ cldAsset: cldVideo, options: { - assetType, - src, - flags - } }); - expect(cldVideo.toURL()).toContain(`${assetType}/upload/fl_keep_iptc/${src}`); - }); - - it('should add multiple flags to a video', () => { - const src = 'turtle.mp4'; - const assetType = 'video'; - const cldVideo = cld.video(src); - const flags = ['no_stream', 'splice'] - plugin({ cldAsset: cldVideo, options: { - assetType, - src, - flags - } }); - expect(cldVideo.toURL()).toContain(`${assetType}/upload/fl_no_stream/fl_splice/${src}`); - }); - - it('should add custom flag definitions via object syntax', () => { - const src = 'turtle'; - const assetType = 'image'; - const cldVideo = cld.image(src); - const flags = { - splice: 'transition_(name_circleopen;du_2.5)', - attachment: 'space_jellyfish' - } - const flagsString = Object.entries(flags).map(([q, v]) => `fl_${q}:${v}`).join('/'); - plugin({ cldAsset: cldVideo, options: { - assetType, - src, - flags - } }); - expect(cldVideo.toURL()).toContain(`${assetType}/upload/${flagsString}/${src}`); - }); - }); -}); diff --git a/packages/url-loader/tests/plugins/flags.spec.ts b/packages/url-loader/tests/plugins/flags.spec.ts new file mode 100644 index 00000000..5a708a9e --- /dev/null +++ b/packages/url-loader/tests/plugins/flags.spec.ts @@ -0,0 +1,75 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { FlagsPlugin } from "../../src/plugins/flags.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +describe("Plugins", () => { + describe("Flags", () => { + it("should include a flag on an image", () => { + const src = "turtle"; + const assetType = "image"; + const cldVideo = cld.image(src); + const flags = "keep_iptc"; + const options = { + assetType, + src, + flags, + } as const; + + FlagsPlugin.apply(cldVideo, options); + + expect(cldVideo.toURL()).toContain( + `${assetType}/upload/fl_keep_iptc/${src}`, + ); + }); + + it("should add multiple flags to a video", () => { + const src = "turtle.mp4"; + const assetType = "video"; + const cldVideo = cld.video(src); + const flags = ["no_stream", "splice"] as const; + + const options = { + assetType, + src, + flags, + } as const; + + FlagsPlugin.apply(cldVideo, options); + + expect(cldVideo.toURL()).toContain( + `${assetType}/upload/fl_no_stream/fl_splice/${src}`, + ); + }); + + it("should add custom flag definitions via object syntax", () => { + const src = "turtle"; + const assetType = "image"; + const cldVideo = cld.image(src); + const flags = { + splice: "transition_(name_circleopen;du_2.5)", + attachment: "space_jellyfish", + }; + const flagsString = Object.entries(flags) + .map(([q, v]) => `fl_${q}:${v}`) + .join("/"); + + const options = { + assetType, + src, + flags, + } as const; + + FlagsPlugin.apply(cldVideo, options); + expect(cldVideo.toURL()).toContain( + `${assetType}/upload/${flagsString}/${src}`, + ); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/named-transformations.spec.js b/packages/url-loader/tests/plugins/named-transformations.spec.js deleted file mode 100644 index 242c08cd..00000000 --- a/packages/url-loader/tests/plugins/named-transformations.spec.js +++ /dev/null @@ -1,92 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; - -import { namedTransformationsPlugin } from '../../src/plugins/named-transformations'; - -const { plugin } = namedTransformationsPlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -const TEST_PUBLIC_ID = 'test-public-id'; - -describe('Plugins', () => { - describe('Named Transformations', () => { - it('should apply a single named transformation to a Cloudinary URL', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - namedTransformations: 'my-transformation' - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`t_${options.namedTransformations}/${TEST_PUBLIC_ID}`); - }); - - it('should apply an array of named transformations to a Cloudinary URL', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - namedTransformations: [ - 'my-transformation', - 'my-other-transformation' - ] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`t_${options.namedTransformations.join('/t_')}/${TEST_PUBLIC_ID}`); - }) - }); - - // @todo - deprecate in favor of namedTransformations - - describe('Named Transformations', () => { - it('should apply a single named transformation to a Cloudinary URL', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - transformations: 'my-transformation' - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`t_${options.transformations}/${TEST_PUBLIC_ID}`); - }); - - it('should apply an array of named transformations to a Cloudinary URL', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - transformations: [ - 'my-transformation', - 'my-other-transformation' - ] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`t_${options.transformations.join('/t_')}/${TEST_PUBLIC_ID}`); - }) - }); -}); \ No newline at end of file diff --git a/packages/url-loader/tests/plugins/named-transformations.spec.ts b/packages/url-loader/tests/plugins/named-transformations.spec.ts new file mode 100644 index 00000000..687a9e1d --- /dev/null +++ b/packages/url-loader/tests/plugins/named-transformations.spec.ts @@ -0,0 +1,80 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { NamedTransformationsPlugin } from "../../src/plugins/named-transformations.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + describe("Named Transformations", () => { + it("should apply a single named transformation to a Cloudinary URL", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + namedTransformations: "my-transformation", + }; + + NamedTransformationsPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `t_${options.namedTransformations}/${TEST_PUBLIC_ID}`, + ); + }); + + it("should apply an array of named transformations to a Cloudinary URL", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + namedTransformations: ["my-transformation", "my-other-transformation"], + }; + + NamedTransformationsPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `t_${options.namedTransformations.join("/t_")}/${TEST_PUBLIC_ID}`, + ); + }); + }); + + // @todo - deprecate in favor of namedTransformations + + describe("Named Transformations", () => { + it("should apply a single named transformation to a Cloudinary URL", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + transformations: "my-transformation", + }; + + NamedTransformationsPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `t_${options.transformations}/${TEST_PUBLIC_ID}`, + ); + }); + + it("should apply an array of named transformations to a Cloudinary URL", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + transformations: ["my-transformation", "my-other-transformation"], + }; + + NamedTransformationsPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `t_${options.transformations.join("/t_")}/${TEST_PUBLIC_ID}`, + ); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/overlays.spec.js b/packages/url-loader/tests/plugins/overlays.spec.js deleted file mode 100644 index 0ec367d1..00000000 --- a/packages/url-loader/tests/plugins/overlays.spec.js +++ /dev/null @@ -1,443 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; - -import { DEFAULT_TEXT_OPTIONS, overlaysPlugin } from '../../src/plugins/overlays'; - -const { plugin } = overlaysPlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -const TEST_PUBLIC_ID = 'test-public-id'; - -describe('Plugins', () => { - describe('Image Overlays', () => { - - it('should add a remote image overlay configured by overlay object', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - overlays: [{ - url: 'https://user-images.githubusercontent.com/1045274/199872380-ced2b84d-fce4-4fc9-9e76-48cb4a7fb35f.png' - }] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_fetch:aHR0cHM6Ly91c2VyLWltYWdlcy5naXRodWJ1c2VyY29udGVudC5jb20vMTA0NTI3NC8xOTk4NzIzODAtY2VkMmI4NGQtZmNlNC00ZmM5LTllNzYtNDhjYjRhN2ZiMzVmLnBuZw%3D%3D`); - }); - - it('should apply effects to an overlay by public ID', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const publicId = 'images/my-cool-image' - - const options = { - overlays: [{ - publicId - }] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_${publicId.replace(/\//g, ':')}/fl_layer_apply,fl_no_overflow`); - }); - - it('should apply effects to an overlay', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const publicId = 'images/my-cool-image' - const width = 100; - const height = 200; - const shear = '40:0'; - const opacity = '50'; - - const options = { - overlays: [{ - publicId, - effects: [ - { - width, - height, - }, - { - shear, - opacity, - } - ] - }] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_${publicId.replace(/\//g, ':')},w_${width},h_${height},e_shear:${shear},o_${opacity}/fl_layer_apply,fl_no_overflow`); - }); - - it('should apply applied effects to an overlay', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const publicId = 'images/my-cool-image' - const width = 100; - const height = 200; - - const options = { - overlays: [{ - publicId, - effects: [ - { - width, - height, - } - ], - appliedEffects: [ - { - screen: true - } - ] - }] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_${publicId.replace(/\//g, ':')},w_${width},h_${height}/fl_layer_apply,fl_no_overflow,e_screen`); - }); - - it('should apply flags to an overlay', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const publicId = 'images/my-cool-image' - const width = '1.0'; - const flags = ['relative'] - - const options = { - overlays: [{ - publicId, - width, - flags - }] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_${publicId.replace(/\//g, ':')},w_${width},${flags.map(f => `fl_${f}`).join(',')}/fl_layer_apply,fl_no_overflow`); - }); - - it('should apply applied flags to an overlay', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const publicId = 'images/my-cool-image' - const width = '1.0'; - // Not sure this makes sense in this location, but for testing purposes - const flags = ['sanitize'] - - const options = { - overlays: [{ - publicId, - width, - appliedFlags: flags - }] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_${publicId.replace(/\//g, ':')},w_${width}/fl_layer_apply,fl_no_overflow,${flags.map(f => `fl_${f}`).join(',')}`); - }); - - it('should not apply undefined effects', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const publicId = 'images/my-cool-image' - - const options = { - overlays: [{ - publicId, - effects: [{ - colby: 'fayock', - space: 'jelly' - }], - appliedEffects: [{ - colby: 'fayock', - space: 'jelly' - }] - }] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`/l_${publicId.replace(/\//g, ':')}/fl_layer_apply,fl_no_overflow/`); - }); - - }) - describe('Text Overlays', () => { - it('should add a text overlay with basic settings', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const fontFamily = 'Source Sans Pro'; - const fontSize = 200; - const text = 'Next Cloudinary'; - - const options = { - overlays: [{ - text: { - fontFamily, - fontSize, - text - } - }] - } - - plugin({ - cldAsset: cldImage, - options - }); - - - expect(cldImage.toURL()).toContain(`l_text:${encodeURIComponent(fontFamily)}_${fontSize}:${encodeURIComponent(text)}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`); - }); - - it('should add a text overlay configured by overlay object', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const color = 'white'; - const fontFamily = 'Source Sans Pro'; - const fontSize = 200; - const fontWeight = 'bold'; - const text = 'Next Cloudinary'; - - const options = { - overlays: [{ - text: { - color, - fontFamily, - fontSize, - fontWeight, - text - } - }] - } - - plugin({ - cldAsset: cldImage, - options - }); - - - expect(cldImage.toURL()).toContain(`l_text:${encodeURIComponent(fontFamily)}_${fontSize}_${fontWeight}:${encodeURIComponent(text)},co_${color}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`); - }); - - it('should add a text overlay by overlay object text string', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const { color, fontFamily, fontSize, fontWeight } = DEFAULT_TEXT_OPTIONS; - const text = 'Next Cloudinary'; - - const options = { - overlays: [{ - text - }] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_text:${encodeURIComponent(fontFamily)}_${fontSize}_${fontWeight}:${encodeURIComponent(text)},co_${color}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`); - }); - - it('should add a text overlay by text string', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const { color, fontFamily, fontSize, fontWeight } = DEFAULT_TEXT_OPTIONS; - const text = 'Next Cloudinary'; - - const options = { - text - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_text:${encodeURIComponent(fontFamily)}_${fontSize}_${fontWeight}:${encodeURIComponent(text)},co_${color}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`); - }); - - it('should add a text overlay by text object', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const color = 'white'; - const fontFamily = 'Source Sans Pro'; - const fontSize = 200; - const fontWeight = 'bold'; - const text = 'Next Cloudinary'; - const letterSpacing = 10; - const lineSpacing = 20; - - const options = { - text: { - color, - fontFamily, - fontSize, - fontWeight, - text, - letterSpacing, - lineSpacing - } - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_text:${encodeURIComponent(fontFamily)}_${fontSize}_${fontWeight}_letter_spacing_${letterSpacing}_line_spacing_${lineSpacing}:${encodeURIComponent(text)},co_${color}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`); - }); - - it('should add a stroke to text', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const alignment = 'right'; - const antialias = 'best'; - const color = 'white'; - const fontFamily = 'Source Sans Pro'; - const fontSize = 200; - const fontStyle = 'italic'; - const fontWeight = 'bold'; - const hinting = 'slight'; - const letterSpacing = 12; - const lineSpacing = -12; - const text = 'Next Cloudinary'; - const border = '20px_solid_blue'; - const stroke = true; - - const options = { - text: { - alignment, - antialias, - color, - fontFamily, - fontSize, - fontStyle, - fontWeight, - hinting, - letterSpacing, - lineSpacing, - text, - border, - stroke - } - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_text:${encodeURIComponent(fontFamily)}_${fontSize}_${fontWeight}_${fontStyle}_${alignment}_stroke_antialias_${antialias}_hinting_${hinting}_letter_spacing_${letterSpacing}_line_spacing_${lineSpacing}:${encodeURIComponent(text)},co_${color},bo_${border}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`); - }); - - it('should add a stroke to text', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const color = 'white'; - const fontFamily = 'Source Sans Pro'; - const fontSize = 200; - const fontWeight = 'bold'; - const text = 'Next Cloudinary'; - const border = '20px_solid_blue'; - const stroke = true; - - const options = { - text: { - color, - fontFamily, - fontSize, - fontWeight, - text, - border, - stroke - } - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_text:${encodeURIComponent(fontFamily)}_${fontSize}_${fontWeight}_stroke:${encodeURIComponent(text)},co_${color},bo_${border}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`); - }); - - it('should add text with special characters', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const color = 'white'; - const fontFamily = 'Source Sans Pro'; - const text = 'Ne xt/Cloud.in,ary'; - const expectedText = 'Ne%20xt%252FCloud%252Ein%252Cary'; - - const options = { - text: { - color, - fontFamily, - text, - } - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_text:${encodeURIComponent(fontFamily)}_200_bold:${expectedText},co_${color}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`); - }); - - it('should replace color with #asdf with rgb:', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const color = '#ff00ff'; - const expectedColor = 'rgb:ff00ff'; - const fontFamily = 'Source Sans Pro'; - const text = 'Next Cloudinary'; - - const options = { - text: { - color, - fontFamily, - text, - } - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`l_text:${encodeURIComponent(fontFamily)}_200_bold:${encodeURIComponent(text)},co_${expectedColor}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`); - }); - }); -}); \ No newline at end of file diff --git a/packages/url-loader/tests/plugins/overlays.spec.ts b/packages/url-loader/tests/plugins/overlays.spec.ts new file mode 100644 index 00000000..579e1e1c --- /dev/null +++ b/packages/url-loader/tests/plugins/overlays.spec.ts @@ -0,0 +1,464 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { + DEFAULT_TEXT_OPTIONS, + OverlaysPlugin, +} from "../../src/plugins/overlays.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + describe("Image Overlays", () => { + it("should add a remote image overlay configured by overlay object", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + overlays: [ + { + url: "https://user-images.githubusercontent.com/1045274/199872380-ced2b84d-fce4-4fc9-9e76-48cb4a7fb35f.png", + }, + ], + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_fetch:aHR0cHM6Ly91c2VyLWltYWdlcy5naXRodWJ1c2VyY29udGVudC5jb20vMTA0NTI3NC8xOTk4NzIzODAtY2VkMmI4NGQtZmNlNC00ZmM5LTllNzYtNDhjYjRhN2ZiMzVmLnBuZw%3D%3D`, + ); + }); + + it("should apply effects to an overlay by public ID", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const publicId = "images/my-cool-image"; + + const options = { + src: TEST_PUBLIC_ID, + overlays: [ + { + publicId, + }, + ], + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_${publicId.replace(/\//g, ":")}/fl_layer_apply,fl_no_overflow`, + ); + }); + + it("should apply effects to an overlay", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const publicId = "images/my-cool-image"; + const width = 100; + const height = 200; + const shear = "40:0"; + const opacity = "50"; + + const options = { + src: TEST_PUBLIC_ID, + overlays: [ + { + publicId, + effects: [ + { + width, + height, + }, + { + shear, + opacity, + }, + ], + }, + ], + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_${publicId.replace(/\//g, ":")},w_${width},h_${height},e_shear:${shear},o_${opacity}/fl_layer_apply,fl_no_overflow`, + ); + }); + + it("should apply applied effects to an overlay", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const publicId = "images/my-cool-image"; + const width = 100; + const height = 200; + + const options = { + src: TEST_PUBLIC_ID, + overlays: [ + { + publicId, + effects: [ + { + width, + height, + }, + ], + appliedEffects: [ + { + screen: true, + }, + ], + }, + ], + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_${publicId.replace(/\//g, ":")},w_${width},h_${height}/fl_layer_apply,fl_no_overflow,e_screen`, + ); + }); + + it("should apply flags to an overlay", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const publicId = "images/my-cool-image"; + const width = "1.0"; + const flags = ["relative"] as const; + + const options = { + src: TEST_PUBLIC_ID, + overlays: [ + { + publicId, + width, + flags, + }, + ], + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_${publicId.replace(/\//g, ":")},w_${width},${flags.map((f) => `fl_${f}`).join(",")}/fl_layer_apply,fl_no_overflow`, + ); + }); + + it("should apply applied flags to an overlay", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const publicId = "images/my-cool-image"; + const width = "1.0"; + // Not sure this makes sense in this location, but for testing purposes + const flags = ["sanitize"] as const; + + const options = { + src: TEST_PUBLIC_ID, + overlays: [ + { + publicId, + width, + appliedFlags: flags, + }, + ], + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_${publicId.replace(/\//g, ":")},w_${width}/fl_layer_apply,fl_no_overflow,${flags.map((f) => `fl_${f}`).join(",")}`, + ); + }); + + it("should not apply undefined effects", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const publicId = "images/my-cool-image"; + + const options = { + src: TEST_PUBLIC_ID, + overlays: [ + { + publicId, + effects: [ + { + colby: "fayock", + space: "jelly", + }, + ], + appliedEffects: [ + { + colby: "fayock", + space: "jelly", + }, + ], + }, + ], + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `/l_${publicId.replace(/\//g, ":")}/fl_layer_apply,fl_no_overflow/`, + ); + }); + }); + describe("Text Overlays", () => { + it("should add a text overlay with basic settings", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const fontFamily = "Source Sans Pro"; + const fontSize = 200; + const text = "Next Cloudinary"; + + const options = { + src: TEST_PUBLIC_ID, + overlays: [ + { + text: { + fontFamily, + fontSize, + text, + }, + }, + ], + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_text:${encodeURIComponent(fontFamily)}_${fontSize}:${encodeURIComponent(text)}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`, + ); + }); + + it("should add a text overlay configured by overlay object", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const color = "white"; + const fontFamily = "Source Sans Pro"; + const fontSize = 200; + const fontWeight = "bold"; + const text = "Next Cloudinary"; + + const options = { + src: TEST_PUBLIC_ID, + overlays: [ + { + text: { + color, + fontFamily, + fontSize, + fontWeight, + text, + }, + }, + ], + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_text:${encodeURIComponent(fontFamily)}_${fontSize}_${fontWeight}:${encodeURIComponent(text)},co_${color}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`, + ); + }); + + it("should add a text overlay by overlay object text string", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const { color, fontFamily, fontSize, fontWeight } = DEFAULT_TEXT_OPTIONS; + const text = "Next Cloudinary"; + + const options = { + src: TEST_PUBLIC_ID, + overlays: [ + { + text, + }, + ], + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_text:${encodeURIComponent(fontFamily)}_${fontSize}_${fontWeight}:${encodeURIComponent(text)},co_${color}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`, + ); + }); + + it("should add a text overlay by text string", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const { color, fontFamily, fontSize, fontWeight } = DEFAULT_TEXT_OPTIONS; + const text = "Next Cloudinary"; + + const options = { + src: TEST_PUBLIC_ID, + text, + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_text:${encodeURIComponent(fontFamily)}_${fontSize}_${fontWeight}:${encodeURIComponent(text)},co_${color}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`, + ); + }); + + it("should add a text overlay by text object", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const color = "white"; + const fontFamily = "Source Sans Pro"; + const fontSize = 200; + const fontWeight = "bold"; + const text = "Next Cloudinary"; + const letterSpacing = 10; + const lineSpacing = 20; + + const options = { + src: TEST_PUBLIC_ID, + text: { + color, + fontFamily, + fontSize, + fontWeight, + text, + letterSpacing, + lineSpacing, + }, + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_text:${encodeURIComponent(fontFamily)}_${fontSize}_${fontWeight}_letter_spacing_${letterSpacing}_line_spacing_${lineSpacing}:${encodeURIComponent(text)},co_${color}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`, + ); + }); + + it("should add a stroke to text", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const alignment = "right"; + const antialias = "best"; + const color = "white"; + const fontFamily = "Source Sans Pro"; + const fontSize = 200; + const fontStyle = "italic"; + const fontWeight = "bold"; + const hinting = "slight"; + const letterSpacing = 12; + const lineSpacing = -12; + const text = "Next Cloudinary"; + const border = "20px_solid_blue"; + const stroke = true; + + const options = { + src: TEST_PUBLIC_ID, + text: { + alignment, + antialias, + color, + fontFamily, + fontSize, + fontStyle, + fontWeight, + hinting, + letterSpacing, + lineSpacing, + text, + border, + stroke, + }, + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_text:${encodeURIComponent(fontFamily)}_${fontSize}_${fontWeight}_${fontStyle}_${alignment}_stroke_antialias_${antialias}_hinting_${hinting}_letter_spacing_${letterSpacing}_line_spacing_${lineSpacing}:${encodeURIComponent(text)},co_${color},bo_${border}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`, + ); + }); + + it("should add a stroke to text", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const color = "white"; + const fontFamily = "Source Sans Pro"; + const fontSize = 200; + const fontWeight = "bold"; + const text = "Next Cloudinary"; + const border = "20px_solid_blue"; + const stroke = true; + + const options = { + src: TEST_PUBLIC_ID, + text: { + color, + fontFamily, + fontSize, + fontWeight, + text, + border, + stroke, + }, + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_text:${encodeURIComponent(fontFamily)}_${fontSize}_${fontWeight}_stroke:${encodeURIComponent(text)},co_${color},bo_${border}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`, + ); + }); + + it("should add text with special characters", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const color = "white"; + const fontFamily = "Source Sans Pro"; + const text = "Ne xt/Cloud.in,ary"; + const expectedText = "Ne%20xt%252FCloud%252Ein%252Cary"; + + const options = { + src: TEST_PUBLIC_ID, + text: { + color, + fontFamily, + text, + }, + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_text:${encodeURIComponent(fontFamily)}_200_bold:${expectedText},co_${color}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`, + ); + }); + + it("should replace color with #asdf with rgb:", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const color = "#ff00ff"; + const expectedColor = "rgb:ff00ff"; + const fontFamily = "Source Sans Pro"; + const text = "Next Cloudinary"; + + const options = { + src: TEST_PUBLIC_ID, + text: { + color, + fontFamily, + text, + }, + }; + + OverlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `l_text:${encodeURIComponent(fontFamily)}_200_bold:${encodeURIComponent(text)},co_${expectedColor}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`, + ); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/preserve-transformations.spec.js b/packages/url-loader/tests/plugins/preserve-transformations.spec.js deleted file mode 100644 index c60132e5..00000000 --- a/packages/url-loader/tests/plugins/preserve-transformations.spec.js +++ /dev/null @@ -1,40 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; - -import { preserveTransformationsPlugin } from '../../src/plugins/preserve-transformations'; - -const { plugin } = preserveTransformationsPlugin - -const cloudName = 'test-cloud-name'; - -const cld = new Cloudinary({ - cloud: { - cloudName - } -}); - -const TEST_PUBLIC_ID = 'test-public-id'; - -describe('Plugins', () => { - describe('Preserve Transformations', () => { - it('should preserve transformations from an existing URL ', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const cloudName = 'customtestcloud'; - const transformations = ['c_limit,w_100', 'f_auto', 'q_auto']; - const url = `https://res.cloudinary.com/${cloudName}/image/upload/${transformations.join('/')}/v1234/turtle`; - - const options = { - src: url, - preserveTransformations: true - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`/image/upload/${transformations.join('/')}/`); - }); - }); -}); \ No newline at end of file diff --git a/packages/url-loader/tests/plugins/preserve-transformations.spec.ts b/packages/url-loader/tests/plugins/preserve-transformations.spec.ts new file mode 100644 index 00000000..ab6e1bd1 --- /dev/null +++ b/packages/url-loader/tests/plugins/preserve-transformations.spec.ts @@ -0,0 +1,37 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { PreserveTransformationsPlugin } from "../../src/plugins/preserve-transformations.js"; + +const cloudName = "test-cloud-name"; + +const cld = new Cloudinary({ + cloud: { + cloudName, + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + describe("Preserve Transformations", () => { + it("should preserve transformations from an existing URL ", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const cloudName = "customtestcloud"; + const transformations = ["c_limit,w_100", "f_auto", "q_auto"]; + const url = `https://res.cloudinary.com/${cloudName}/image/upload/${transformations.join("/")}/v1234/turtle`; + + const options = { + src: url, + preserveTransformations: true, + }; + + PreserveTransformationsPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `/image/upload/${transformations.join("/")}/`, + ); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/raw-transformations.spec.js b/packages/url-loader/tests/plugins/raw-transformations.spec.js deleted file mode 100644 index de33b53d..00000000 --- a/packages/url-loader/tests/plugins/raw-transformations.spec.js +++ /dev/null @@ -1,55 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; - -import { rawTransformationsPlugin } from '../../src/plugins/raw-transformations'; - -const { plugin } = rawTransformationsPlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -const TEST_PUBLIC_ID = 'test-public-id'; - -describe('Plugins', () => { - describe('Raw Transformations', () => { - it('should apply a single raw transformations to the end of a Cloudinary URL', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - rawTransformations: [ - 'e_blur:2000' - ] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`${options.rawTransformations.join('/')}/${TEST_PUBLIC_ID}`); - }); - - it('should apply an array of raw transformations to the end of a Cloudinary URL', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - rawTransformations: [ - 'e_blur:2000', - 'e_tint:100:0000FF:0p:FF1493:100p' - ] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`${options.rawTransformations.join('/')}/${TEST_PUBLIC_ID}`); - }) - }); -}); \ No newline at end of file diff --git a/packages/url-loader/tests/plugins/raw-transformations.spec.ts b/packages/url-loader/tests/plugins/raw-transformations.spec.ts new file mode 100644 index 00000000..b62af5a6 --- /dev/null +++ b/packages/url-loader/tests/plugins/raw-transformations.spec.ts @@ -0,0 +1,46 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { RawTransformationsPlugin } from "../../src/plugins/raw-transformations.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + describe("Raw Transformations", () => { + it("should apply a single raw transformations to the end of a Cloudinary URL", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + rawTransformations: ["e_blur:2000"], + }; + + RawTransformationsPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `${options.rawTransformations.join("/")}/${TEST_PUBLIC_ID}`, + ); + }); + + it("should apply an array of raw transformations to the end of a Cloudinary URL", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + rawTransformations: ["e_blur:2000", "e_tint:100:0000FF:0p:FF1493:100p"], + }; + + RawTransformationsPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `${options.rawTransformations.join("/")}/${TEST_PUBLIC_ID}`, + ); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/recolor.spec.js b/packages/url-loader/tests/plugins/recolor.spec.js deleted file mode 100644 index 0c8801b1..00000000 --- a/packages/url-loader/tests/plugins/recolor.spec.js +++ /dev/null @@ -1,86 +0,0 @@ -import { Cloudinary } from "@cloudinary/url-gen"; -import { describe, expect, it } from 'vitest'; - -import { recolorPlugin } from "../../src/plugins/recolor"; - -const { plugin } = recolorPlugin; - -const cld = new Cloudinary({ - cloud: { - cloudName: "test-cloud-name", - }, -}); - -const TEST_PUBLIC_ID = "test-public-id"; - -describe("Plugins", () => { - describe("Recolor", () => { - it("should recolor an object by Array", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - recolor: ['duck', 'blue'] - }; - - plugin({ - cldAsset: cldImage, - options, - }); - - expect(cldImage.toURL()).toContain(`e_gen_recolor:prompt_duck;to-color_blue`); - }); - - it("should recolor multiple objects by an array", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - recolor: [['duck', 'horse'], 'blue'] - }; - - plugin({ - cldAsset: cldImage, - options, - }); - - expect(cldImage.toURL()).toContain(`e_gen_recolor:prompt_(duck;horse);to-color_blue`); - }); - - it("should recolor an object by object configuration", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - recolor: { - prompt: 'duck', - to: 'blue', - multiple: true - } - }; - - plugin({ - cldAsset: cldImage, - options, - }); - - expect(cldImage.toURL()).toContain(`e_gen_recolor:prompt_duck;to-color_blue;multiple_true`); - }); - - it("should recolor multiple objects by object configuration", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - recolor: { - prompt: ['duck', 'horse'], - to: 'blue', - } - }; - - plugin({ - cldAsset: cldImage, - options, - }); - - expect(cldImage.toURL()).toContain(`e_gen_recolor:prompt_(duck;horse);to-color_blue`); - }); - - }); -}); diff --git a/packages/url-loader/tests/plugins/recolor.spec.ts b/packages/url-loader/tests/plugins/recolor.spec.ts new file mode 100644 index 00000000..b9c20c59 --- /dev/null +++ b/packages/url-loader/tests/plugins/recolor.spec.ts @@ -0,0 +1,83 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { RecolorPlugin } from "../../src/plugins/recolor.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + describe("Recolor", () => { + it("should recolor an object by Array", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + recolor: ["duck", "blue"], + }; + + RecolorPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `e_gen_recolor:prompt_duck;to-color_blue`, + ); + }); + + it("should recolor multiple objects by an array", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + recolor: [["duck", "horse"], "blue"] as const, + }; + + RecolorPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `e_gen_recolor:prompt_(duck;horse);to-color_blue`, + ); + }); + + it("should recolor an object by object configuration", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + recolor: { + prompt: "duck", + to: "blue", + multiple: true, + }, + }; + + RecolorPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `e_gen_recolor:prompt_duck;to-color_blue;multiple_true`, + ); + }); + + it("should recolor multiple objects by object configuration", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + recolor: { + prompt: ["duck", "horse"], + to: "blue", + }, + }; + + RecolorPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `e_gen_recolor:prompt_(duck;horse);to-color_blue`, + ); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/remove-background.spec.js b/packages/url-loader/tests/plugins/remove-background.spec.js deleted file mode 100644 index 0e0764ee..00000000 --- a/packages/url-loader/tests/plugins/remove-background.spec.js +++ /dev/null @@ -1,47 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; - -import { removeBackgroundPlugin } from '../../src/plugins/remove-background'; - -const { plugin } = removeBackgroundPlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -const TEST_PUBLIC_ID = 'test-public-id'; - -describe('Plugins', () => { - describe('Remove Background', () => { - it('should remove the background', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - removeBackground : true - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`e_background_removal`); - }); - - it('should not remove the background', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - plugin({ - cldAsset: cldImage, - options: {} - }); - - expect(cldImage.toURL()).not.toContain(`e_background_removal`); - }); - - }); -}); diff --git a/packages/url-loader/tests/plugins/remove-background.spec.ts b/packages/url-loader/tests/plugins/remove-background.spec.ts new file mode 100644 index 00000000..d5ccf7ad --- /dev/null +++ b/packages/url-loader/tests/plugins/remove-background.spec.ts @@ -0,0 +1,41 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { RemoveBackgroundPlugin } from "../../src/plugins/remove-background.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + describe("Remove Background", () => { + it("should remove the background", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + removeBackground: true, + }; + + RemoveBackgroundPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain(`e_background_removal`); + }); + + it("should not remove the background", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + }; + + RemoveBackgroundPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).not.toContain(`e_background_removal`); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/remove.spec.js b/packages/url-loader/tests/plugins/remove.spec.ts similarity index 51% rename from packages/url-loader/tests/plugins/remove.spec.js rename to packages/url-loader/tests/plugins/remove.spec.ts index a5302742..adabc6bd 100644 --- a/packages/url-loader/tests/plugins/remove.spec.js +++ b/packages/url-loader/tests/plugins/remove.spec.ts @@ -1,9 +1,7 @@ import { Cloudinary } from "@cloudinary/url-gen"; -import { describe, expect, it } from 'vitest'; +import { describe, expect, it } from "vitest"; -import { removePlugin } from "../../src/plugins/remove"; - -const { plugin } = removePlugin; +import { RemovePlugin } from "../../src/plugins/remove.js"; const cld = new Cloudinary({ cloud: { @@ -19,13 +17,11 @@ describe("Plugins", () => { const cldImage = cld.image(TEST_PUBLIC_ID); const options = { - remove: 'apple' + src: TEST_PUBLIC_ID, + remove: "apple", }; - plugin({ - cldAsset: cldImage, - options, - }); + RemovePlugin.apply(cldImage, options); expect(cldImage.toURL()).toContain(`e_gen_remove:prompt_apple`); }); @@ -34,49 +30,47 @@ describe("Plugins", () => { const cldImage = cld.image(TEST_PUBLIC_ID); const options = { - remove: ['apple', 'banana', 'orange'] + src: TEST_PUBLIC_ID, + remove: ["apple", "banana", "orange"], }; - plugin({ - cldAsset: cldImage, - options, - }); + RemovePlugin.apply(cldImage, options); - expect(cldImage.toURL()).toContain(`e_gen_remove:prompt_(apple;banana;orange)`); + expect(cldImage.toURL()).toContain( + `e_gen_remove:prompt_(apple;banana;orange)`, + ); }); - + it("should remove an object with object configuration", () => { const cldImage = cld.image(TEST_PUBLIC_ID); const options = { + src: TEST_PUBLIC_ID, remove: { - prompt: ['apple', 'banana'], + prompt: ["apple", "banana"], multiple: true, - removeShadow: true - } + removeShadow: true, + }, }; - plugin({ - cldAsset: cldImage, - options, - }); + RemovePlugin.apply(cldImage, options); - expect(cldImage.toURL()).toContain(`e_gen_remove:prompt_(apple;banana);multiple_true;remove-shadow_true`); + expect(cldImage.toURL()).toContain( + `e_gen_remove:prompt_(apple;banana);multiple_true;remove-shadow_true`, + ); }); it("should remove an object with region", () => { const cldImage = cld.image(TEST_PUBLIC_ID); const options = { + src: TEST_PUBLIC_ID, remove: { - region: [300, 200, 1900, 3500] - } + region: [300, 200, 1900, 3500], + }, }; - plugin({ - cldAsset: cldImage, - options, - }); + RemovePlugin.apply(cldImage, options); expect(cldImage.toURL()).toContain(`region_(x_300;y_200;w_1900;h_3500)`); }); @@ -85,40 +79,39 @@ describe("Plugins", () => { const cldImage = cld.image(TEST_PUBLIC_ID); const options = { + src: TEST_PUBLIC_ID, remove: { region: [ [300, 200, 1900, 3500], - [123, 321, 750, 500] - ] - } + [123, 321, 750, 500], + ], + }, }; - plugin({ - cldAsset: cldImage, - options, - }); + RemovePlugin.apply(cldImage, options); - expect(cldImage.toURL()).toContain(`region_((x_300;y_200;w_1900;h_3500);(x_123;y_321;w_750;h_500))`); + expect(cldImage.toURL()).toContain( + `region_((x_300;y_200;w_1900;h_3500);(x_123;y_321;w_750;h_500))`, + ); }); it("should not allow both a prompt and a region", () => { const cldImage = cld.image(TEST_PUBLIC_ID); const options = { + src: TEST_PUBLIC_ID, remove: { - prompt: 'apple', + prompt: "apple", region: [ [300, 200, 1900, 3500], - [123, 321, 750, 500] - ] - } + [123, 321, 750, 500], + ], + }, }; - expect(() => plugin({ - cldAsset: cldImage, - options, - })).toThrow('Invalid remove options: you can not have both a prompt and a region. More info: https://cloudinary.com/documentation/transformation_reference#e_gen_remove') + expect(() => RemovePlugin.apply(cldImage, options)).toThrow( + "Invalid remove options: you can not have both a prompt and a region. More info: https://cloudinary.com/documentation/transformation_reference#e_gen_remove", + ); }); - }); }); diff --git a/packages/url-loader/tests/plugins/replace-background.spec.js b/packages/url-loader/tests/plugins/replace-background.spec.js deleted file mode 100644 index 4a91cb8b..00000000 --- a/packages/url-loader/tests/plugins/replace-background.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -import { Cloudinary } from "@cloudinary/url-gen"; -import { describe, expect, it } from 'vitest'; - -import { replaceBackgroundPlugin } from "../../src/plugins/replace-background"; - -const { plugin } = replaceBackgroundPlugin; - -const cld = new Cloudinary({ - cloud: { - cloudName: "test-cloud-name", - }, -}); - -const TEST_PUBLIC_ID = "test-public-id"; - -describe("Plugins", () => { - describe("Generative Replace Background", () => { - it("should replace the background", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - replaceBackground: true, - }; - - plugin({ - cldAsset: cldImage, - options, - }); - - expect(cldImage.toURL()).toContain('/e_gen_background_replace/'); - }); - - it("should replace the background with a prompt", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - replaceBackground: 'space jellyfish in space', - }; - - plugin({ - cldAsset: cldImage, - options, - }); - - expect(cldImage.toURL()).toContain(`/e_gen_background_replace:prompt_${encodeURIComponent(options.replaceBackground)}/`); - }); - - it("should replace the background with a prompt", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - replaceBackground: { - prompt: 'space jellyfish in outer space', - seed: 2 - } - }; - - plugin({ - cldAsset: cldImage, - options, - }); - - expect(cldImage.toURL()).toContain(`/e_gen_background_replace:prompt_${encodeURIComponent(options.replaceBackground.prompt)};seed_${options.replaceBackground.seed}/`); - }); - }); -}); diff --git a/packages/url-loader/tests/plugins/replace-background.spec.ts b/packages/url-loader/tests/plugins/replace-background.spec.ts new file mode 100644 index 00000000..b6744826 --- /dev/null +++ b/packages/url-loader/tests/plugins/replace-background.spec.ts @@ -0,0 +1,64 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { ReplaceBackgroundPlugin } from "../../src/plugins/replace-background.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + describe("Generative Replace Background", () => { + it("should replace the background", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + replaceBackground: {}, + }; + + ReplaceBackgroundPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain("/e_gen_background_replace/"); + }); + + it("should replace the background with a prompt", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + replaceBackground: { + prompt: "space jellyfish in space", + }, + }; + + ReplaceBackgroundPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `/e_gen_background_replace:prompt_${encodeURIComponent(options.replaceBackground.prompt)}/`, + ); + }); + + it("should replace the background with a prompt", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + replaceBackground: { + prompt: "space jellyfish in outer space", + seed: 2, + }, + }; + + ReplaceBackgroundPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `/e_gen_background_replace:prompt_${encodeURIComponent(options.replaceBackground.prompt)};seed_${options.replaceBackground.seed}/`, + ); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/replace.spec.js b/packages/url-loader/tests/plugins/replace.spec.ts similarity index 76% rename from packages/url-loader/tests/plugins/replace.spec.js rename to packages/url-loader/tests/plugins/replace.spec.ts index 5519f64b..6ee0b3f2 100644 --- a/packages/url-loader/tests/plugins/replace.spec.js +++ b/packages/url-loader/tests/plugins/replace.spec.ts @@ -1,9 +1,7 @@ import { Cloudinary } from "@cloudinary/url-gen"; -import { describe, expect, it } from 'vitest'; +import { describe, expect, it } from "vitest"; -import { replacePlugin } from "../../src/plugins/replace"; - -const { plugin } = replacePlugin; +import { ReplacePlugin } from "../../src/plugins/replace.js"; const cld = new Cloudinary({ cloud: { @@ -19,16 +17,14 @@ describe("Plugins", () => { const cldImage = cld.image(TEST_PUBLIC_ID); const options = { + src: TEST_PUBLIC_ID, replace: { from: "apple", to: "orange", }, }; - plugin({ - cldAsset: cldImage, - options, - }); + ReplacePlugin.apply(cldImage, options); expect(cldImage.toURL()).toContain(`e_gen_replace:from_apple;to_orange`); }); @@ -37,6 +33,7 @@ describe("Plugins", () => { const cldImage = cld.image(TEST_PUBLIC_ID); const options = { + src: TEST_PUBLIC_ID, replace: { from: "apple", to: "orange", @@ -44,13 +41,10 @@ describe("Plugins", () => { }, }; - plugin({ - cldAsset: cldImage, - options, - }); + ReplacePlugin.apply(cldImage, options); expect(cldImage.toURL()).toContain( - `e_gen_replace:from_apple;to_orange;preserve-geometry_true` + `e_gen_replace:from_apple;to_orange;preserve-geometry_true`, ); }); @@ -58,13 +52,11 @@ describe("Plugins", () => { const cldImage = cld.image(TEST_PUBLIC_ID); const options = { + src: TEST_PUBLIC_ID, replace: ["apple", "orange"], }; - plugin({ - cldAsset: cldImage, - options, - }); + ReplacePlugin.apply(cldImage, options); expect(cldImage.toURL()).toContain(`e_gen_replace:from_apple;to_orange`); }); @@ -73,26 +65,25 @@ describe("Plugins", () => { const cldImage = cld.image(TEST_PUBLIC_ID); const options = { + src: TEST_PUBLIC_ID, replace: ["apple", "candy bar", "true"], }; - plugin({ - cldAsset: cldImage, - options, - }); + ReplacePlugin.apply(cldImage, options); expect(cldImage.toURL()).toContain( - `e_gen_replace:from_apple;to_candy%20bar;preserve-geometry_true` + `e_gen_replace:from_apple;to_candy%20bar;preserve-geometry_true`, ); }); it("should not attempt generative replace", () => { const cldImage = cld.image(TEST_PUBLIC_ID); - plugin({ - cldAsset: cldImage, - options: {}, - }); + const options = { + src: TEST_PUBLIC_ID, + }; + + ReplacePlugin.apply(cldImage, options); expect(cldImage.toURL()).not.toContain(`e_gen_replace`); }); diff --git a/packages/url-loader/tests/plugins/restore.spec.js b/packages/url-loader/tests/plugins/restore.spec.js deleted file mode 100644 index 28837727..00000000 --- a/packages/url-loader/tests/plugins/restore.spec.js +++ /dev/null @@ -1,47 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; - -import { restorePlugin } from '../../src/plugins/restore'; - -const { plugin } = restorePlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -const TEST_PUBLIC_ID = 'test-public-id'; - -describe('Plugins', () => { - describe('Generative Restore', () => { - it('should restore', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - restore: true - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`e_gen_restore`); - }); - - it('should not restore', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - plugin({ - cldAsset: cldImage, - options: {} - }); - - expect(cldImage.toURL()).not.toContain(`e_gen_restore`); - }); - - }); -}); diff --git a/packages/url-loader/tests/plugins/restore.spec.ts b/packages/url-loader/tests/plugins/restore.spec.ts new file mode 100644 index 00000000..a70a4a74 --- /dev/null +++ b/packages/url-loader/tests/plugins/restore.spec.ts @@ -0,0 +1,41 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { RestorePlugin } from "../../src/plugins/restore.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + describe("Generative Restore", () => { + it("should restore", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + restore: true, + }; + + RestorePlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain(`e_gen_restore`); + }); + + it("should not restore", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + }; + + RestorePlugin.apply(cldImage, options); + + expect(cldImage.toURL()).not.toContain(`e_gen_restore`); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/sanitize.spec.ts b/packages/url-loader/tests/plugins/sanitize.spec.ts index 4371c169..808a6fe8 100644 --- a/packages/url-loader/tests/plugins/sanitize.spec.ts +++ b/packages/url-loader/tests/plugins/sanitize.spec.ts @@ -1,9 +1,6 @@ import { Cloudinary } from "@cloudinary/url-gen"; import { describe, expect, it } from "vitest"; - -import { sanitizePlugin } from "../../src/plugins/sanitize.js"; - -const { plugin } = sanitizePlugin; +import { SanitizePlugin } from "../../src/plugins/sanitize.js"; const cld = new Cloudinary({ cloud: { @@ -16,11 +13,8 @@ describe("Cloudinary Sanitize", () => { it("should include fl_sanitize when display image source name end with svg", () => { const src = "turtle.svg"; const cldImage = cld.image(src); - plugin({ - cldAsset: cldImage, - options: { - src, - }, + SanitizePlugin.apply(cldImage, { + src, }); expect(cldImage.toURL()).toContain(`image/upload/fl_sanitize/turtle.svg`); }); @@ -28,12 +22,9 @@ describe("Cloudinary Sanitize", () => { it("should include fl_sanitize and f_svg when display format is svg", () => { const src = "turtle"; const cldImage = cld.image(src); - plugin({ - cldAsset: cldImage, - options: { - format: "svg", - src, - }, + SanitizePlugin.apply(cldImage, { + format: "svg", + src, }); expect(cldImage.toURL()).toContain(`image/upload/fl_sanitize/turtle`); }); @@ -41,12 +32,9 @@ describe("Cloudinary Sanitize", () => { it("should include fl_sanitize and f_svg when display format svg image", () => { const src = "turtle.svg"; const cldImage = cld.image(src); - plugin({ - cldAsset: cldImage, - options: { - format: "svg", - src, - }, + SanitizePlugin.apply(cldImage, { + format: "svg", + src, }); expect(cldImage.toURL()).toContain(`image/upload/fl_sanitize/turtle.svg`); }); @@ -54,12 +42,9 @@ describe("Cloudinary Sanitize", () => { it("should not include fl_sanitize when set option sanitize to false", () => { const src = "turtle.svg"; const cldImage = cld.image(src); - plugin({ - cldAsset: cldImage, - options: { - sanitize: false, - src, - }, + SanitizePlugin.apply(cldImage, { + sanitize: false, + src, }); expect(cldImage.toURL()).toContain(`image/upload/turtle.svg`); }); @@ -67,11 +52,8 @@ describe("Cloudinary Sanitize", () => { it("should not include fl_sanitize when display other image", () => { const src = "turtle"; const cldImage = cld.image(src); - plugin({ - cldAsset: cldImage, - options: { - src, - }, + SanitizePlugin.apply(cldImage, { + src, }); expect(cldImage.toURL()).toContain(`image/upload/turtle`); }); diff --git a/packages/url-loader/tests/plugins/underlays.spec.js b/packages/url-loader/tests/plugins/underlays.spec.js deleted file mode 100644 index 358bd680..00000000 --- a/packages/url-loader/tests/plugins/underlays.spec.js +++ /dev/null @@ -1,63 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; - -import { underlaysPlugin } from '../../src/plugins/underlays'; - -const { plugin } = underlaysPlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -const TEST_PUBLIC_ID = 'test-public-id'; - -describe('Plugins', () => { - describe('Underlays', () => { - it('should add an underlay configured by object', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const publicId = 'images/galaxy'; - const width = 1920; - const height = 1200; - const crop = 'fill'; - - const options = { - underlays: [{ - publicId, - width, - height, - crop, - }] - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`u_${publicId.replace(/\//g, ':')},w_${width},h_${height},c_${crop}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`); - }); - - it('should add an underlay by string', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const publicId = 'images/galaxy'; - const width = '1.0'; - const height = '1.0'; - const crop = 'fill'; - - const options = { - underlay: publicId - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`u_${publicId.replace(/\//g, ':')},c_${crop},w_${width},h_${height},fl_relative/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`); - }); - }); -}); \ No newline at end of file diff --git a/packages/url-loader/tests/plugins/underlays.spec.ts b/packages/url-loader/tests/plugins/underlays.spec.ts new file mode 100644 index 00000000..7dde0db6 --- /dev/null +++ b/packages/url-loader/tests/plugins/underlays.spec.ts @@ -0,0 +1,63 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; + +import { UnderlaysPlugin } from "../../src/plugins/underlays.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + describe("Underlays", () => { + it("should add an underlay configured by object", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const publicId = "images/galaxy"; + const width = 1920; + const height = 1200; + const crop = "fill"; + + const options = { + src: TEST_PUBLIC_ID, + underlays: [ + { + publicId, + width, + height, + crop, + }, + ], + } as const; + + UnderlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `u_${publicId.replace(/\//g, ":")},w_${width},h_${height},c_${crop}/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`, + ); + }); + + it("should add an underlay by string", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const publicId = "images/galaxy"; + const width = "1.0"; + const height = "1.0"; + const crop = "fill"; + + const options = { + src: TEST_PUBLIC_ID, + underlay: publicId, + }; + + UnderlaysPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `u_${publicId.replace(/\//g, ":")},c_${crop},w_${width},h_${height},fl_relative/fl_layer_apply,fl_no_overflow/${TEST_PUBLIC_ID}`, + ); + }); + }); +}); diff --git a/packages/url-loader/tests/plugins/zoompan.spec.js b/packages/url-loader/tests/plugins/zoompan.spec.js deleted file mode 100644 index 1251d580..00000000 --- a/packages/url-loader/tests/plugins/zoompan.spec.js +++ /dev/null @@ -1,132 +0,0 @@ -import { Cloudinary } from '@cloudinary/url-gen'; -import { describe, expect, it } from 'vitest'; -import { zoompanPlugin } from '../../src/plugins/zoompan'; - -const { plugin } = zoompanPlugin - -const cld = new Cloudinary({ - cloud: { - cloudName: 'test-cloud-name' - } -}); - -const TEST_PUBLIC_ID = 'test-public-id'; - -describe('Plugins', () => { - describe('Zoom pan', () => { - it('should add "e_zoompan"', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - zoompan: true - } - - const result = plugin({ - cldAsset: cldImage, - options - }); - - expect(result.options.format).toBe('auto:animated'); - expect(cldImage.toURL()).toContain(`e_zoompan`); - }); - - it('should not zoom pan', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - plugin({ - cldAsset: cldImage, - options: {} - }); - - expect(cldImage.toURL()).not.toContain(`e_zoompan`); - }); - - it('should add loop effect ', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - zoompan: "loop" - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`e_zoompan`); - expect(cldImage.toURL()).toContain(`e_loop`); - }); - - it('should add a custom zoompan', () => { - - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - zoompan: 'mode_ofc;maxzoom_3.2;du_5;fps_30' - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`e_zoompan:${options.zoompan}`); - }); - - it('should add a custom options', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - zoompan: { - loop: true, - options: 'to_(g_auto;zoom_1.4)' - } - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`e_zoompan:${options.zoompan.options}`); - expect(cldImage.toURL()).toContain('e_loop'); - }); - - it('should add a custom loop option', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - zoompan: { - options: 'string', - loop: 15 - } - } - - plugin({ - cldAsset: cldImage, - options - }); - - expect(cldImage.toURL()).toContain(`e_zoompan:${options.zoompan.options}/e_loop:${options.zoompan.loop}`); - }); - - it('should not override format', () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - zoompan: false - } - - const result = plugin({ - cldAsset: cldImage, - options - }); - - expect(result.options.format).toBe(undefined); - }); - - }); -}); diff --git a/packages/url-loader/tests/plugins/zoompan.spec.ts b/packages/url-loader/tests/plugins/zoompan.spec.ts new file mode 100644 index 00000000..5cfbd914 --- /dev/null +++ b/packages/url-loader/tests/plugins/zoompan.spec.ts @@ -0,0 +1,118 @@ +import { Cloudinary } from "@cloudinary/url-gen"; +import { describe, expect, it } from "vitest"; +import { ZoompanPlugin } from "../../src/plugins/zoompan.js"; + +const cld = new Cloudinary({ + cloud: { + cloudName: "test-cloud-name", + }, +}); + +const TEST_PUBLIC_ID = "test-public-id"; + +describe("Plugins", () => { + describe("Zoom pan", () => { + it('should add "e_zoompan"', () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + zoompan: true, + }; + + const result = ZoompanPlugin.apply(cldImage, options); + + expect(result.options?.format).toBe("auto:animated"); + expect(cldImage.toURL()).toContain(`e_zoompan`); + }); + + it("should not zoom pan", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + }; + + ZoompanPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).not.toContain(`e_zoompan`); + }); + + it("should add loop effect ", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + zoompan: "loop", + }; + + ZoompanPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain(`e_zoompan`); + expect(cldImage.toURL()).toContain(`e_loop`); + }); + + it("should add a custom zoompan", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + zoompan: "mode_ofc;maxzoom_3.2;du_5;fps_30", + }; + + ZoompanPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain(`e_zoompan:${options.zoompan}`); + }); + + it("should add a custom options", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + zoompan: { + loop: true, + options: "to_(g_auto;zoom_1.4)", + }, + }; + + ZoompanPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `e_zoompan:${options.zoompan.options}`, + ); + expect(cldImage.toURL()).toContain("e_loop"); + }); + + it("should add a custom loop option", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + zoompan: { + options: "string", + loop: 15, + }, + }; + + ZoompanPlugin.apply(cldImage, options); + + expect(cldImage.toURL()).toContain( + `e_zoompan:${options.zoompan.options}/e_loop:${options.zoompan.loop}`, + ); + }); + + it("should not override format", () => { + const cldImage = cld.image(TEST_PUBLIC_ID); + + const options = { + src: TEST_PUBLIC_ID, + zoompan: false, + }; + + const result = ZoompanPlugin.apply(cldImage, options); + + expect(result.options?.format).toBe(undefined); + }); + }); +}); diff --git a/packages/util/CHANGELOG.md b/packages/util/CHANGELOG.md index 6408b362..93cd4e18 100644 --- a/packages/util/CHANGELOG.md +++ b/packages/util/CHANGELOG.md @@ -26,52 +26,45 @@ # [@cloudinary-util/util-v3.3.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.3.1...@cloudinary-util/util-v3.3.2) (2024-08-28) - ### Bug Fixes -* update pollForProcessingImage style ([#189](https://github.com/cloudinary-community/cloudinary-util/issues/189)) ([72826a0](https://github.com/cloudinary-community/cloudinary-util/commit/72826a01c5c485f27dc0244f89e2b1ffbb8e3f14)) +- update pollForProcessingImage style ([#189](https://github.com/cloudinary-community/cloudinary-util/issues/189)) ([72826a0](https://github.com/cloudinary-community/cloudinary-util/commit/72826a01c5c485f27dc0244f89e2b1ffbb8e3f14)) # [@cloudinary-util/util-v3.3.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.3.0...@cloudinary-util/util-v3.3.1) (2024-08-28) - ### Bug Fixes -* add delay to pollForProcessingImage ([#188](https://github.com/cloudinary-community/cloudinary-util/issues/188)) ([f720c0f](https://github.com/cloudinary-community/cloudinary-util/commit/f720c0ffaaf5267fc83ec90954f2650dcd5ee88f)) +- add delay to pollForProcessingImage ([#188](https://github.com/cloudinary-community/cloudinary-util/issues/188)) ([f720c0f](https://github.com/cloudinary-community/cloudinary-util/commit/f720c0ffaaf5267fc83ec90954f2650dcd5ee88f)) # [@cloudinary-util/util-v3.3.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.2.0...@cloudinary-util/util-v3.3.0) (2024-08-28) - ### Features -* add pollForProcessingImage ([#187](https://github.com/cloudinary-community/cloudinary-util/issues/187)) ([8b7a1c7](https://github.com/cloudinary-community/cloudinary-util/commit/8b7a1c7b0a0bae9b32c8fbd8ac53960caf340c94)) +- add pollForProcessingImage ([#187](https://github.com/cloudinary-community/cloudinary-util/issues/187)) ([8b7a1c7](https://github.com/cloudinary-community/cloudinary-util/commit/8b7a1c7b0a0bae9b32c8fbd8ac53960caf340c94)) # [@cloudinary-util/util-v3.2.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.1.0...@cloudinary-util/util-v3.2.0) (2024-08-07) - ### Features -* url-loader@5.6.0 ([#166](https://github.com/cloudinary-community/cloudinary-util/issues/166)) ([26736af](https://github.com/cloudinary-community/cloudinary-util/commit/26736afe7c9e32bad971beb273c71a9519c36944)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) +- url-loader@5.6.0 ([#166](https://github.com/cloudinary-community/cloudinary-util/issues/166)) ([26736af](https://github.com/cloudinary-community/cloudinary-util/commit/26736afe7c9e32bad971beb273c71a9519c36944)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) # [@cloudinary-util/util-v3.2.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.1.0...@cloudinary-util/util-v3.2.0-beta.1) (2024-08-02) - ### Features -* getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) +- getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) # [@cloudinary-util/util-v3.2.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.1.0...@cloudinary-util/util-v3.2.0-beta.1) (2024-08-02) - ### Features -* getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) +- getUploadWidgetOptions, generateSignatureCallback, generateUploadWidgetResultCallback ([#165](https://github.com/cloudinary-community/cloudinary-util/issues/165)) ([4e3adc4](https://github.com/cloudinary-community/cloudinary-util/commit/4e3adc4317022ceb8031cda5372b5419ba8bafe7)), closes [#164](https://github.com/cloudinary-community/cloudinary-util/issues/164) # [@cloudinary-util/util-v3.1.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.0.2...@cloudinary-util/util-v3.1.0-beta.1) (2024-07-09) - ### Features -* Improve plugin types, modernize monorepo structure ([#161](https://github.com/cloudinary-community/cloudinary-util/issues/161)) ([8ad6066](https://github.com/cloudinary-community/cloudinary-util/commit/8ad60661d4b3c78c08e9dd1939171a689eeb7b08)) +- Improve plugin types, modernize monorepo structure ([#161](https://github.com/cloudinary-community/cloudinary-util/issues/161)) ([8ad6066](https://github.com/cloudinary-community/cloudinary-util/commit/8ad60661d4b3c78c08e9dd1939171a689eeb7b08)) # [@cloudinary-util/util-v3.0.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.0.1...@cloudinary-util/util-v3.0.2) (2024-05-24) diff --git a/packages/util/src/index.ts b/packages/util/src/index.ts index 04a487cf..6cd494d7 100644 --- a/packages/util/src/index.ts +++ b/packages/util/src/index.ts @@ -2,10 +2,11 @@ export { getFormat, getPublicId, getTransformations, + normalizeNumberParameter, parseUrl, pollForProcessingImage, + type ParseUrl, type PollForProcessingImageOptions, } from "./lib/cloudinary.js"; -export type { ParseUrl } from "./lib/cloudinary.js"; export { convertColorHexToRgb, testColorIsHex } from "./lib/colors.js"; export { encodeBase64, objectHasKey, sortByKey } from "./lib/util.js"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1bc4a7f2..e8de1004 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -140,16 +140,10 @@ importers: '@cloudinary/url-gen': specifier: 1.15.0 version: 1.15.0 - zod: - specifier: ^3.22.4 - version: 3.22.4 devDependencies: '@types/node': specifier: ^17.0.12 version: 17.0.45 - zod-to-ts: - specifier: ^1.2.0 - version: 1.2.0(typescript@5.5.2)(zod@3.22.4) packages/util: devDependencies: @@ -5361,12 +5355,6 @@ packages: peerDependencies: zod: ^3.22.4 - zod-to-ts@1.2.0: - resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==} - peerDependencies: - typescript: ^4.9.4 || ^5.0.2 - zod: ^3 - zod@3.22.4: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} @@ -7958,8 +7946,8 @@ snapshots: '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.5.2) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0) eslint-plugin-react: 7.34.3(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) @@ -7983,13 +7971,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 4.3.6 enhanced-resolve: 5.17.0 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.5 is-core-module: 2.13.1 @@ -8010,14 +7998,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.5.2) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -8048,7 +8036,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -8058,7 +8046,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -11436,11 +11424,6 @@ snapshots: dependencies: zod: 3.22.4 - zod-to-ts@1.2.0(typescript@5.5.2)(zod@3.22.4): - dependencies: - typescript: 5.5.2 - zod: 3.22.4 - zod@3.22.4: {} zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f1dcdd07..174f395d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,3 @@ packages: - - "docs" + # - "docs" - "packages/*" diff --git a/tsconfig.json b/tsconfig.json index 84f10a9d..6f181131 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "module": "NodeNext", "target": "ES2022", "moduleResolution": "NodeNext", - "lib": ["ESNext", "DOM"], + "lib": ["DOM", "ESNext"], "noEmit": true, "skipLibCheck": true, "strict": true, From 139d623a0bcae544c19fffddb996ae0438d54103 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 18 Oct 2024 18:12:51 +0000 Subject: [PATCH 02/21] chore(release): 5.0.0-beta.1 [skip ci] # [@cloudinary-util/util-v5.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v4.0.0...@cloudinary-util/util-v5.0.0-beta.1) (2024-10-18) ### Features * migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481)) --- packages/util/CHANGELOG.md | 7 +++++++ packages/util/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/util/CHANGELOG.md b/packages/util/CHANGELOG.md index 93cd4e18..d0422ae0 100644 --- a/packages/util/CHANGELOG.md +++ b/packages/util/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cloudinary-util/util-v5.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v4.0.0...@cloudinary-util/util-v5.0.0-beta.1) (2024-10-18) + + +### Features + +* migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481)) + # [@cloudinary-util/util-v4.0.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.4.0...@cloudinary-util/util-v4.0.0) (2024-10-15) diff --git a/packages/util/package.json b/packages/util/package.json index bf67b153..1e21ea38 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@cloudinary-util/util", - "version": "4.0.0", + "version": "5.0.0-beta.1", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", From 6c6b55e9fa724267fe475083d3a770f50e336e2a Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Fri, 18 Oct 2024 14:20:31 -0400 Subject: [PATCH 03/21] push From 689d02d3a617ef7a72f2b811ebbbc4cc1ab08bf7 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 18 Oct 2024 18:21:44 +0000 Subject: [PATCH 04/21] chore(release): 6.0.0-beta.1 [skip ci] # [@cloudinary-util/url-loader-v6.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.5...@cloudinary-util/url-loader-v6.0.0-beta.1) (2024-10-18) ### Features * migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481)) --- packages/url-loader/CHANGELOG.md | 7 +++++++ packages/url-loader/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/url-loader/CHANGELOG.md b/packages/url-loader/CHANGELOG.md index ba4c7295..25367ea3 100644 --- a/packages/url-loader/CHANGELOG.md +++ b/packages/url-loader/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cloudinary-util/url-loader-v6.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.5...@cloudinary-util/url-loader-v6.0.0-beta.1) (2024-10-18) + + +### Features + +* migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481)) + # [@cloudinary-util/url-loader-v5.10.5](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.4...@cloudinary-util/url-loader-v5.10.5) (2024-10-07) ### Bug Fixes diff --git a/packages/url-loader/package.json b/packages/url-loader/package.json index 793314ca..16b0a27e 100644 --- a/packages/url-loader/package.json +++ b/packages/url-loader/package.json @@ -1,6 +1,6 @@ { "name": "@cloudinary-util/url-loader", - "version": "5.10.5", + "version": "6.0.0-beta.1", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", From 8b99479510c6900a8975de0e8b2fcd1421005c35 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 18 Oct 2024 18:22:14 +0000 Subject: [PATCH 05/21] chore(release): 2.0.0-beta.1 [skip ci] # [@cloudinary-util/types-v2.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.11...@cloudinary-util/types-v2.0.0-beta.1) (2024-10-18) ### Features * migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481)) --- packages/types/CHANGELOG.md | 7 +++++++ packages/types/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 7167d311..372d8728 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cloudinary-util/types-v2.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.11...@cloudinary-util/types-v2.0.0-beta.1) (2024-10-18) + + +### Features + +* migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481)) + # [@cloudinary-util/types-v1.5.11](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.10...@cloudinary-util/types-v1.5.11) (2024-10-07) ### Bug Fixes diff --git a/packages/types/package.json b/packages/types/package.json index c0c2de04..5991db23 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@cloudinary-util/types", - "version": "1.5.11", + "version": "2.0.0-beta.1", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", From 05cd33e3948d486ac87600b798e0006789e2d914 Mon Sep 17 00:00:00 2001 From: Mrinank Bhowmick <77621953+Mrinank-Bhowmick@users.noreply.github.com> Date: Tue, 22 Oct 2024 18:01:57 +0530 Subject: [PATCH 06/21] fix: Add TypeScript Types for Cloudinary Product Gallery Widget (#218) # Description This pull request introduces TypeScript types for the Cloudinary Product Gallery Widget. It defines a comprehensive interface for the widget, following the reference documentation for better type safety and improved developer experience. No additional dependencies are required for this change. ## Issue Ticket Number 199 Fixes #199 ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Fix or improve the documentation - [ ] This change requires a documentation update # Checklist - [x] I have followed the contributing guidelines of this project as mentioned in [CONTRIBUTING.md](/CONTRIBUTING.md) - [x] I have created an [issue](https://github.com/colbyfayock/cloudinary-util/issues) ticket for this PR - [x] I have checked to ensure there aren't other open [Pull Requests](https://github.com/colbyfayock/cloudinary-util/pulls) for the same update/change? - [x] I have performed a self-review of my own code - [x] I have run tests locally to ensure they all pass - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes needed to the documentation --- packages/types/src/index.ts | 2 + .../src/types/cloudinary-product-gallery.ts | 135 ++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 packages/types/src/types/cloudinary-product-gallery.ts diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 1b13275b..2bd33ffe 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -37,6 +37,8 @@ export type { CloudinaryVideoPlayerTextTracksTrackOptionsTheme, } from "./types/cloudinary-video-player.js"; +export type { CloudinaryProductGallery } from "./types/cloudinary-product-gallery.js"; + export type { CloudinaryAssetConfiguration, CloudinaryAssetConfigurationAuthToken, diff --git a/packages/types/src/types/cloudinary-product-gallery.ts b/packages/types/src/types/cloudinary-product-gallery.ts new file mode 100644 index 00000000..2878095e --- /dev/null +++ b/packages/types/src/types/cloudinary-product-gallery.ts @@ -0,0 +1,135 @@ +export interface CloudinaryProductGallery { + // Required parameters + cloudName?: string; + mediaAssets?: + | { + publicId?: string; + tag?: string; + mediaType?: string; + resourceType?: string; + transformation?: object; + thumbnailTransformation?: object; + altText?: string; + videoPlayerSource?: object; + }[] + | string[]; // string[] is a list of publicIDs + container?: string | HTMLElement; + + // Widget + analytics?: boolean; + displayProps?: { + mode?: "classic" | "expanded"; + spacing?: number; + columns?: number; + topOffset?: number; + bottomOffset?: number; + }; + focus?: boolean; + loaderProps?: { + color?: string; + opacity?: number; + style?: "cloudinary" | "circle" | "custom"; + url?: string; + }; + placeholderImage?: boolean; + sort?: "none" | "asc" | "desc"; + sortProps?: { + source?: string; + id?: string; + direction?: string; + }; + themeProps?: { + primary?: string; // Default: "#FFFFFF" + onPrimary?: string; // Default: "#000000" + active?: string; // Default: "#0078FF" + }; + viewportBreakpoints?: { + breakpoint: number; // Required + [key: string]: any; // Other configuration parameters to override + }[]; + + // Main viewer parameters + accessibilityProps?: { + mediaAltSource?: string; + mediaAltId?: string; + }; + ar3dProps?: { + shadows?: boolean; + showAR?: boolean; + }; + aspectRatio?: + | "square" + | "1:1" + | "3:4" + | "4:3" + | "4:6" + | "6:4" + | "5:7" + | "7:5" + | "5:8" + | "8:5" + | "9:16" + | "16:9"; + borderColor?: string; + borderWidth?: number; + imageBreakpoint?: number; + videoBreakpoint?: number; + preload?: string[]; + radius?: number; + spinProps?: { + animate?: "none" | "start" | "end" | "both"; + spinDirection?: "clockwise" | "counter-clockwise"; + disableZoom?: boolean; + showTip?: "always" | "never" | "touch"; + tipPosition?: "top" | "center" | "bottom"; + tipText?: string; // Default: "Drag to rotate" + tipTouchText?: string; // Default: "Swipe to rotate" + }; + startIndex?: number; + tipProps?: { + textColor?: string; + color?: string; + radius?: number; + opacity?: number; + }; + transition?: "slide" | "fade" | "none"; + videoProps?: { + controls?: string; + sound?: boolean; + autoplay?: boolean; + loop?: boolean; + playerType?: string; + }; + zoom?: boolean; + zoomProps?: any; + zoomPopupProps?: { + backdropColor?: string; + backdropOpacity?: number; + zIndex?: number; + }; + + // Carousel parameters + carouselLocation?: "left" | "right" | "top" | "bottom"; + carouselOffset?: number; + carouselStyle?: "none" | "thumbnails" | "indicators"; + indicatorProps?: { + color?: string; + selectedColor?: string; + shape?: "round" | "square" | "radius"; + size?: number; + spacing?: number; + sticky?: boolean; + }; + thumbnailProps?: any; + + // Navigation parameters + navigation?: "none" | "always" | "mouseover"; + navigationButtonProps?: { + shape?: "none" | "round" | "square" | "radius" | "rectangle"; + iconColor?: string; + color?: string; + size?: number; + }; + navigationOffset?: number; + navigationPosition?: "inside" | "outside" | "offset"; +} From d262d802d2fd01f73f0df1aed1c51b6e66b35500 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 22 Oct 2024 12:33:05 +0000 Subject: [PATCH 07/21] chore(release): 2.0.0-beta.2 [skip ci] # [@cloudinary-util/types-v2.0.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v2.0.0-beta.1...@cloudinary-util/types-v2.0.0-beta.2) (2024-10-22) ### Bug Fixes * Add TypeScript Types for Cloudinary Product Gallery Widget ([#218](https://github.com/cloudinary-community/cloudinary-util/issues/218)) ([05cd33e](https://github.com/cloudinary-community/cloudinary-util/commit/05cd33e3948d486ac87600b798e0006789e2d914)), closes [#199](https://github.com/cloudinary-community/cloudinary-util/issues/199) --- packages/types/CHANGELOG.md | 7 +++++++ packages/types/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 372d8728..a4976f31 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cloudinary-util/types-v2.0.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v2.0.0-beta.1...@cloudinary-util/types-v2.0.0-beta.2) (2024-10-22) + + +### Bug Fixes + +* Add TypeScript Types for Cloudinary Product Gallery Widget ([#218](https://github.com/cloudinary-community/cloudinary-util/issues/218)) ([05cd33e](https://github.com/cloudinary-community/cloudinary-util/commit/05cd33e3948d486ac87600b798e0006789e2d914)), closes [#199](https://github.com/cloudinary-community/cloudinary-util/issues/199) + # [@cloudinary-util/types-v2.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.11...@cloudinary-util/types-v2.0.0-beta.1) (2024-10-18) diff --git a/packages/types/package.json b/packages/types/package.json index 5991db23..e8ce96b8 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@cloudinary-util/types", - "version": "2.0.0-beta.1", + "version": "2.0.0-beta.2", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", From e0b1bef0e8a844388766a9e6871a32cba925ea26 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 22 Oct 2024 13:11:32 +0000 Subject: [PATCH 08/21] chore(release): 6.0.0-beta.2 [skip ci] # [@cloudinary-util/url-loader-v6.0.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.1...@cloudinary-util/url-loader-v6.0.0-beta.2) (2024-10-22) ### Bug Fixes * Add enum for format parameter ([#220](https://github.com/cloudinary-community/cloudinary-util/issues/220)) ([0ecd331](https://github.com/cloudinary-community/cloudinary-util/commit/0ecd331e1bfe9244bedc82fc8d61e228bdc00d4c)), closes [#142](https://github.com/cloudinary-community/cloudinary-util/issues/142) --- packages/url-loader/CHANGELOG.md | 7 +++++++ packages/url-loader/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/url-loader/CHANGELOG.md b/packages/url-loader/CHANGELOG.md index 25367ea3..3549a56a 100644 --- a/packages/url-loader/CHANGELOG.md +++ b/packages/url-loader/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cloudinary-util/url-loader-v6.0.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.1...@cloudinary-util/url-loader-v6.0.0-beta.2) (2024-10-22) + + +### Bug Fixes + +* Add enum for format parameter ([#220](https://github.com/cloudinary-community/cloudinary-util/issues/220)) ([0ecd331](https://github.com/cloudinary-community/cloudinary-util/commit/0ecd331e1bfe9244bedc82fc8d61e228bdc00d4c)), closes [#142](https://github.com/cloudinary-community/cloudinary-util/issues/142) + # [@cloudinary-util/url-loader-v6.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.5...@cloudinary-util/url-loader-v6.0.0-beta.1) (2024-10-18) diff --git a/packages/url-loader/package.json b/packages/url-loader/package.json index 16b0a27e..39f917e0 100644 --- a/packages/url-loader/package.json +++ b/packages/url-loader/package.json @@ -1,6 +1,6 @@ { "name": "@cloudinary-util/url-loader", - "version": "6.0.0-beta.1", + "version": "6.0.0-beta.2", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", From 731d54511741f9bb56fc6b1d6e978a8f21d88082 Mon Sep 17 00:00:00 2001 From: David Blass Date: Thu, 24 Oct 2024 15:46:27 -0400 Subject: [PATCH 09/21] feat: enumerate plugin props (#224) # Description Based on a conversation with @colbyfayock, this adds back enumerated props for each plugin. They're collected via two top-level exports, `cloudinaryPluginProps` and `cloudinaryPluginKeys`, so we can expose which props are handled by cloudinary without all the implementation details of each plugin. --- packages/url-loader/src/index.ts | 2 + packages/url-loader/src/lib/cloudinary.ts | 20 ++++++- packages/url-loader/src/lib/plugin.ts | 6 +- packages/url-loader/src/plugins/abr.ts | 3 + packages/url-loader/src/plugins/cropping.ts | 6 ++ .../url-loader/src/plugins/default-image.ts | 1 + packages/url-loader/src/plugins/effects.ts | 55 +++++++++++++++++++ packages/url-loader/src/plugins/enhance.ts | 3 + packages/url-loader/src/plugins/extract.ts | 3 + .../url-loader/src/plugins/fill-background.ts | 3 + packages/url-loader/src/plugins/flags.ts | 3 + .../src/plugins/named-transformations.ts | 4 ++ packages/url-loader/src/plugins/overlays.ts | 4 ++ .../src/plugins/preserve-transformations.ts | 3 + .../src/plugins/raw-transformations.ts | 3 + packages/url-loader/src/plugins/recolor.ts | 3 + .../src/plugins/remove-background.ts | 3 + packages/url-loader/src/plugins/remove.ts | 3 + .../src/plugins/replace-background.ts | 3 + packages/url-loader/src/plugins/replace.ts | 3 + packages/url-loader/src/plugins/restore.ts | 3 + packages/url-loader/src/plugins/sanitize.ts | 3 + packages/url-loader/src/plugins/seo.ts | 3 + packages/url-loader/src/plugins/underlays.ts | 4 ++ packages/url-loader/src/plugins/version.ts | 3 + packages/url-loader/src/plugins/zoompan.ts | 3 + 26 files changed, 150 insertions(+), 3 deletions(-) diff --git a/packages/url-loader/src/index.ts b/packages/url-loader/src/index.ts index 7d7bf9e8..45c50a00 100644 --- a/packages/url-loader/src/index.ts +++ b/packages/url-loader/src/index.ts @@ -1,6 +1,8 @@ // URL Construction & Plugins export { + cloudinaryPluginKeys, + cloudinaryPluginProps, constructCloudinaryUrl, transformationPlugins, type AnalyticsOptions, diff --git a/packages/url-loader/src/lib/cloudinary.ts b/packages/url-loader/src/lib/cloudinary.ts index 3a508f40..bcc01085 100644 --- a/packages/url-loader/src/lib/cloudinary.ts +++ b/packages/url-loader/src/lib/cloudinary.ts @@ -38,14 +38,25 @@ import type { import type { ImageOptions } from "../types/image.js"; import type { PluginOptions, PluginResults } from "../types/plugins.js"; import type { VideoOptions } from "../types/video.js"; -import type { OptionsFor, TransformationPlugin } from "./plugin.js"; +import type { + CloudinaryKey, + OptionsFor, + TransformationPlugin, +} from "./plugin.js"; import { entriesOf, throwError } from "./utils.js"; +export const cloudinaryPluginProps = {} as Record; + const validatePlugins = ( ...plugins: plugins extends validatePlugins ? plugins : validatePlugins -) => plugins; +) => { + plugins.forEach((plugin) => { + Object.assign(cloudinaryPluginProps, plugin.props); + }); + return plugins; +}; export const transformationPlugins = validatePlugins( // Some features *must* be the first transformation applied @@ -87,6 +98,11 @@ export const transformationPlugins = validatePlugins( ZoompanPlugin ); +// important this comes after `validatePlugins` is called so we've collected the props +export const cloudinaryPluginKeys: readonly CloudinaryKey[] = Object.keys( + cloudinaryPluginProps +) as never; + export interface AnalyticsOptions extends IAnalyticsOptions {} export interface ConfigOptions extends CloudinaryAssetConfiguration {} diff --git a/packages/url-loader/src/lib/plugin.ts b/packages/url-loader/src/lib/plugin.ts index 03987970..4b3ddfc0 100644 --- a/packages/url-loader/src/lib/plugin.ts +++ b/packages/url-loader/src/lib/plugin.ts @@ -4,7 +4,9 @@ import type { PluginResults } from "../types/plugins.js"; import type { VideoOptions } from "../types/video.js"; import type { CldAsset } from "./cloudinary.js"; -interface AllOptions extends AssetOptions, ImageOptions, VideoOptions {} +export interface AllOptions extends AssetOptions, ImageOptions, VideoOptions {} + +export type CloudinaryKey = keyof AllOptions & {}; export type SupportedAssetType = "image" | "video" | "all"; @@ -24,6 +26,7 @@ export interface PluginDefinition< supports: assetType; apply: PluginApplication; inferOwnOptions: options; + props: Record; applyWhen?: when | undefined; strict?: boolean; } @@ -38,6 +41,7 @@ export interface TransformationPlugin< supports: assetType; apply: PluginApplication; inferOwnOptions: options; + props: Record; applyWhen?: when | undefined; strict?: boolean; } diff --git a/packages/url-loader/src/plugins/abr.ts b/packages/url-loader/src/plugins/abr.ts index ceb07551..44aa50b5 100644 --- a/packages/url-loader/src/plugins/abr.ts +++ b/packages/url-loader/src/plugins/abr.ts @@ -14,6 +14,9 @@ export const AbrPlugin = plugin({ name: "Abr", supports: "video", inferOwnOptions: {} as AbrPlugin.Options, + props: { + streamingProfile: true, + }, apply: (asset, opts) => { if (typeof opts.streamingProfile === "string") { asset.addTransformation(`sp_${opts.streamingProfile}`); diff --git a/packages/url-loader/src/plugins/cropping.ts b/packages/url-loader/src/plugins/cropping.ts index 988c5b91..d9d92bf9 100644 --- a/packages/url-loader/src/plugins/cropping.ts +++ b/packages/url-loader/src/plugins/cropping.ts @@ -44,6 +44,12 @@ export const CroppingPlugin = plugin({ name: "Cropping", supports: "all", inferOwnOptions: {} as CroppingPlugin.Options, + props: { + aspectRatio: true, + crop: true, + gravity: true, + zoom: true, + }, // crop is applied even if the crop key is undefined apply: (asset, opts) => { let crops: Array = []; diff --git a/packages/url-loader/src/plugins/default-image.ts b/packages/url-loader/src/plugins/default-image.ts index 3f364a93..76070c6d 100644 --- a/packages/url-loader/src/plugins/default-image.ts +++ b/packages/url-loader/src/plugins/default-image.ts @@ -15,6 +15,7 @@ export const DefaultImagePlugin = plugin({ name: "DefaultImage", supports: "image", inferOwnOptions: {} as DefaultImagePlugin.Options, + props: { defaultImage: true }, apply: (asset, opts) => { const { defaultImage } = opts; diff --git a/packages/url-loader/src/plugins/effects.ts b/packages/url-loader/src/plugins/effects.ts index 7ff81901..d01cc938 100644 --- a/packages/url-loader/src/plugins/effects.ts +++ b/packages/url-loader/src/plugins/effects.ts @@ -21,6 +21,61 @@ export const EffectsPlugin = plugin({ name: "Effects", supports: "all", inferOwnOptions: {} as EffectsPlugin.Options, + props: { + angle: true, + art: true, + autoBrightness: true, + autoColor: true, + autoContrast: true, + assistColorblind: true, + background: true, + blackwhite: true, + blur: true, + blurFaces: true, + blurRegion: true, + border: true, + brightness: true, + brightnessHSB: true, + cartoonify: true, + color: true, + colorize: true, + contrast: true, + displace: true, + distort: true, + fillLight: true, + gamma: true, + gradientFade: true, + grayscale: true, + hue: true, + improve: true, + loop: true, + multiply: true, + negate: true, + noise: true, + oilPaint: true, + opacity: true, + outline: true, + pixelate: true, + pixelateFaces: true, + pixelateRegion: true, + radius: true, + redeye: true, + replaceColor: true, + saturation: true, + screen: true, + sepia: true, + shadow: true, + sharpen: true, + shear: true, + simulateColorblind: true, + tint: true, + trim: true, + unsharpMask: true, + vectorize: true, + vibrance: true, + vignette: true, + effects: true, + }, apply: (cldAsset, options) => { // Handle any top-level effect props diff --git a/packages/url-loader/src/plugins/enhance.ts b/packages/url-loader/src/plugins/enhance.ts index 1a959542..0347a130 100644 --- a/packages/url-loader/src/plugins/enhance.ts +++ b/packages/url-loader/src/plugins/enhance.ts @@ -14,6 +14,9 @@ export const EnhancePlugin = plugin({ name: "Enhance", supports: "image", inferOwnOptions: {} as EnhancePlugin.Options, + props: { + enhance: true, + }, apply: (cldAsset, options) => { if (options.enhance) { cldAsset.addTransformation("e_enhance"); diff --git a/packages/url-loader/src/plugins/extract.ts b/packages/url-loader/src/plugins/extract.ts index 3f319322..53a66ec2 100644 --- a/packages/url-loader/src/plugins/extract.ts +++ b/packages/url-loader/src/plugins/extract.ts @@ -28,6 +28,9 @@ export const ExtractPlugin = plugin({ supports: "image", applyWhen: "extract", inferOwnOptions: {} as ExtractPlugin.Options, + props: { + extract: true, + }, apply: (cldAsset, { extract }) => { const properties = []; diff --git a/packages/url-loader/src/plugins/fill-background.ts b/packages/url-loader/src/plugins/fill-background.ts index 14756580..610863b5 100644 --- a/packages/url-loader/src/plugins/fill-background.ts +++ b/packages/url-loader/src/plugins/fill-background.ts @@ -28,6 +28,9 @@ export const FillBackgroundPlugin = plugin({ name: "FillBackground", supports: "image", inferOwnOptions: {} as FillBackgroundPlugin.Options, + props: { + fillBackground: true, + }, apply: (cldAsset, options) => { const { fillBackground } = options; diff --git a/packages/url-loader/src/plugins/flags.ts b/packages/url-loader/src/plugins/flags.ts index 62abb49e..d2c09a9a 100644 --- a/packages/url-loader/src/plugins/flags.ts +++ b/packages/url-loader/src/plugins/flags.ts @@ -13,6 +13,9 @@ export const FlagsPlugin = plugin({ supports: "all", applyWhen: "flags", inferOwnOptions: {} as FlagsPlugin.Options, + props: { + flags: true, + }, apply: (cldAsset, { flags }) => { // First iteration of adding flags follows the same pattern // as the top level option from Cloudinary URL Gen SDK where diff --git a/packages/url-loader/src/plugins/named-transformations.ts b/packages/url-loader/src/plugins/named-transformations.ts index 0e2ad8dc..924628e3 100644 --- a/packages/url-loader/src/plugins/named-transformations.ts +++ b/packages/url-loader/src/plugins/named-transformations.ts @@ -22,6 +22,10 @@ export const NamedTransformationsPlugin = plugin({ strict: true, supports: "all", inferOwnOptions: {} as NamedTransformationsPlugin.Options, + props: { + namedTransformations: true, + transformations: true, + }, apply: (cldAsset, options) => { const { transformations, namedTransformations } = options; diff --git a/packages/url-loader/src/plugins/overlays.ts b/packages/url-loader/src/plugins/overlays.ts index 2fdbc817..9d1ebde3 100644 --- a/packages/url-loader/src/plugins/overlays.ts +++ b/packages/url-loader/src/plugins/overlays.ts @@ -73,6 +73,10 @@ export const OverlaysPlugin = plugin({ name: "Overlays", supports: "all", inferOwnOptions: {} as OverlaysPlugin.Options, + props: { + overlays: true, + text: true, + }, apply: (cldAsset, options) => { const { text, overlays = [] } = options; diff --git a/packages/url-loader/src/plugins/preserve-transformations.ts b/packages/url-loader/src/plugins/preserve-transformations.ts index 8adb53f4..19c8995c 100644 --- a/packages/url-loader/src/plugins/preserve-transformations.ts +++ b/packages/url-loader/src/plugins/preserve-transformations.ts @@ -14,6 +14,9 @@ export const PreserveTransformationsPlugin = plugin({ name: "PreserveTransformations", supports: "all", inferOwnOptions: {} as PreserveTransformationsPlugin.Options, + props: { + preserveTransformations: true, + }, apply: (cldAsset, options) => { const { preserveTransformations = false } = options; diff --git a/packages/url-loader/src/plugins/raw-transformations.ts b/packages/url-loader/src/plugins/raw-transformations.ts index a7e61036..6ca1ab2c 100644 --- a/packages/url-loader/src/plugins/raw-transformations.ts +++ b/packages/url-loader/src/plugins/raw-transformations.ts @@ -15,6 +15,9 @@ export const RawTransformationsPlugin = plugin({ name: "RawTransformations", supports: "all", inferOwnOptions: {} as RawTransformationsPlugin.Options, + props: { + rawTransformations: true, + }, apply: (cldAsset, options) => { let { rawTransformations = [] } = options; diff --git a/packages/url-loader/src/plugins/recolor.ts b/packages/url-loader/src/plugins/recolor.ts index c11a9512..da394613 100644 --- a/packages/url-loader/src/plugins/recolor.ts +++ b/packages/url-loader/src/plugins/recolor.ts @@ -27,6 +27,9 @@ export const RecolorPlugin = plugin({ name: "Recolor", supports: "image", inferOwnOptions: {} as RecolorPlugin.Options, + props: { + recolor: true, + }, apply: (cldAsset, options) => { const { recolor } = options; diff --git a/packages/url-loader/src/plugins/remove-background.ts b/packages/url-loader/src/plugins/remove-background.ts index 5a626809..193f3fd0 100644 --- a/packages/url-loader/src/plugins/remove-background.ts +++ b/packages/url-loader/src/plugins/remove-background.ts @@ -14,6 +14,9 @@ export const RemoveBackgroundPlugin = plugin({ name: "RemoveBackground", supports: "image", inferOwnOptions: {} as RemoveBackgroundPlugin.Options, + props: { + removeBackground: true, + }, apply: (cldAsset, options) => { if (options.removeBackground) { cldAsset.addTransformation("e_background_removal"); diff --git a/packages/url-loader/src/plugins/remove.ts b/packages/url-loader/src/plugins/remove.ts index e6ef69e3..ab48e95d 100644 --- a/packages/url-loader/src/plugins/remove.ts +++ b/packages/url-loader/src/plugins/remove.ts @@ -24,6 +24,9 @@ export const RemovePlugin = plugin({ name: "Remove", supports: "image", inferOwnOptions: {} as RemovePlugin.Options, + props: { + remove: true, + }, apply: (cldAsset, options) => { const { remove } = options; diff --git a/packages/url-loader/src/plugins/replace-background.ts b/packages/url-loader/src/plugins/replace-background.ts index b038cdb6..829aa138 100644 --- a/packages/url-loader/src/plugins/replace-background.ts +++ b/packages/url-loader/src/plugins/replace-background.ts @@ -19,6 +19,9 @@ export const ReplaceBackgroundPlugin = plugin({ name: "ReplaceBackground", supports: "image", inferOwnOptions: {} as ReplaceBackgroundPlugin.Options, + props: { + replaceBackground: true, + }, apply: (cldAsset, options) => { const { replaceBackground } = options; diff --git a/packages/url-loader/src/plugins/replace.ts b/packages/url-loader/src/plugins/replace.ts index e883e8b9..3463473d 100644 --- a/packages/url-loader/src/plugins/replace.ts +++ b/packages/url-loader/src/plugins/replace.ts @@ -21,6 +21,9 @@ export const ReplacePlugin = plugin({ name: "Replace", supports: "image", inferOwnOptions: {} as ReplacePlugin.Options, + props: { + replace: true, + }, apply: (cldAsset, options) => { const { replace = null } = options; diff --git a/packages/url-loader/src/plugins/restore.ts b/packages/url-loader/src/plugins/restore.ts index 0b0d6160..21966b91 100644 --- a/packages/url-loader/src/plugins/restore.ts +++ b/packages/url-loader/src/plugins/restore.ts @@ -14,6 +14,9 @@ export const RestorePlugin = plugin({ name: "Restore", supports: "image", inferOwnOptions: {} as RestorePlugin.Options, + props: { + restore: true, + }, apply: (cldAsset, options) => { const { restore = false } = options; diff --git a/packages/url-loader/src/plugins/sanitize.ts b/packages/url-loader/src/plugins/sanitize.ts index 63bd8145..3c24c39c 100644 --- a/packages/url-loader/src/plugins/sanitize.ts +++ b/packages/url-loader/src/plugins/sanitize.ts @@ -14,6 +14,9 @@ export const SanitizePlugin = plugin({ name: "Sanitize", supports: "image", inferOwnOptions: {} as SanitizePlugin.Options, + props: { + sanitize: true, + }, apply: (cldAsset, options) => { const { sanitize = true } = options; diff --git a/packages/url-loader/src/plugins/seo.ts b/packages/url-loader/src/plugins/seo.ts index afceea67..42c7292d 100644 --- a/packages/url-loader/src/plugins/seo.ts +++ b/packages/url-loader/src/plugins/seo.ts @@ -14,6 +14,9 @@ export const SeoPlugin = plugin({ name: "Seo", supports: "all", inferOwnOptions: {} as SeoPlugin.Options, + props: { + seoSuffix: true, + }, apply: (cldAsset, options) => { const { seoSuffix } = options; diff --git a/packages/url-loader/src/plugins/underlays.ts b/packages/url-loader/src/plugins/underlays.ts index fec4745f..9378e456 100644 --- a/packages/url-loader/src/plugins/underlays.ts +++ b/packages/url-loader/src/plugins/underlays.ts @@ -46,6 +46,10 @@ export const UnderlaysPlugin = plugin({ name: "Underlays", supports: "all", inferOwnOptions: {} as UnderlaysPlugin.Options, + props: { + underlay: true, + underlays: true, + }, apply: (cldAsset, options) => { const { underlay, underlays = [] } = options; diff --git a/packages/url-loader/src/plugins/version.ts b/packages/url-loader/src/plugins/version.ts index 79584c6e..f762b76d 100644 --- a/packages/url-loader/src/plugins/version.ts +++ b/packages/url-loader/src/plugins/version.ts @@ -14,6 +14,9 @@ export const VersionPlugin = plugin({ name: "Version", supports: "all", inferOwnOptions: {} as VersionPlugin.Options, + props: { + version: true, + }, apply: (cldAsset, options) => { const { version } = options; diff --git a/packages/url-loader/src/plugins/zoompan.ts b/packages/url-loader/src/plugins/zoompan.ts index 899316ee..5866df06 100644 --- a/packages/url-loader/src/plugins/zoompan.ts +++ b/packages/url-loader/src/plugins/zoompan.ts @@ -21,6 +21,9 @@ export const ZoompanPlugin = plugin({ name: "Zoompan", supports: "image", inferOwnOptions: {} as ZoompanPlugin.Options, + props: { + zoompan: true, + }, apply: (cldAsset, options) => { const { zoompan = false } = options; From 2f8615672f9c88e3a4cee9482c627cfc2936fe47 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 24 Oct 2024 19:47:45 +0000 Subject: [PATCH 10/21] chore(release): 6.0.0-beta.3 [skip ci] # [@cloudinary-util/url-loader-v6.0.0-beta.3](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.2...@cloudinary-util/url-loader-v6.0.0-beta.3) (2024-10-24) ### Features * enumerate plugin props ([#224](https://github.com/cloudinary-community/cloudinary-util/issues/224)) ([731d545](https://github.com/cloudinary-community/cloudinary-util/commit/731d54511741f9bb56fc6b1d6e978a8f21d88082)) --- packages/url-loader/CHANGELOG.md | 7 +++++++ packages/url-loader/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/url-loader/CHANGELOG.md b/packages/url-loader/CHANGELOG.md index 6e877a0a..51ae8296 100644 --- a/packages/url-loader/CHANGELOG.md +++ b/packages/url-loader/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cloudinary-util/url-loader-v6.0.0-beta.3](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.2...@cloudinary-util/url-loader-v6.0.0-beta.3) (2024-10-24) + + +### Features + +* enumerate plugin props ([#224](https://github.com/cloudinary-community/cloudinary-util/issues/224)) ([731d545](https://github.com/cloudinary-community/cloudinary-util/commit/731d54511741f9bb56fc6b1d6e978a8f21d88082)) + # [@cloudinary-util/url-loader-v6.0.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.1...@cloudinary-util/url-loader-v6.0.0-beta.2) (2024-10-22) diff --git a/packages/url-loader/package.json b/packages/url-loader/package.json index 39f917e0..bb249864 100644 --- a/packages/url-loader/package.json +++ b/packages/url-loader/package.json @@ -1,6 +1,6 @@ { "name": "@cloudinary-util/url-loader", - "version": "6.0.0-beta.2", + "version": "6.0.0-beta.3", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", From 672009afb7797c540c0a6fdc31115f0c245ed8b2 Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Fri, 25 Oct 2024 14:33:40 -0400 Subject: [PATCH 11/21] fix: adding string and number back to replaceBackground --- packages/url-loader/src/plugins/replace-background.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/url-loader/src/plugins/replace-background.ts b/packages/url-loader/src/plugins/replace-background.ts index 829aa138..6a42e8ef 100644 --- a/packages/url-loader/src/plugins/replace-background.ts +++ b/packages/url-loader/src/plugins/replace-background.ts @@ -6,7 +6,7 @@ export declare namespace ReplaceBackgroundPlugin { * @description Replaces the background of an image with an AI-generated background. * @url https://cloudinary.com/documentation/transformation_reference#e_gen_background_replace */ - replaceBackground?: NestedOptions; + replaceBackground?: NestedOptions | string | number; } export interface NestedOptions { From ef7e57adc03afb0e08ebf2bb0053d34c12054523 Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Fri, 25 Oct 2024 14:35:52 -0400 Subject: [PATCH 12/21] fix: adding applyWhen to streaming profile to prevent abr plugin from running --- packages/url-loader/src/plugins/abr.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/url-loader/src/plugins/abr.ts b/packages/url-loader/src/plugins/abr.ts index 44aa50b5..eb1d903f 100644 --- a/packages/url-loader/src/plugins/abr.ts +++ b/packages/url-loader/src/plugins/abr.ts @@ -14,6 +14,7 @@ export const AbrPlugin = plugin({ name: "Abr", supports: "video", inferOwnOptions: {} as AbrPlugin.Options, + applyWhen: 'streamingProfile', props: { streamingProfile: true, }, From 5e9849e7c0f7efe78ac410c97a3cafe36cc25108 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 25 Oct 2024 18:37:10 +0000 Subject: [PATCH 13/21] chore(release): 6.0.0-beta.4 [skip ci] # [@cloudinary-util/url-loader-v6.0.0-beta.4](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.3...@cloudinary-util/url-loader-v6.0.0-beta.4) (2024-10-25) ### Bug Fixes * adding applyWhen to streaming profile to prevent abr plugin from running ([ef7e57a](https://github.com/cloudinary-community/cloudinary-util/commit/ef7e57adc03afb0e08ebf2bb0053d34c12054523)) * adding string and number back to replaceBackground ([672009a](https://github.com/cloudinary-community/cloudinary-util/commit/672009afb7797c540c0a6fdc31115f0c245ed8b2)) --- packages/url-loader/CHANGELOG.md | 8 ++++++++ packages/url-loader/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/url-loader/CHANGELOG.md b/packages/url-loader/CHANGELOG.md index 51ae8296..7435dcdc 100644 --- a/packages/url-loader/CHANGELOG.md +++ b/packages/url-loader/CHANGELOG.md @@ -1,3 +1,11 @@ +# [@cloudinary-util/url-loader-v6.0.0-beta.4](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.3...@cloudinary-util/url-loader-v6.0.0-beta.4) (2024-10-25) + + +### Bug Fixes + +* adding applyWhen to streaming profile to prevent abr plugin from running ([ef7e57a](https://github.com/cloudinary-community/cloudinary-util/commit/ef7e57adc03afb0e08ebf2bb0053d34c12054523)) +* adding string and number back to replaceBackground ([672009a](https://github.com/cloudinary-community/cloudinary-util/commit/672009afb7797c540c0a6fdc31115f0c245ed8b2)) + # [@cloudinary-util/url-loader-v6.0.0-beta.3](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.2...@cloudinary-util/url-loader-v6.0.0-beta.3) (2024-10-24) diff --git a/packages/url-loader/package.json b/packages/url-loader/package.json index bb249864..f20e5d1b 100644 --- a/packages/url-loader/package.json +++ b/packages/url-loader/package.json @@ -1,6 +1,6 @@ { "name": "@cloudinary-util/url-loader", - "version": "6.0.0-beta.3", + "version": "6.0.0-beta.4", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", From 163cb2fdd05c7a3444cfb22edade79891f25ffd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 31 Oct 2024 18:47:29 +0100 Subject: [PATCH 14/21] fix: make plugins and cloudinaryPluginProps tree-shakeable (#227) --- packages/url-loader/src/lib/cloudinary.ts | 38 ++++++++++++----------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/url-loader/src/lib/cloudinary.ts b/packages/url-loader/src/lib/cloudinary.ts index bcc01085..5e91f5b9 100644 --- a/packages/url-loader/src/lib/cloudinary.ts +++ b/packages/url-loader/src/lib/cloudinary.ts @@ -45,20 +45,7 @@ import type { } from "./plugin.js"; import { entriesOf, throwError } from "./utils.js"; -export const cloudinaryPluginProps = {} as Record; - -const validatePlugins = ( - ...plugins: plugins extends validatePlugins - ? plugins - : validatePlugins -) => { - plugins.forEach((plugin) => { - Object.assign(cloudinaryPluginProps, plugin.props); - }); - return plugins; -}; - -export const transformationPlugins = validatePlugins( +export const transformationPlugins = [ // Some features *must* be the first transformation applied // thus their plugins *must* come first in the chain @@ -96,10 +83,25 @@ export const transformationPlugins = validatePlugins( UnderlaysPlugin, VersionPlugin, ZoompanPlugin -); +] as const; + +const getCloudinaryPluginProps = ( + plugins: plugins extends validatePlugins + ? plugins + : validatePlugins +): Record => { + const cloudinaryPluginProps = {} as Record; + + plugins.forEach((plugin) => { + Object.assign(cloudinaryPluginProps, plugin.props); + }); + + return cloudinaryPluginProps; +}; + +export const cloudinaryPluginProps = /* #__PURE__ */ getCloudinaryPluginProps(transformationPlugins); -// important this comes after `validatePlugins` is called so we've collected the props -export const cloudinaryPluginKeys: readonly CloudinaryKey[] = Object.keys( +export const cloudinaryPluginKeys: readonly CloudinaryKey[] = /* #__PURE__ */ Object.keys( cloudinaryPluginProps ) as never; @@ -355,7 +357,7 @@ type validatePlugins< ] ? validatePlugins< rest, - [ + readonly [ ...validated, keyof opts & keyof next["inferOwnOptions"] extends never ? // if the intersection is never, no options duplicate existing so the plugin is valid From 23e9afd3180ecdcf93d898b07ebc1a7d7e0e2c35 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Oct 2024 17:48:47 +0000 Subject: [PATCH 15/21] chore(release): 6.0.0-beta.5 [skip ci] # [@cloudinary-util/url-loader-v6.0.0-beta.5](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.4...@cloudinary-util/url-loader-v6.0.0-beta.5) (2024-10-31) ### Bug Fixes * make plugins and cloudinaryPluginProps tree-shakeable ([#227](https://github.com/cloudinary-community/cloudinary-util/issues/227)) ([163cb2f](https://github.com/cloudinary-community/cloudinary-util/commit/163cb2fdd05c7a3444cfb22edade79891f25ffd3)) --- packages/url-loader/CHANGELOG.md | 7 +++++++ packages/url-loader/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/url-loader/CHANGELOG.md b/packages/url-loader/CHANGELOG.md index 7435dcdc..6a8ef103 100644 --- a/packages/url-loader/CHANGELOG.md +++ b/packages/url-loader/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cloudinary-util/url-loader-v6.0.0-beta.5](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.4...@cloudinary-util/url-loader-v6.0.0-beta.5) (2024-10-31) + + +### Bug Fixes + +* make plugins and cloudinaryPluginProps tree-shakeable ([#227](https://github.com/cloudinary-community/cloudinary-util/issues/227)) ([163cb2f](https://github.com/cloudinary-community/cloudinary-util/commit/163cb2fdd05c7a3444cfb22edade79891f25ffd3)) + # [@cloudinary-util/url-loader-v6.0.0-beta.4](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.3...@cloudinary-util/url-loader-v6.0.0-beta.4) (2024-10-25) diff --git a/packages/url-loader/package.json b/packages/url-loader/package.json index f20e5d1b..6e687f4f 100644 --- a/packages/url-loader/package.json +++ b/packages/url-loader/package.json @@ -1,6 +1,6 @@ { "name": "@cloudinary-util/url-loader", - "version": "6.0.0-beta.4", + "version": "6.0.0-beta.5", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", From 90d07c2a302a628e6c6e0352d479608131d45d65 Mon Sep 17 00:00:00 2001 From: David Blass Date: Thu, 31 Oct 2024 15:01:48 -0400 Subject: [PATCH 16/21] fix: remove applyWhen in favor of explicit props overlap check with alwaysApply exception (#228) # Description Simplify applyWhen to just check for presence of props from the new props key as discussed with @colbyfayock, add an alwaysApply key that can be used for exceptions like SanitizePlugin that should always run regardless of the presence of associated keys. This is a rebased version of https://github.com/cloudinary-community/cloudinary-util/pull/226. ## Issue Ticket Number Fixes # ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Fix or improve the documentation - [ ] This change requires a documentation update # Checklist - [ ] I have followed the contributing guidelines of this project as mentioned in [CONTRIBUTING.md](/CONTRIBUTING.md) - [ ] I have created an [issue](https://github.com/colbyfayock/cloudinary-util/issues) ticket for this PR - [ ] I have checked to ensure there aren't other open [Pull Requests](https://github.com/colbyfayock/cloudinary-util/pulls) for the same update/change? - [ ] I have performed a self-review of my own code - [ ] I have run tests locally to ensure they all pass - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes needed to the documentation --- .../components/SchemaTable/SchemaTable.tsx | 2 +- packages/types/CHANGELOG.md | 6 +- packages/url-loader/CHANGELOG.md | 18 +- packages/url-loader/src/lib/cloudinary.ts | 17 +- packages/url-loader/src/lib/plugin.ts | 82 +- packages/url-loader/src/lib/upload.ts | 4 +- packages/url-loader/src/lib/utils.ts | 2 +- packages/url-loader/src/lib/video-player.ts | 6 +- packages/url-loader/src/plugins/abr.ts | 7 +- packages/url-loader/src/plugins/cropping.ts | 10 + .../url-loader/src/plugins/default-image.ts | 16 +- packages/url-loader/src/plugins/effects.ts | 10 +- packages/url-loader/src/plugins/enhance.ts | 4 +- packages/url-loader/src/plugins/extract.ts | 1 - .../url-loader/src/plugins/fill-background.ts | 10 +- packages/url-loader/src/plugins/flags.ts | 1 - .../src/plugins/named-transformations.ts | 6 +- packages/url-loader/src/plugins/overlays.ts | 12 +- .../src/plugins/preserve-transformations.ts | 12 +- .../src/plugins/raw-transformations.ts | 4 +- packages/url-loader/src/plugins/recolor.ts | 4 +- .../src/plugins/remove-background.ts | 4 +- packages/url-loader/src/plugins/remove.ts | 8 +- .../src/plugins/replace-background.ts | 9 +- packages/url-loader/src/plugins/replace.ts | 52 +- packages/url-loader/src/plugins/restore.ts | 4 +- packages/url-loader/src/plugins/sanitize.ts | 7 +- packages/url-loader/src/plugins/seo.ts | 18 +- packages/url-loader/src/plugins/underlays.ts | 6 +- packages/url-loader/src/plugins/version.ts | 14 +- packages/url-loader/src/plugins/zoompan.ts | 4 +- packages/url-loader/src/types/asset.ts | 10 +- .../url-loader/tests/plugins/default.spec.ts | 6 +- .../tests/plugins/remove-background.spec.ts | 12 - .../url-loader/tests/plugins/replace.spec.ts | 12 - .../url-loader/tests/plugins/restore.spec.ts | 12 - .../url-loader/tests/plugins/zoompan.spec.ts | 12 - packages/util/CHANGELOG.md | 15 +- packages/util/src/lib/cloudinary.ts | 4 +- packages/util/src/lib/util.ts | 2 +- pnpm-lock.yaml | 3286 +---------------- 41 files changed, 318 insertions(+), 3413 deletions(-) diff --git a/docs/src/components/SchemaTable/SchemaTable.tsx b/docs/src/components/SchemaTable/SchemaTable.tsx index db51dae8..aa30564e 100644 --- a/docs/src/components/SchemaTable/SchemaTable.tsx +++ b/docs/src/components/SchemaTable/SchemaTable.tsx @@ -59,7 +59,7 @@ export const SchemaTable = ({ schema, schemaKey }) => { }; return property; - } + }, ); const sortedProperties = sortByKey(formattedProperties, "name"); diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index a4976f31..7d044d01 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,16 +1,14 @@ # [@cloudinary-util/types-v2.0.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v2.0.0-beta.1...@cloudinary-util/types-v2.0.0-beta.2) (2024-10-22) - ### Bug Fixes -* Add TypeScript Types for Cloudinary Product Gallery Widget ([#218](https://github.com/cloudinary-community/cloudinary-util/issues/218)) ([05cd33e](https://github.com/cloudinary-community/cloudinary-util/commit/05cd33e3948d486ac87600b798e0006789e2d914)), closes [#199](https://github.com/cloudinary-community/cloudinary-util/issues/199) +- Add TypeScript Types for Cloudinary Product Gallery Widget ([#218](https://github.com/cloudinary-community/cloudinary-util/issues/218)) ([05cd33e](https://github.com/cloudinary-community/cloudinary-util/commit/05cd33e3948d486ac87600b798e0006789e2d914)), closes [#199](https://github.com/cloudinary-community/cloudinary-util/issues/199) # [@cloudinary-util/types-v2.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.11...@cloudinary-util/types-v2.0.0-beta.1) (2024-10-18) - ### Features -* migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481)) +- migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481)) # [@cloudinary-util/types-v1.5.11](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.10...@cloudinary-util/types-v1.5.11) (2024-10-07) diff --git a/packages/url-loader/CHANGELOG.md b/packages/url-loader/CHANGELOG.md index 6a8ef103..b8e22582 100644 --- a/packages/url-loader/CHANGELOG.md +++ b/packages/url-loader/CHANGELOG.md @@ -1,43 +1,39 @@ # [@cloudinary-util/url-loader-v6.0.0-beta.5](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.4...@cloudinary-util/url-loader-v6.0.0-beta.5) (2024-10-31) - ### Bug Fixes -* make plugins and cloudinaryPluginProps tree-shakeable ([#227](https://github.com/cloudinary-community/cloudinary-util/issues/227)) ([163cb2f](https://github.com/cloudinary-community/cloudinary-util/commit/163cb2fdd05c7a3444cfb22edade79891f25ffd3)) +- make plugins and cloudinaryPluginProps tree-shakeable ([#227](https://github.com/cloudinary-community/cloudinary-util/issues/227)) ([163cb2f](https://github.com/cloudinary-community/cloudinary-util/commit/163cb2fdd05c7a3444cfb22edade79891f25ffd3)) # [@cloudinary-util/url-loader-v6.0.0-beta.4](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.3...@cloudinary-util/url-loader-v6.0.0-beta.4) (2024-10-25) - ### Bug Fixes -* adding applyWhen to streaming profile to prevent abr plugin from running ([ef7e57a](https://github.com/cloudinary-community/cloudinary-util/commit/ef7e57adc03afb0e08ebf2bb0053d34c12054523)) -* adding string and number back to replaceBackground ([672009a](https://github.com/cloudinary-community/cloudinary-util/commit/672009afb7797c540c0a6fdc31115f0c245ed8b2)) +- adding applyWhen to streaming profile to prevent abr plugin from running ([ef7e57a](https://github.com/cloudinary-community/cloudinary-util/commit/ef7e57adc03afb0e08ebf2bb0053d34c12054523)) +- adding string and number back to replaceBackground ([672009a](https://github.com/cloudinary-community/cloudinary-util/commit/672009afb7797c540c0a6fdc31115f0c245ed8b2)) # [@cloudinary-util/url-loader-v6.0.0-beta.3](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.2...@cloudinary-util/url-loader-v6.0.0-beta.3) (2024-10-24) - ### Features -* enumerate plugin props ([#224](https://github.com/cloudinary-community/cloudinary-util/issues/224)) ([731d545](https://github.com/cloudinary-community/cloudinary-util/commit/731d54511741f9bb56fc6b1d6e978a8f21d88082)) +- enumerate plugin props ([#224](https://github.com/cloudinary-community/cloudinary-util/issues/224)) ([731d545](https://github.com/cloudinary-community/cloudinary-util/commit/731d54511741f9bb56fc6b1d6e978a8f21d88082)) # [@cloudinary-util/url-loader-v6.0.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.1...@cloudinary-util/url-loader-v6.0.0-beta.2) (2024-10-22) - ### Bug Fixes -* Add enum for format parameter ([#220](https://github.com/cloudinary-community/cloudinary-util/issues/220)) ([0ecd331](https://github.com/cloudinary-community/cloudinary-util/commit/0ecd331e1bfe9244bedc82fc8d61e228bdc00d4c)), closes [#142](https://github.com/cloudinary-community/cloudinary-util/issues/142) +- Add enum for format parameter ([#220](https://github.com/cloudinary-community/cloudinary-util/issues/220)) ([0ecd331](https://github.com/cloudinary-community/cloudinary-util/commit/0ecd331e1bfe9244bedc82fc8d61e228bdc00d4c)), closes [#142](https://github.com/cloudinary-community/cloudinary-util/issues/142) # [@cloudinary-util/url-loader-v6.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.5...@cloudinary-util/url-loader-v6.0.0-beta.1) (2024-10-18) ### Features -* migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481)) +- migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481)) # [@cloudinary-util/url-loader-v5.10.6](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.5...@cloudinary-util/url-loader-v5.10.6) (2024-10-22) ### Bug Fixes -* Add enum for format parameter ([#220](https://github.com/cloudinary-community/cloudinary-util/issues/220)) ([0ecd331](https://github.com/cloudinary-community/cloudinary-util/commit/0ecd331e1bfe9244bedc82fc8d61e228bdc00d4c)), closes [#142](https://github.com/cloudinary-community/cloudinary-util/issues/142) +- Add enum for format parameter ([#220](https://github.com/cloudinary-community/cloudinary-util/issues/220)) ([0ecd331](https://github.com/cloudinary-community/cloudinary-util/commit/0ecd331e1bfe9244bedc82fc8d61e228bdc00d4c)), closes [#142](https://github.com/cloudinary-community/cloudinary-util/issues/142) # [@cloudinary-util/url-loader-v5.10.5](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v5.10.4...@cloudinary-util/url-loader-v5.10.5) (2024-10-07) diff --git a/packages/url-loader/src/lib/cloudinary.ts b/packages/url-loader/src/lib/cloudinary.ts index 5e91f5b9..a0be824f 100644 --- a/packages/url-loader/src/lib/cloudinary.ts +++ b/packages/url-loader/src/lib/cloudinary.ts @@ -40,7 +40,7 @@ import type { PluginOptions, PluginResults } from "../types/plugins.js"; import type { VideoOptions } from "../types/video.js"; import type { CloudinaryKey, - OptionsFor, + CtxParam, TransformationPlugin, } from "./plugin.js"; import { entriesOf, throwError } from "./utils.js"; @@ -135,7 +135,7 @@ export interface ConstructUrlProps< */ config?: ConfigOptions; // prioritize inferring assetType so available options can be derived from it - options: { assetType?: assetType } & OptionsFor; + options: { assetType?: assetType } & CtxParam; } export type CldAsset = CloudinaryImage | CloudinaryVideo; @@ -214,12 +214,10 @@ export function constructCloudinaryUrl< const pluginEffects: PluginOptions = {}; transformationPlugins.forEach( - ({ name, apply, strict, applyWhen, supports }: TransformationPlugin) => { - const shouldApply = - applyWhen === undefined || - (typeof applyWhen === "string" - ? options[applyWhen as never] !== undefined - : applyWhen(options)); + ({ name, apply, strict, supports, props }: TransformationPlugin) => { + const shouldApply = Object.keys(props).some( + (key) => options[key as never] !== undefined + ); if (!shouldApply) return; @@ -235,6 +233,9 @@ export function constructCloudinaryUrl< return; } + // we're actually passing options for both opts and ctx, but + // the second param is typed to only include the options + // declared by the plugin's `inferOwnOptions` const results: PluginResults = apply(cldAsset, options); const pluginOptions = results?.options ?? {}; diff --git a/packages/url-loader/src/lib/plugin.ts b/packages/url-loader/src/lib/plugin.ts index 4b3ddfc0..e38f4439 100644 --- a/packages/url-loader/src/lib/plugin.ts +++ b/packages/url-loader/src/lib/plugin.ts @@ -18,59 +18,89 @@ export type AlwaysApply = () => true; export interface PluginDefinition< assetType extends SupportedAssetType, - when extends ApplyWhen, name extends string, options extends object, + alwaysApply extends boolean, > { name: name; supports: assetType; - apply: PluginApplication; + apply: PluginApplicationDefinition; inferOwnOptions: options; props: Record; - applyWhen?: when | undefined; + alwaysApply?: alwaysApply; strict?: boolean; } export interface TransformationPlugin< assetType extends SupportedAssetType = SupportedAssetType, - when extends ApplyWhen = ApplyWhen, name extends string = string, - options extends object = object, + opts extends object = object, + alwaysApply extends boolean = boolean, > { name: name; supports: assetType; - apply: PluginApplication; - inferOwnOptions: options; - props: Record; - applyWhen?: when | undefined; + apply: PluginApplication; + inferOwnOptions: opts; + props: Record; + alwaysApply: alwaysApply; strict?: boolean; } -export type OptionsFor< - assetType extends SupportedAssetTypeInput, - when extends ApplyWhen = AlwaysApply, - options = assetType extends "all" +export type OwnOptionsParam< + opts extends object, + alwaysApply extends boolean, +> = opts & + // if there's only one owned key, we know it must be present if + // apply is being invoked, so require it so we don't have to recheck + // in the implementation unless alwaysApply is true + ([alwaysApply] extends [true] + ? {} + : { [k in singleKeyOf]: Exclude }); + +export type CtxParam = + assetType extends "all" ? AllOptions : assetType extends "video" | "videos" ? VideoOptions - : ImageOptions, -> = [when] extends [keyof options] - ? // if the plugin applies based on a single key being defined, we know it will be - // present in the options passed to apply - options & { [k in when]: {} } - : options; + : ImageOptions; + +// extract the key if there is exactly one, otherwise never +type singleKeyOf = { + [k in keyof opts]: keyof opts extends k ? k : never; +}[keyof opts]; + +export type PluginApplicationDefinition< + assetType extends SupportedAssetType, + opts extends object, + alwaysApply extends boolean, +> = ( + cldAsset: CldAsset, + /** Options owned by this plugin */ + opts: OwnOptionsParam, + ctx: CtxParam, +) => PluginResults; export type PluginApplication< assetType extends SupportedAssetType, - when extends ApplyWhen = AlwaysApply, -> = (cldAsset: CldAsset, options: OptionsFor) => PluginResults; + opts extends object, + alwaysApply extends boolean, +> = ( + cldAsset: CldAsset, + // externally, we want the wider assetType options as well + opts: OwnOptionsParam & CtxParam, +) => PluginResults; export const plugin = < asset extends SupportedAssetType, - when extends ApplyWhen, name extends string, - options extends object, + opts extends object, + alwaysApply extends boolean, >( - def: PluginDefinition -): TransformationPlugin => - ({ strict: false, ...def }) as never; + def: PluginDefinition, +): TransformationPlugin => + ({ + strict: false, + alwaysApply: false, + ...def, + apply: (cldAsset, ctx) => def.apply(cldAsset, ctx as never, ctx as never), + }) satisfies TransformationPlugin as never; diff --git a/packages/url-loader/src/lib/upload.ts b/packages/url-loader/src/lib/upload.ts index 7c05fc8c..7e22db4b 100644 --- a/packages/url-loader/src/lib/upload.ts +++ b/packages/url-loader/src/lib/upload.ts @@ -14,11 +14,11 @@ export function generateSignatureCallback({ }: GenerateSignatureCallback) { return function generateSignature( callback: (signature: string | null, error?: unknown) => void, - paramsToSign: object + paramsToSign: object, ) { if (typeof signatureEndpoint === "undefined") { throw Error( - "Failed to generate signature: signatureEndpoint property undefined." + "Failed to generate signature: signatureEndpoint property undefined.", ); } diff --git a/packages/url-loader/src/lib/utils.ts b/packages/url-loader/src/lib/utils.ts index 106f75ca..df102233 100644 --- a/packages/url-loader/src/lib/utils.ts +++ b/packages/url-loader/src/lib/utils.ts @@ -33,7 +33,7 @@ export const entriesOf: (o: o) => entryOf[] = */ export const throwError: ( message: string, - ctor?: new (message: string) => Error + ctor?: new (message: string) => Error, ) => never = (message, ctor = Error) => { throw new ctor(message); }; diff --git a/packages/url-loader/src/lib/video-player.ts b/packages/url-loader/src/lib/video-player.ts index a95c8d30..bcea13ef 100644 --- a/packages/url-loader/src/lib/video-player.ts +++ b/packages/url-loader/src/lib/video-player.ts @@ -38,7 +38,7 @@ export interface GetVideoPlayerOptionsLogo { export function getVideoPlayerOptions( options: GetVideoPlayerOptions, - config: CloudinaryAssetConfiguration + config: CloudinaryAssetConfiguration, ) { const { autoplay, @@ -63,7 +63,7 @@ export function getVideoPlayerOptions( if (!cloudName) { throw new Error( - "A Cloudinary Cloud name is required, please make sure your environment variable is set and configured in your environment." + "A Cloudinary Cloud name is required, please make sure your environment variable is set and configured in your environment.", ); } @@ -85,7 +85,7 @@ export function getVideoPlayerOptions( if (!publicId) { throw new Error( - "Video Player requires a src, please make sure to configure your src as a public ID or Cloudinary URL." + "Video Player requires a src, please make sure to configure your src as a public ID or Cloudinary URL.", ); } diff --git a/packages/url-loader/src/plugins/abr.ts b/packages/url-loader/src/plugins/abr.ts index eb1d903f..edf12992 100644 --- a/packages/url-loader/src/plugins/abr.ts +++ b/packages/url-loader/src/plugins/abr.ts @@ -14,14 +14,13 @@ export const AbrPlugin = plugin({ name: "Abr", supports: "video", inferOwnOptions: {} as AbrPlugin.Options, - applyWhen: 'streamingProfile', props: { streamingProfile: true, }, apply: (asset, opts) => { - if (typeof opts.streamingProfile === "string") { - asset.addTransformation(`sp_${opts.streamingProfile}`); - } + if (typeof opts.streamingProfile !== "string") return {}; + + asset.addTransformation(`sp_${opts.streamingProfile}`); return {}; }, diff --git a/packages/url-loader/src/plugins/cropping.ts b/packages/url-loader/src/plugins/cropping.ts index d9d92bf9..ec971843 100644 --- a/packages/url-loader/src/plugins/cropping.ts +++ b/packages/url-loader/src/plugins/cropping.ts @@ -25,6 +25,14 @@ export declare namespace CroppingPlugin { crop?: CropMode | NestedOptions | ReadonlyArray; gravity?: Gravity; zoom?: Zoom; + /** + * @description Height of the given asset. + */ + height?: string | number; + /** + * @description Width of the given asset. + */ + width?: string | number; } export interface NestedOptions { @@ -49,6 +57,8 @@ export const CroppingPlugin = plugin({ crop: true, gravity: true, zoom: true, + height: true, + width: true, }, // crop is applied even if the crop key is undefined apply: (asset, opts) => { diff --git a/packages/url-loader/src/plugins/default-image.ts b/packages/url-loader/src/plugins/default-image.ts index 76070c6d..3b4a4e5c 100644 --- a/packages/url-loader/src/plugins/default-image.ts +++ b/packages/url-loader/src/plugins/default-image.ts @@ -19,15 +19,15 @@ export const DefaultImagePlugin = plugin({ apply: (asset, opts) => { const { defaultImage } = opts; - if (typeof defaultImage === "string") { - if (!getFormat(defaultImage)) { - console.warn( - `The defaultImage prop may be missing a format and must include it along with the public ID. (Ex: myimage.jpg)` - ); - } - const defaultImageId = defaultImage.replace(/\//g, ":"); - asset.addTransformation(`d_${defaultImageId}`); + if (typeof defaultImage !== "string") return {}; + + if (!getFormat(defaultImage)) { + console.warn( + `The defaultImage prop may be missing a format and must include it along with the public ID. (Ex: myimage.jpg)` + ); } + const defaultImageId = defaultImage.replace(/\//g, ":"); + asset.addTransformation(`d_${defaultImageId}`); return {}; }, diff --git a/packages/url-loader/src/plugins/effects.ts b/packages/url-loader/src/plugins/effects.ts index d01cc938..5826dce8 100644 --- a/packages/url-loader/src/plugins/effects.ts +++ b/packages/url-loader/src/plugins/effects.ts @@ -76,12 +76,12 @@ export const EffectsPlugin = plugin({ vignette: true, effects: true, }, - apply: (cldAsset, options) => { + apply: (cldAsset, opts) => { // Handle any top-level effect props const transformationStrings = constructTransformationString({ effects: qualifiersEffects, - options, + options: opts, }); transformationStrings.forEach((transformation) => { @@ -93,8 +93,8 @@ export const EffectsPlugin = plugin({ // If we're passing in an effects prop explicitly, treat it as an array of // effects that we need to process - if (isArray(options?.effects)) { - options?.effects.forEach((effectsSet) => { + if (isArray(opts?.effects)) { + opts?.effects.forEach((effectsSet) => { const transformationString = constructTransformationString({ effects: qualifiersEffects, options: effectsSet, @@ -123,7 +123,7 @@ export const EffectsPlugin = plugin({ value: options?.[key], converters, }); - } + }, ); } diff --git a/packages/url-loader/src/plugins/enhance.ts b/packages/url-loader/src/plugins/enhance.ts index 0347a130..ca17c85a 100644 --- a/packages/url-loader/src/plugins/enhance.ts +++ b/packages/url-loader/src/plugins/enhance.ts @@ -17,8 +17,8 @@ export const EnhancePlugin = plugin({ props: { enhance: true, }, - apply: (cldAsset, options) => { - if (options.enhance) { + apply: (cldAsset, opts) => { + if (opts.enhance) { cldAsset.addTransformation("e_enhance"); } diff --git a/packages/url-loader/src/plugins/extract.ts b/packages/url-loader/src/plugins/extract.ts index 53a66ec2..8408204f 100644 --- a/packages/url-loader/src/plugins/extract.ts +++ b/packages/url-loader/src/plugins/extract.ts @@ -26,7 +26,6 @@ export declare namespace ExtractPlugin { export const ExtractPlugin = plugin({ name: "Extract", supports: "image", - applyWhen: "extract", inferOwnOptions: {} as ExtractPlugin.Options, props: { extract: true, diff --git a/packages/url-loader/src/plugins/fill-background.ts b/packages/url-loader/src/plugins/fill-background.ts index 610863b5..74df677c 100644 --- a/packages/url-loader/src/plugins/fill-background.ts +++ b/packages/url-loader/src/plugins/fill-background.ts @@ -31,16 +31,16 @@ export const FillBackgroundPlugin = plugin({ props: { fillBackground: true, }, - apply: (cldAsset, options) => { - const { fillBackground } = options; + apply: (cldAsset, opts, ctx) => { + const { fillBackground } = opts; if (typeof fillBackground === "undefined") return {}; - const width = normalizeNumberParameter(options.width); - const height = normalizeNumberParameter(options.height); + const width = normalizeNumberParameter(ctx.width); + const height = normalizeNumberParameter(ctx.height); const hasDefinedDimensions = typeof height === "number" && typeof width === "number"; - let aspectRatio = options.aspectRatio; + let aspectRatio = ctx.aspectRatio; if (!aspectRatio && hasDefinedDimensions) { aspectRatio = `${width}:${height}`; diff --git a/packages/url-loader/src/plugins/flags.ts b/packages/url-loader/src/plugins/flags.ts index d2c09a9a..79120195 100644 --- a/packages/url-loader/src/plugins/flags.ts +++ b/packages/url-loader/src/plugins/flags.ts @@ -11,7 +11,6 @@ export declare namespace FlagsPlugin { export const FlagsPlugin = plugin({ name: "Flags", supports: "all", - applyWhen: "flags", inferOwnOptions: {} as FlagsPlugin.Options, props: { flags: true, diff --git a/packages/url-loader/src/plugins/named-transformations.ts b/packages/url-loader/src/plugins/named-transformations.ts index 924628e3..5a0f5294 100644 --- a/packages/url-loader/src/plugins/named-transformations.ts +++ b/packages/url-loader/src/plugins/named-transformations.ts @@ -26,12 +26,12 @@ export const NamedTransformationsPlugin = plugin({ namedTransformations: true, transformations: true, }, - apply: (cldAsset, options) => { - const { transformations, namedTransformations } = options; + apply: (cldAsset, opts) => { + const { transformations, namedTransformations } = opts; if (transformations && process.env.NODE_ENVIRONMENT === "development") { console.warn( - "The transformations prop is deprecated. Please use namedTransformations instead." + "The transformations prop is deprecated. Please use namedTransformations instead.", ); } diff --git a/packages/url-loader/src/plugins/overlays.ts b/packages/url-loader/src/plugins/overlays.ts index 9d1ebde3..76d403e8 100644 --- a/packages/url-loader/src/plugins/overlays.ts +++ b/packages/url-loader/src/plugins/overlays.ts @@ -77,8 +77,8 @@ export const OverlaysPlugin = plugin({ overlays: true, text: true, }, - apply: (cldAsset, options) => { - const { text, overlays = [] } = options; + apply: (cldAsset, opts) => { + const { text, overlays = [] } = opts; const type = "overlay"; const typeQualifier = "l"; @@ -130,7 +130,7 @@ export const OverlaysPlugin = plugin({ } else if (hasPublicId) { layerTransformation = `${typeQualifier}_${publicId.replace( /\//g, - ":" + ":", )}`; } else if (hasUrl) { layerTransformation = `${typeQualifier}_fetch:${encodeBase64(url)}`; @@ -271,7 +271,7 @@ export const OverlaysPlugin = plugin({ value, order: qualifiersText[key].order || 99, }; - } + }, ); const sortedTextOptions = sortByKey(textOptions, "order"); @@ -314,13 +314,13 @@ export const OverlaysPlugin = plugin({ )?.forEach((character: string) => { layerText = layerText?.replace( character, - specialCharacters[character] + specialCharacters[character], ); }); } layerTransformation = `${layerTransformation}:${textTransformations.join( - "_" + "_", )}:${layerText}`; } diff --git a/packages/url-loader/src/plugins/preserve-transformations.ts b/packages/url-loader/src/plugins/preserve-transformations.ts index 19c8995c..6bfd0f8e 100644 --- a/packages/url-loader/src/plugins/preserve-transformations.ts +++ b/packages/url-loader/src/plugins/preserve-transformations.ts @@ -17,8 +17,8 @@ export const PreserveTransformationsPlugin = plugin({ props: { preserveTransformations: true, }, - apply: (cldAsset, options) => { - const { preserveTransformations = false } = options; + apply: (cldAsset, opts, ctx) => { + const { preserveTransformations = false } = opts; // Try to preserve the original transformations from the Cloudinary URL passed in // to the function. This only works if the URL has a version number on it and otherwise @@ -26,18 +26,18 @@ export const PreserveTransformationsPlugin = plugin({ if (preserveTransformations) { try { - if (options.src === undefined) { + if (ctx.src === undefined) { throw new Error("options.src was undefined"); } - const transformations = getTransformations(options.src).map((t) => - t.join(",") + const transformations = getTransformations(ctx.src).map((t) => + t.join(","), ); transformations.flat().forEach((transformation) => { cldAsset.addTransformation(transformation); }); } catch (e) { console.warn( - `Failed to preserve transformations: ${(e as Error).message}` + `Failed to preserve transformations: ${(e as Error).message}`, ); } } diff --git a/packages/url-loader/src/plugins/raw-transformations.ts b/packages/url-loader/src/plugins/raw-transformations.ts index 6ca1ab2c..4f08a277 100644 --- a/packages/url-loader/src/plugins/raw-transformations.ts +++ b/packages/url-loader/src/plugins/raw-transformations.ts @@ -18,8 +18,8 @@ export const RawTransformationsPlugin = plugin({ props: { rawTransformations: true, }, - apply: (cldAsset, options) => { - let { rawTransformations = [] } = options; + apply: (cldAsset, opts) => { + let { rawTransformations = [] } = opts; if (!isArray(rawTransformations)) { rawTransformations = [rawTransformations]; diff --git a/packages/url-loader/src/plugins/recolor.ts b/packages/url-loader/src/plugins/recolor.ts index da394613..890e5c0f 100644 --- a/packages/url-loader/src/plugins/recolor.ts +++ b/packages/url-loader/src/plugins/recolor.ts @@ -30,8 +30,8 @@ export const RecolorPlugin = plugin({ props: { recolor: true, }, - apply: (cldAsset, options) => { - const { recolor } = options; + apply: (cldAsset, opts) => { + const { recolor } = opts; const recolorOptions: Record = { prompt: undefined, diff --git a/packages/url-loader/src/plugins/remove-background.ts b/packages/url-loader/src/plugins/remove-background.ts index 193f3fd0..e2177a95 100644 --- a/packages/url-loader/src/plugins/remove-background.ts +++ b/packages/url-loader/src/plugins/remove-background.ts @@ -17,8 +17,8 @@ export const RemoveBackgroundPlugin = plugin({ props: { removeBackground: true, }, - apply: (cldAsset, options) => { - if (options.removeBackground) { + apply: (cldAsset, opts) => { + if (opts.removeBackground) { cldAsset.addTransformation("e_background_removal"); } return {}; diff --git a/packages/url-loader/src/plugins/remove.ts b/packages/url-loader/src/plugins/remove.ts index ab48e95d..e611f124 100644 --- a/packages/url-loader/src/plugins/remove.ts +++ b/packages/url-loader/src/plugins/remove.ts @@ -27,8 +27,8 @@ export const RemovePlugin = plugin({ props: { remove: true, }, - apply: (cldAsset, options) => { - const { remove } = options; + apply: (cldAsset, opts) => { + const { remove } = opts; const removeOptions: Record = { prompt: undefined, @@ -48,7 +48,7 @@ export const RemovePlugin = plugin({ if (hasPrompt && hasRegion) { throw new Error( - "Invalid remove options: you can not have both a prompt and a region. More info: https://cloudinary.com/documentation/transformation_reference#e_gen_remove" + "Invalid remove options: you can not have both a prompt and a region. More info: https://cloudinary.com/documentation/transformation_reference#e_gen_remove", ); } @@ -93,7 +93,7 @@ export const RemovePlugin = plugin({ */ function regionArrayToString( - regionArray: Array> + regionArray: Array>, ): string { const indexes: Record = { 0: "x", diff --git a/packages/url-loader/src/plugins/replace-background.ts b/packages/url-loader/src/plugins/replace-background.ts index 6a42e8ef..b69945f8 100644 --- a/packages/url-loader/src/plugins/replace-background.ts +++ b/packages/url-loader/src/plugins/replace-background.ts @@ -6,7 +6,7 @@ export declare namespace ReplaceBackgroundPlugin { * @description Replaces the background of an image with an AI-generated background. * @url https://cloudinary.com/documentation/transformation_reference#e_gen_background_replace */ - replaceBackground?: NestedOptions | string | number; + replaceBackground?: NestedOptions | string | boolean; } export interface NestedOptions { @@ -22,11 +22,10 @@ export const ReplaceBackgroundPlugin = plugin({ props: { replaceBackground: true, }, - apply: (cldAsset, options) => { - const { replaceBackground } = options; + apply: (cldAsset, opts) => { + const { replaceBackground } = opts; - if (!replaceBackground || typeof replaceBackground === "undefined") - return {}; + if (!replaceBackground) return {}; const properties = []; diff --git a/packages/url-loader/src/plugins/replace.ts b/packages/url-loader/src/plugins/replace.ts index 3463473d..e2e880ff 100644 --- a/packages/url-loader/src/plugins/replace.ts +++ b/packages/url-loader/src/plugins/replace.ts @@ -24,34 +24,34 @@ export const ReplacePlugin = plugin({ props: { replace: true, }, - apply: (cldAsset, options) => { - const { replace = null } = options; - - if (replace) { - let from: string, - to: string, - preserveGeometry: boolean = false; - - if (isArray(replace)) { - from = replace[0] as string; - to = replace[1] as string; - preserveGeometry = (replace[2] as boolean) || false; - } else { - from = replace.from; - to = replace.to; - preserveGeometry = replace.preserveGeometry || false; - } - - const properties = [`e_gen_replace:from_${from}`, `to_${to}`]; - - // This property defaults to false, so we only need to pass it if it's true - if (preserveGeometry) { - properties.push(`preserve-geometry_${preserveGeometry}`); - } - - cldAsset.addTransformation(properties.join(";")); + apply: (cldAsset, opts) => { + const { replace } = opts; + + if (!replace) return {}; + + let from: string, + to: string, + preserveGeometry: boolean = false; + + if (isArray(replace)) { + from = replace[0] as string; + to = replace[1] as string; + preserveGeometry = (replace[2] as boolean) || false; + } else { + from = replace.from; + to = replace.to; + preserveGeometry = replace.preserveGeometry || false; } + const properties = [`e_gen_replace:from_${from}`, `to_${to}`]; + + // This property defaults to false, so we only need to pass it if it's true + if (preserveGeometry) { + properties.push(`preserve-geometry_${preserveGeometry}`); + } + + cldAsset.addTransformation(properties.join(";")); + return {}; }, }); diff --git a/packages/url-loader/src/plugins/restore.ts b/packages/url-loader/src/plugins/restore.ts index 21966b91..4ed987a6 100644 --- a/packages/url-loader/src/plugins/restore.ts +++ b/packages/url-loader/src/plugins/restore.ts @@ -17,8 +17,8 @@ export const RestorePlugin = plugin({ props: { restore: true, }, - apply: (cldAsset, options) => { - const { restore = false } = options; + apply: (cldAsset, opts) => { + const { restore } = opts; if (restore) { cldAsset.addTransformation("e_gen_restore"); diff --git a/packages/url-loader/src/plugins/sanitize.ts b/packages/url-loader/src/plugins/sanitize.ts index 3c24c39c..3c5836c8 100644 --- a/packages/url-loader/src/plugins/sanitize.ts +++ b/packages/url-loader/src/plugins/sanitize.ts @@ -17,12 +17,13 @@ export const SanitizePlugin = plugin({ props: { sanitize: true, }, - apply: (cldAsset, options) => { - const { sanitize = true } = options; + alwaysApply: true, + apply: (cldAsset, opts, ctx) => { + const { sanitize = true } = opts; const shouldApplySanitizer: boolean = sanitize && - (options.format === "svg" || + (ctx.format === "svg" || (cldAsset as {} as { publicID: string }).publicID.endsWith(".svg")); if (shouldApplySanitizer) { diff --git a/packages/url-loader/src/plugins/seo.ts b/packages/url-loader/src/plugins/seo.ts index 42c7292d..8df5c59b 100644 --- a/packages/url-loader/src/plugins/seo.ts +++ b/packages/url-loader/src/plugins/seo.ts @@ -17,17 +17,15 @@ export const SeoPlugin = plugin({ props: { seoSuffix: true, }, - apply: (cldAsset, options) => { - const { seoSuffix } = options; + apply: (cldAsset, opts, ctx) => { + const { seoSuffix } = opts; - if (typeof seoSuffix === "string") { - if (options.deliveryType === "fetch") { - console.warn( - "SEO suffix is not supported with a delivery type of fetch" - ); - } else { - cldAsset.setSuffix(seoSuffix); - } + if (typeof seoSuffix !== "string") return {}; + + if (ctx.deliveryType === "fetch") { + console.warn("SEO suffix is not supported with a delivery type of fetch"); + } else { + cldAsset.setSuffix(seoSuffix); } return {}; diff --git a/packages/url-loader/src/plugins/underlays.ts b/packages/url-loader/src/plugins/underlays.ts index 9378e456..3a172bef 100644 --- a/packages/url-loader/src/plugins/underlays.ts +++ b/packages/url-loader/src/plugins/underlays.ts @@ -50,8 +50,8 @@ export const UnderlaysPlugin = plugin({ underlay: true, underlays: true, }, - apply: (cldAsset, options) => { - const { underlay, underlays = [] } = options; + apply: (cldAsset, opts) => { + const { underlay, underlays = [] } = opts; const typeQualifier = "u"; @@ -96,7 +96,7 @@ export const UnderlaysPlugin = plugin({ let layerTransformation = `${typeQualifier}_${publicId.replace( /\//g, - ":" + ":", )}`; // Begin organizing transformations based on what it is and the location diff --git a/packages/url-loader/src/plugins/version.ts b/packages/url-loader/src/plugins/version.ts index f762b76d..5c9ac871 100644 --- a/packages/url-loader/src/plugins/version.ts +++ b/packages/url-loader/src/plugins/version.ts @@ -17,14 +17,14 @@ export const VersionPlugin = plugin({ props: { version: true, }, - apply: (cldAsset, options) => { - const { version } = options; + apply: (cldAsset, opts) => { + const { version } = opts; - if (typeof version === "string" || typeof version === "number") { - // Replace a `v` in the string just in case the caller - // passes it in - cldAsset.setVersion(`${version}`.replace("v", "")); - } + if (typeof version !== "string" && typeof version !== "number") return {}; + + // Replace a `v` in the string just in case the caller + // passes it in + cldAsset.setVersion(`${version}`.replace("v", "")); return {}; }, diff --git a/packages/url-loader/src/plugins/zoompan.ts b/packages/url-loader/src/plugins/zoompan.ts index 5866df06..a3e75d73 100644 --- a/packages/url-loader/src/plugins/zoompan.ts +++ b/packages/url-loader/src/plugins/zoompan.ts @@ -24,8 +24,8 @@ export const ZoompanPlugin = plugin({ props: { zoompan: true, }, - apply: (cldAsset, options) => { - const { zoompan = false } = options; + apply: (cldAsset, opts) => { + const { zoompan = false } = opts; const overrides: PluginOptions = { format: undefined, diff --git a/packages/url-loader/src/types/asset.ts b/packages/url-loader/src/types/asset.ts index ae93cecc..443ee9cc 100644 --- a/packages/url-loader/src/types/asset.ts +++ b/packages/url-loader/src/types/asset.ts @@ -13,7 +13,7 @@ import type { UnderlaysPlugin } from "../plugins/underlays.js"; import type { VersionPlugin } from "../plugins/version.js"; import type { ZoompanPlugin } from "../plugins/zoompan.js"; -import type { Format } from '../constants/parameters.js'; +import type { Format } from "../constants/parameters.js"; export type SupportedAssetTypeInput = SupportedAssetType | "videos" | "images"; @@ -44,10 +44,6 @@ export interface BaseAssetOptions< * @url https://cloudinary.com/documentation/transformation_reference#f_format */ format?: Format; - /** - * @description Height of the given asset. - */ - height?: string | number; /** * @description Quality of the delivered asset * @url https://cloudinary.com/documentation/transformation_reference#q_quality @@ -58,10 +54,6 @@ export interface BaseAssetOptions< * @url https://cloudinary.com/documentation/control_access_to_media#strict_transformations */ strictTransformations?: boolean; - /** - * @description Width of the given asset. - */ - width?: string | number; } export interface AssetOptions< diff --git a/packages/url-loader/tests/plugins/default.spec.ts b/packages/url-loader/tests/plugins/default.spec.ts index ceee5ebe..ef01c82b 100644 --- a/packages/url-loader/tests/plugins/default.spec.ts +++ b/packages/url-loader/tests/plugins/default.spec.ts @@ -32,7 +32,7 @@ describe("Default Image plugin", () => { }; DefaultImagePlugin.apply(cldImage, options); expect(cldImage.toURL()).toContain( - `d_${options.defaultImage}/${TEST_PUBLIC_ID}` + `d_${options.defaultImage}/${TEST_PUBLIC_ID}`, ); }); it("should warn if no format", () => { @@ -45,10 +45,10 @@ describe("Default Image plugin", () => { }; DefaultImagePlugin.apply(cldImage, options); expect((console.warn as any).mock.calls[0][0]).toContain( - "The defaultImage prop may be missing" + "The defaultImage prop may be missing", ); expect(cldImage.toURL()).toContain( - `d_${options.defaultImage}/${TEST_PUBLIC_ID}` + `d_${options.defaultImage}/${TEST_PUBLIC_ID}`, ); }); }); diff --git a/packages/url-loader/tests/plugins/remove-background.spec.ts b/packages/url-loader/tests/plugins/remove-background.spec.ts index d5ccf7ad..701b3d5f 100644 --- a/packages/url-loader/tests/plugins/remove-background.spec.ts +++ b/packages/url-loader/tests/plugins/remove-background.spec.ts @@ -25,17 +25,5 @@ describe("Plugins", () => { expect(cldImage.toURL()).toContain(`e_background_removal`); }); - - it("should not remove the background", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - src: TEST_PUBLIC_ID, - }; - - RemoveBackgroundPlugin.apply(cldImage, options); - - expect(cldImage.toURL()).not.toContain(`e_background_removal`); - }); }); }); diff --git a/packages/url-loader/tests/plugins/replace.spec.ts b/packages/url-loader/tests/plugins/replace.spec.ts index 6ee0b3f2..e31a9beb 100644 --- a/packages/url-loader/tests/plugins/replace.spec.ts +++ b/packages/url-loader/tests/plugins/replace.spec.ts @@ -75,17 +75,5 @@ describe("Plugins", () => { `e_gen_replace:from_apple;to_candy%20bar;preserve-geometry_true`, ); }); - - it("should not attempt generative replace", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - src: TEST_PUBLIC_ID, - }; - - ReplacePlugin.apply(cldImage, options); - - expect(cldImage.toURL()).not.toContain(`e_gen_replace`); - }); }); }); diff --git a/packages/url-loader/tests/plugins/restore.spec.ts b/packages/url-loader/tests/plugins/restore.spec.ts index a70a4a74..f98f752e 100644 --- a/packages/url-loader/tests/plugins/restore.spec.ts +++ b/packages/url-loader/tests/plugins/restore.spec.ts @@ -25,17 +25,5 @@ describe("Plugins", () => { expect(cldImage.toURL()).toContain(`e_gen_restore`); }); - - it("should not restore", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - src: TEST_PUBLIC_ID, - }; - - RestorePlugin.apply(cldImage, options); - - expect(cldImage.toURL()).not.toContain(`e_gen_restore`); - }); }); }); diff --git a/packages/url-loader/tests/plugins/zoompan.spec.ts b/packages/url-loader/tests/plugins/zoompan.spec.ts index 5cfbd914..795dd2f7 100644 --- a/packages/url-loader/tests/plugins/zoompan.spec.ts +++ b/packages/url-loader/tests/plugins/zoompan.spec.ts @@ -26,18 +26,6 @@ describe("Plugins", () => { expect(cldImage.toURL()).toContain(`e_zoompan`); }); - it("should not zoom pan", () => { - const cldImage = cld.image(TEST_PUBLIC_ID); - - const options = { - src: TEST_PUBLIC_ID, - }; - - ZoompanPlugin.apply(cldImage, options); - - expect(cldImage.toURL()).not.toContain(`e_zoompan`); - }); - it("should add loop effect ", () => { const cldImage = cld.image(TEST_PUBLIC_ID); diff --git a/packages/util/CHANGELOG.md b/packages/util/CHANGELOG.md index d0422ae0..ef19c468 100644 --- a/packages/util/CHANGELOG.md +++ b/packages/util/CHANGELOG.md @@ -1,35 +1,30 @@ # [@cloudinary-util/util-v5.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v4.0.0...@cloudinary-util/util-v5.0.0-beta.1) (2024-10-18) - ### Features -* migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481)) +- migrate Zod to pure TS w/ JSDoc, improve type safety and simplify parsing ([#217](https://github.com/cloudinary-community/cloudinary-util/issues/217)) ([f605f26](https://github.com/cloudinary-community/cloudinary-util/commit/f605f26f9de1d111c26d65dd3b8955491b357481)) # [@cloudinary-util/util-v4.0.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.4.0...@cloudinary-util/util-v4.0.0) (2024-10-15) - ### Features -* Change to Force Deploy ([#216](https://github.com/cloudinary-community/cloudinary-util/issues/216)) ([78e44a0](https://github.com/cloudinary-community/cloudinary-util/commit/78e44a043da447394280bdc9065910d0194517b8)) +- Change to Force Deploy ([#216](https://github.com/cloudinary-community/cloudinary-util/issues/216)) ([78e44a0](https://github.com/cloudinary-community/cloudinary-util/commit/78e44a043da447394280bdc9065910d0194517b8)) # [@cloudinary-util/util-v3.4.0](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.3.2...@cloudinary-util/util-v3.4.0) (2024-10-15) - ### Features -* Util v4 ([#213](https://github.com/cloudinary-community/cloudinary-util/issues/213)) ([75fef30](https://github.com/cloudinary-community/cloudinary-util/commit/75fef30393a678f435acf8bbc4814e8da4a0bd40)) +- Util v4 ([#213](https://github.com/cloudinary-community/cloudinary-util/issues/213)) ([75fef30](https://github.com/cloudinary-community/cloudinary-util/commit/75fef30393a678f435acf8bbc4814e8da4a0bd40)) # [@cloudinary-util/util-v4.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.3.2...@cloudinary-util/util-v4.0.0-beta.1) (2024-10-08) - ### Features -* Log X-Cld-Error header in dev mode ([#211](https://github.com/cloudinary-community/cloudinary-util/issues/211)) ([2a5251b](https://github.com/cloudinary-community/cloudinary-util/commit/2a5251b83a44e22d11d4abf9def3bbd975a25f8c)) - +- Log X-Cld-Error header in dev mode ([#211](https://github.com/cloudinary-community/cloudinary-util/issues/211)) ([2a5251b](https://github.com/cloudinary-community/cloudinary-util/commit/2a5251b83a44e22d11d4abf9def3bbd975a25f8c)) ### BREAKING CHANGES -* pollForProcessingImage now returns an object instead of a boolean +- pollForProcessingImage now returns an object instead of a boolean # [@cloudinary-util/util-v3.3.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v3.3.1...@cloudinary-util/util-v3.3.2) (2024-08-28) diff --git a/packages/util/src/lib/cloudinary.ts b/packages/util/src/lib/cloudinary.ts index bfc2e458..de9d05c1 100644 --- a/packages/util/src/lib/cloudinary.ts +++ b/packages/util/src/lib/cloudinary.ts @@ -181,7 +181,7 @@ export async function pollForProcessingImage( return { success: false, status: response.status, - error: response.headers.get('x-cld-error') || 'Unknown error', + error: response.headers.get("x-cld-error") || "Unknown error", }; } @@ -193,7 +193,7 @@ export async function pollForProcessingImage( return { success: false, status: 500, - error: (error as Error).message || 'Network error', + error: (error as Error).message || "Network error", }; } } diff --git a/packages/util/src/lib/util.ts b/packages/util/src/lib/util.ts index 70eaf50d..b783f009 100644 --- a/packages/util/src/lib/util.ts +++ b/packages/util/src/lib/util.ts @@ -32,7 +32,7 @@ export function objectHasKey(obj: T, key: PropertyKey): key is keyof T { export function sortByKey( array: Array = [], key: string, - type: string = "asc" + type: string = "asc", ) { function compare(a: any, b: any) { let keyA = a[key]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e8de1004..54d678cd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,52 +81,6 @@ importers: specifier: ^2.0.5 version: 2.0.5(@types/node@20.10.8)(sass@1.69.7) - docs: - dependencies: - '@cloudinary-util/url-loader': - specifier: workspace:* - version: link:../packages/url-loader - next: - specifier: ^14.0.4 - version: 14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7) - nextra: - specifier: ^2.13.2 - version: 2.13.2(next@14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - nextra-theme-docs: - specifier: ^2.13.2 - version: 2.13.2(next@14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7))(nextra@2.13.2(next@14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react: - specifier: ^18.2.0 - version: 18.2.0 - react-dom: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) - sass: - specifier: ^1.69.7 - version: 1.69.7 - zod: - specifier: ^3.22.4 - version: 3.22.4 - zod-to-json-schema: - specifier: ^3.22.3 - version: 3.22.3(zod@3.22.4) - devDependencies: - '@types/node': - specifier: 20.10.8 - version: 20.10.8 - autoprefixer: - specifier: ^10.4.16 - version: 10.4.16(postcss@8.4.33) - postcss: - specifier: ^8.4.33 - version: 8.4.33 - tailwindcss: - specifier: ^3.4.1 - version: 3.4.1 - typescript: - specifier: ^5.3.3 - version: 5.3.3 - packages/types: {} packages/url-loader: @@ -153,10 +107,6 @@ importers: packages: - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - '@ampproject/remapping@2.2.0': resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} engines: {node: '>=6.0.0'} @@ -729,9 +679,6 @@ packages: resolution: {integrity: sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==} engines: {node: '>=6.9.0'} - '@braintree/sanitize-url@6.0.4': - resolution: {integrity: sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==} - '@cloudinary/transformation-builder-sdk@1.10.1': resolution: {integrity: sha512-UUb1wS/eWCf4YBThGszoBBzH6kP+frdd5JeJkF0/SOwbX3tkcrdzxD+Srn5GXPCqzf6Gw1nrGrv/3U9hiZP55A==} @@ -1036,13 +983,6 @@ packages: resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@headlessui/react@1.7.17': - resolution: {integrity: sha512-4am+tzvkqDSSgiwrsEpGWqgGo9dz8qU5M3znCkC4PgkpY4HcCZzEDEvozltGGGHIKl9jbXbZPSH5TWn4sWJdow==} - engines: {node: '>=10'} - peerDependencies: - react: ^16 || ^17 || ^18 - react-dom: ^16 || ^17 || ^18 - '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -1099,144 +1039,9 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@mdx-js/mdx@2.3.0': - resolution: {integrity: sha512-jLuwRlz8DQfQNiUCJR50Y09CGPq3fLtmtUQfVrj79E0JWu3dvsVcxVIcfhR5h0iXu+/z++zDrYeiJqifRynJkA==} - - '@mdx-js/react@2.3.0': - resolution: {integrity: sha512-zQH//gdOmuu7nt2oJR29vFhDv88oGPmVw6BggmrHeMI+xgEkp1B2dX9/bMBSYtK0dyLX/aOmesKS09g222K1/g==} - peerDependencies: - react: '>=16' - - '@napi-rs/simple-git-android-arm-eabi@0.1.9': - resolution: {integrity: sha512-9D4JnfePMpgL4pg9aMUX7/TIWEUQ+Tgx8n3Pf8TNCMGjUbImJyYsDSLJzbcv9wH7srgn4GRjSizXFJHAPjzEug==} - engines: {node: '>= 10'} - cpu: [arm] - os: [android] - - '@napi-rs/simple-git-android-arm64@0.1.9': - resolution: {integrity: sha512-Krilsw0gPrrASZzudNEl9pdLuNbhoTK0j7pUbfB8FRifpPdFB/zouwuEm0aSnsDXN4ftGrmGG82kuiR/2MeoPg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - - '@napi-rs/simple-git-darwin-arm64@0.1.9': - resolution: {integrity: sha512-H/F09nDgYjv4gcFrZBgdTKkZEepqt0KLYcCJuUADuxkKupmjLdecMhypXLk13AzvLW4UQI7NlLTLDXUFLyr2BA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@napi-rs/simple-git-darwin-x64@0.1.9': - resolution: {integrity: sha512-jBR2xS9nVPqmHv0TWz874W0m/d453MGrMeLjB+boK5IPPLhg3AWIZj0aN9jy2Je1BGVAa0w3INIQJtBBeB6kFA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@napi-rs/simple-git-linux-arm-gnueabihf@0.1.9': - resolution: {integrity: sha512-3n0+VpO4YfZxndZ0sCvsHIvsazd+JmbSjrlTRBCnJeAU1/sfos3skNZtKGZksZhjvd+3o+/GFM8L7Xnv01yggA==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@napi-rs/simple-git-linux-arm64-gnu@0.1.9': - resolution: {integrity: sha512-lIzf0KHU2SKC12vMrWwCtysG2Sdt31VHRPMUiz9lD9t3xwVn8qhFSTn5yDkTeG3rgX6o0p5EKalfQN5BXsJq2w==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@napi-rs/simple-git-linux-arm64-musl@0.1.9': - resolution: {integrity: sha512-KQozUoNXrxrB8k741ncWXSiMbjl1AGBGfZV21PANzUM8wH4Yem2bg3kfglYS/QIx3udspsT35I9abu49n7D1/w==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@napi-rs/simple-git-linux-x64-gnu@0.1.9': - resolution: {integrity: sha512-O/Niui5mnHPcK3iYC3ui8wgERtJWsQ3Y74W/09t0bL/3dgzGMl4oQt0qTj9dWCsnoGsIEYHPzwCBp/2vqYp/pw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@napi-rs/simple-git-linux-x64-musl@0.1.9': - resolution: {integrity: sha512-L9n+e8Wn3hKr3RsIdY8GaB+ry4xZ4BaGwyKExgoB8nDGQuRUY9oP6p0WA4hWfJvJnU1H6hvo36a5UFPReyBO7A==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@napi-rs/simple-git-win32-arm64-msvc@0.1.9': - resolution: {integrity: sha512-Z6Ja/SZK+lMvRWaxj7wjnvSbAsGrH006sqZo8P8nxKUdZfkVvoCaAWr1r0cfkk2Z3aijLLtD+vKeXGlUPH6gGQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@napi-rs/simple-git-win32-x64-msvc@0.1.9': - resolution: {integrity: sha512-VAZj1UvC+R2MjKOD3I/Y7dmQlHWAYy4omhReQJRpbCf+oGCBi9CWiIduGqeYEq723nLIKdxP7XjaO0wl1NnUww==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@napi-rs/simple-git@0.1.9': - resolution: {integrity: sha512-qKzDS0+VjMvVyU28px+C6zlD1HKy83NIdYzfMQWa/g/V1iG/Ic8uwrS2ihHfm7mp7X0PPrmINLiTTi6ieUIKfw==} - engines: {node: '>= 10'} - - '@next/env@14.0.4': - resolution: {integrity: sha512-irQnbMLbUNQpP1wcE5NstJtbuA/69kRfzBrpAD7Gsn8zm/CY6YQYc3HQBz8QPxwISG26tIm5afvvVbu508oBeQ==} - '@next/eslint-plugin-next@14.2.4': resolution: {integrity: sha512-svSFxW9f3xDaZA3idQmlFw7SusOuWTpDTAeBlO3AEPDltrraV+lqs7mAc6A27YdnpQVVIA3sODqUAAHdWhVWsA==} - '@next/swc-darwin-arm64@14.0.4': - resolution: {integrity: sha512-mF05E/5uPthWzyYDyptcwHptucf/jj09i2SXBPwNzbgBNc+XnwzrL0U6BmPjQeOL+FiB+iG1gwBeq7mlDjSRPg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-x64@14.0.4': - resolution: {integrity: sha512-IZQ3C7Bx0k2rYtrZZxKKiusMTM9WWcK5ajyhOZkYYTCc8xytmwSzR1skU7qLgVT/EY9xtXDG0WhY6fyujnI3rw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-linux-arm64-gnu@14.0.4': - resolution: {integrity: sha512-VwwZKrBQo/MGb1VOrxJ6LrKvbpo7UbROuyMRvQKTFKhNaXjUmKTu7wxVkIuCARAfiI8JpaWAnKR+D6tzpCcM4w==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-musl@14.0.4': - resolution: {integrity: sha512-8QftwPEW37XxXoAwsn+nXlodKWHfpMaSvt81W43Wh8dv0gkheD+30ezWMcFGHLI71KiWmHK5PSQbTQGUiidvLQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-x64-gnu@14.0.4': - resolution: {integrity: sha512-/s/Pme3VKfZAfISlYVq2hzFS8AcAIOTnoKupc/j4WlvF6GQ0VouS2Q2KEgPuO1eMBwakWPB1aYFIA4VNVh667A==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-musl@14.0.4': - resolution: {integrity: sha512-m8z/6Fyal4L9Bnlxde5g2Mfa1Z7dasMQyhEhskDATpqr+Y0mjOBZcXQ7G5U+vgL22cI4T7MfvgtrM2jdopqWaw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-win32-arm64-msvc@14.0.4': - resolution: {integrity: sha512-7Wv4PRiWIAWbm5XrGz3D8HUkCVDMMz9igffZG4NB1p4u1KoItwx9qjATHz88kwCEal/HXmbShucaslXCQXUM5w==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-ia32-msvc@14.0.4': - resolution: {integrity: sha512-zLeNEAPULsl0phfGb4kdzF/cAVIfaC7hY+kt0/d+y9mzcZHsMS3hAS829WbJ31DkSlVKQeHEjZHIdhN+Pg7Gyg==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - - '@next/swc-win32-x64-msvc@14.0.4': - resolution: {integrity: sha512-yEh2+R8qDlDCjxVpzOTEpBLQTEFAcP2A8fUFLaWNap9GitYKkKv1//y2S6XY6zsR4rCOPRpU7plYDR+az2n30A==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1312,9 +1117,6 @@ packages: resolution: {integrity: sha512-hD8ml183638O3R6/Txrh0L8VzGOrFXgRtRDG4qQC4tONdZ5Z1M+tlUUDUvrjYdmK6G+JTBTeaCLMna11cXzi8A==} engines: {node: '>=12'} - '@popperjs/core@2.11.8': - resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - '@rollup/rollup-android-arm-eabi@4.9.0': resolution: {integrity: sha512-+1ge/xmaJpm1KVBuIH38Z94zj9fBD+hp+/5WLaHgyY8XLq1ibxk/zj6dTXaqM2cAbYKq8jYlhHd6k05If1W5xA==} cpu: [arm] @@ -1427,72 +1229,19 @@ packages: resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} - '@swc/helpers@0.5.2': - resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} - - '@theguild/remark-mermaid@0.0.5': - resolution: {integrity: sha512-e+ZIyJkEv9jabI4m7q29wZtZv+2iwPGsXJ2d46Zi7e+QcFudiyuqhLhHG/3gX3ZEB+hxTch+fpItyMS8jwbIcw==} - peerDependencies: - react: ^18.2.0 - - '@theguild/remark-npm2yarn@0.2.1': - resolution: {integrity: sha512-jUTFWwDxtLEFtGZh/TW/w30ySaDJ8atKWH8dq2/IiQF61dPrGfETpl0WxD0VdBfuLOeU14/kop466oBSRO/5CA==} - '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} - '@types/acorn@4.0.6': - resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} - - '@types/d3-scale-chromatic@3.0.3': - resolution: {integrity: sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==} - - '@types/d3-scale@4.0.8': - resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==} - - '@types/d3-time@3.0.3': - resolution: {integrity: sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==} - - '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - - '@types/estree-jsx@1.0.3': - resolution: {integrity: sha512-pvQ+TKeRHeiUGRhvYwRrQ/ISnohKkSJR14fT2yqyZ4e9K5vqc7hrtY2Y1Dw0ZwAzQ6DQsxsaCUuSIIi8v0Cq6w==} - '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - '@types/hast@2.3.8': - resolution: {integrity: sha512-aMIqAlFd2wTIDZuvLbhUT+TGvMxrNC8ECUIVtH6xxy0sQLs3iu6NO8Kp/VT5je7i5ufnebXzdV1dNDMnvaH6IQ==} - - '@types/hast@3.0.3': - resolution: {integrity: sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==} - - '@types/js-yaml@4.0.9': - resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} - '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/katex@0.16.7': - resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} - - '@types/mdast@3.0.15': - resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==} - - '@types/mdast@4.0.3': - resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==} - - '@types/mdx@2.0.10': - resolution: {integrity: sha512-Rllzc5KHk0Al5/WANwgSPl1/CwjqCy+AZrGd78zuK+jO9aDM6ffblZ+zIjgPNAaEBmlO0RYDvLNh7wD0zKVgEg==} - '@types/minimist@1.2.2': resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} - '@types/ms@0.7.34': - resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} - '@types/node@17.0.45': resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} @@ -1502,24 +1251,9 @@ packages: '@types/normalize-package-data@2.4.1': resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} - '@types/prop-types@15.7.5': - resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} - - '@types/react@18.0.25': - resolution: {integrity: sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g==} - '@types/retry@0.12.0': resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} - '@types/scheduler@0.16.2': - resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} - - '@types/unist@2.0.10': - resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} - - '@types/unist@3.0.2': - resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} - '@typescript-eslint/eslint-plugin@7.18.0': resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} engines: {node: ^18.18.0 || >=20.0.0} @@ -1675,9 +1409,6 @@ packages: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} - ansi-sequence-parser@1.1.1: - resolution: {integrity: sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==} - ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -1700,18 +1431,6 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - arch@2.2.0: - resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} - - arg@1.0.0: - resolution: {integrity: sha512-Wk7TEzl1KqvTGs/uyhmHO/3XLd3t1UeU4IstvPXVzGPM522cTjqjNZ99esCkcL52sjqjo8e8CTBcWhkxvGzoAw==} - - arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1774,17 +1493,6 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} - astring@1.8.6: - resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} - hasBin: true - - autoprefixer@10.4.16: - resolution: {integrity: sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -1811,9 +1519,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - bail@2.0.2: - resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} - balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1848,10 +1553,6 @@ packages: peerDependencies: esbuild: '>=0.17' - busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} - cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -1864,10 +1565,6 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} - camelcase-keys@6.2.2: resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} engines: {node: '>=8'} @@ -1883,17 +1580,10 @@ packages: resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==} hasBin: true - ccount@2.0.1: - resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - chai@5.1.1: resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==} engines: {node: '>=12'} - chalk@2.3.0: - resolution: {integrity: sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==} - engines: {node: '>=4'} - chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -1914,18 +1604,6 @@ packages: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} - character-entities-html4@2.1.0: - resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} - - character-entities-legacy@3.0.0: - resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} - - character-entities@2.0.2: - resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} - - character-reference-invalid@2.0.1: - resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} - check-error@2.1.1: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} @@ -1946,21 +1624,10 @@ packages: resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} engines: {node: 10.* || >= 12.*} - client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - - clipboardy@1.2.2: - resolution: {integrity: sha512-16KrBOV7bHmHdxcQiCvfUFYVFyEah4FI8vYT1Fr7CGSA4G+xBWMEfUEQJS1hxeHGtI9ju1Bzs9uXSbj5HZKArw==} - engines: {node: '>=4'} - cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} - clsx@2.0.0: - resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} - engines: {node: '>=6'} - color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -1974,9 +1641,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - comma-separated-tokens@2.0.3: - resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} @@ -1985,20 +1649,9 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} - commander@7.2.0: - resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} - engines: {node: '>= 10'} - - commander@8.3.0: - resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} - engines: {node: '>= 12'} - compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} - compute-scroll-into-view@3.1.0: - resolution: {integrity: sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==} - concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -2032,12 +1685,6 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - cose-base@1.0.3: - resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} - - cose-base@2.2.0: - resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} - cosmiconfig@8.0.0: resolution: {integrity: sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==} engines: {node: '>=14'} @@ -2053,170 +1700,6 @@ packages: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - - csstype@3.1.1: - resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} - - cytoscape-cose-bilkent@4.1.0: - resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} - peerDependencies: - cytoscape: ^3.2.0 - - cytoscape-fcose@2.2.0: - resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} - peerDependencies: - cytoscape: ^3.2.0 - - cytoscape@3.28.0: - resolution: {integrity: sha512-x7+BHQXN90Audv5xXvdOECmiKuZdeKeoqOmDuYoht4zDKSdObC0Z9AdJXFkXEQvXU8UndI6WnTz47TRI7duReg==} - engines: {node: '>=0.10'} - - d3-array@2.12.1: - resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} - - d3-array@3.2.4: - resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} - engines: {node: '>=12'} - - d3-axis@3.0.0: - resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} - engines: {node: '>=12'} - - d3-brush@3.0.0: - resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} - engines: {node: '>=12'} - - d3-chord@3.0.1: - resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} - engines: {node: '>=12'} - - d3-color@3.1.0: - resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} - engines: {node: '>=12'} - - d3-contour@4.0.2: - resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} - engines: {node: '>=12'} - - d3-delaunay@6.0.4: - resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} - engines: {node: '>=12'} - - d3-dispatch@3.0.1: - resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} - engines: {node: '>=12'} - - d3-drag@3.0.0: - resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} - engines: {node: '>=12'} - - d3-dsv@3.0.1: - resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} - engines: {node: '>=12'} - hasBin: true - - d3-ease@3.0.1: - resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} - engines: {node: '>=12'} - - d3-fetch@3.0.1: - resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} - engines: {node: '>=12'} - - d3-force@3.0.0: - resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} - engines: {node: '>=12'} - - d3-format@3.1.0: - resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} - engines: {node: '>=12'} - - d3-geo@3.1.0: - resolution: {integrity: sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==} - engines: {node: '>=12'} - - d3-hierarchy@3.1.2: - resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} - engines: {node: '>=12'} - - d3-interpolate@3.0.1: - resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} - engines: {node: '>=12'} - - d3-path@1.0.9: - resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} - - d3-path@3.1.0: - resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} - engines: {node: '>=12'} - - d3-polygon@3.0.1: - resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} - engines: {node: '>=12'} - - d3-quadtree@3.0.1: - resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} - engines: {node: '>=12'} - - d3-random@3.0.1: - resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} - engines: {node: '>=12'} - - d3-sankey@0.12.3: - resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} - - d3-scale-chromatic@3.0.0: - resolution: {integrity: sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==} - engines: {node: '>=12'} - - d3-scale@4.0.2: - resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} - engines: {node: '>=12'} - - d3-selection@3.0.0: - resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} - engines: {node: '>=12'} - - d3-shape@1.3.7: - resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} - - d3-shape@3.2.0: - resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} - engines: {node: '>=12'} - - d3-time-format@4.1.0: - resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} - engines: {node: '>=12'} - - d3-time@3.1.0: - resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} - engines: {node: '>=12'} - - d3-timer@3.0.1: - resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} - engines: {node: '>=12'} - - d3-transition@3.0.1: - resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} - engines: {node: '>=12'} - peerDependencies: - d3-selection: 2 - 3 - - d3-zoom@3.0.0: - resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} - engines: {node: '>=12'} - - d3@7.8.5: - resolution: {integrity: sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==} - engines: {node: '>=12'} - - dagre-d3-es@7.0.10: - resolution: {integrity: sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A==} - damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -2235,9 +1718,6 @@ packages: dateformat@3.0.3: resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} - dayjs@1.11.10: - resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} - debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -2272,9 +1752,6 @@ packages: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} - decode-named-character-reference@1.0.2: - resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} - deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} @@ -2302,33 +1779,13 @@ packages: resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} engines: {node: '>=10'} - delaunator@5.0.0: - resolution: {integrity: sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==} - deprecation@2.3.1: resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - devlop@1.1.0: - resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - - didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - - diff@5.1.0: - resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} - engines: {node: '>=0.3.1'} - dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -2337,9 +1794,6 @@ packages: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} - dompurify@3.0.6: - resolution: {integrity: sha512-ilkD8YEnnGh1zJ240uJsW7AzE+2qpbOUYjacomn3AvJ6J4JhKGSZ2nh4wUIXPZrEPppaCLx5jFe8T89Rk8tQ7w==} - dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} @@ -2353,9 +1807,6 @@ packages: electron-to-chromium@1.4.626: resolution: {integrity: sha512-f7/be56VjRRQk+Ric6PmIrEtPcIqsn3tElyAu9Sh6egha2VLJ82qwkcOdcnT06W+Pb6RUulV1ckzrGbKzVcTHg==} - elkjs@0.8.2: - resolution: {integrity: sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ==} - emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2369,10 +1820,6 @@ packages: resolution: {integrity: sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==} engines: {node: '>=10.13.0'} - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - env-ci@8.0.0: resolution: {integrity: sha512-W+3BqGZozFua9MPeXpmTm5eYEBtGgL76jGu/pwMVp/L8PdECSCEWaIp7d4Mw7kuUrbUldK0oV0bNd6ZZjLiMiA==} engines: {node: ^16.10 || >=18} @@ -2556,25 +2003,6 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} - estree-util-attach-comments@2.1.1: - resolution: {integrity: sha512-+5Ba/xGGS6mnwFbXIuQiDPTbuTxuMCooq3arVv7gPZtYpjp+VXH/NkHAP35OOefPhNG/UGqU3vt/LTABwcHX0w==} - - estree-util-build-jsx@2.2.2: - resolution: {integrity: sha512-m56vOXcOBuaF+Igpb9OPAy7f9w9OIkb5yhjsZuaPm7HoGi4oTOQi0h2+yZ+AtKklYFZ+rPC4n0wYCJCEU1ONqg==} - - estree-util-is-identifier-name@2.1.0: - resolution: {integrity: sha512-bEN9VHRyXAUOjkKVQVvArFym08BTWB0aJPppZZr0UNyAqWsLaVfAqP7hbaTJjzHifmB5ebnR8Wm7r7yGN/HonQ==} - - estree-util-to-js@1.2.0: - resolution: {integrity: sha512-IzU74r1PK5IMMGZXUVZbmiu4A1uhiPgW5hm1GjcOfr4ZzHaMPpLNJjR7HjXiIOzi25nZDrgFTobHTkV5Q6ITjA==} - - estree-util-value-to-estree@1.3.0: - resolution: {integrity: sha512-Y+ughcF9jSUJvncXwqRageavjrNPAI+1M/L3BI3PyLp1nmgYTGUXU6t5z1Y7OWuThoDdhPME07bQU+d5LxdJqw==} - engines: {node: '>=12.0.0'} - - estree-util-visit@1.2.1: - resolution: {integrity: sha512-xbgqcrkIVbIG+lI/gzbvd9SGTJL4zqJKBFttUl5pP27KhAjtMKbX/mQXJ7qgyXpMgVy/zvpm0xoQQaGL8OloOw==} - estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -2598,13 +2026,6 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} - extend-shallow@2.0.1: - resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} - engines: {node: '>=0.10.0'} - - extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -2671,12 +2092,6 @@ packages: flatted@3.2.7: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} - flexsearch@0.7.31: - resolution: {integrity: sha512-XGozTsMPYkm+6b5QL3Z9wQcJjNYxp0CYn3U1gO7dwD6PAqU1SVWZxI9CCg3z+ml3YfqdPnrBehaBrnH2AGKbNA==} - - focus-visible@5.2.0: - resolution: {integrity: sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ==} - for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -2684,9 +2099,6 @@ packages: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} - fraction.js@4.3.7: - resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - from2@2.3.0: resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} @@ -2756,15 +2168,6 @@ packages: git-log-parser@1.2.0: resolution: {integrity: sha512-rnCVNfkTL8tdNryFuaY0fYiBWEBcgF748O6ZI61rslBvr2o7U65c2/6npCRqH40vuAhtgtDiqLTJjBVdrejCzA==} - git-up@7.0.0: - resolution: {integrity: sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==} - - git-url-parse@13.1.1: - resolution: {integrity: sha512-PCFJyeSSdtnbfhSNRw9Wk96dDCNx+sogTe4YNXeXSJxt7xz5hvXekuRn9JX7m+Mf4OscCu8h+mtAl3+h5Fo8lQ==} - - github-slugger@2.0.0: - resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} - glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -2773,9 +2176,6 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.3.10: resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} engines: {node: '>=16 || 14 >=14.17'} @@ -2818,10 +2218,6 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - gray-matter@4.0.3: - resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} - engines: {node: '>=6.0'} - handlebars@4.7.7: resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==} engines: {node: '>=0.4.7'} @@ -2834,10 +2230,6 @@ packages: has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - has-flag@2.0.0: - resolution: {integrity: sha512-P+1n3MnwjR/Epg9BBo1KT8qbye2g2Ou4sFumihwt6I4tsUX7jnLcX4BTOSKg/B1ZrIYMN9FcEnG4x5a7NB8Eng==} - engines: {node: '>=0.10.0'} - has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -2865,10 +2257,6 @@ packages: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} - hash-obj@4.0.0: - resolution: {integrity: sha512-FwO1BUVWkyHasWDW4S8o0ssQXjvyghLV2rfVhnN36b2bbcj45eGiuzdn9XOvOpjV3TKQD7Gm2BWNXdE9V4KKYg==} - engines: {node: '>=12'} - hasown@2.0.0: resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} engines: {node: '>= 0.4'} @@ -2877,45 +2265,6 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hast-util-from-dom@5.0.0: - resolution: {integrity: sha512-d6235voAp/XR3Hh5uy7aGLbM3S4KamdW0WEgOaU1YoewnuYw4HXb5eRtv9g65m/RFGEfUY1Mw4UqCc5Y8L4Stg==} - - hast-util-from-html-isomorphic@2.0.0: - resolution: {integrity: sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==} - - hast-util-from-html@2.0.1: - resolution: {integrity: sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g==} - - hast-util-from-parse5@8.0.1: - resolution: {integrity: sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==} - - hast-util-is-element@3.0.0: - resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} - - hast-util-parse-selector@4.0.0: - resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} - - hast-util-raw@9.0.1: - resolution: {integrity: sha512-5m1gmba658Q+lO5uqL5YNGQWeh1MYWZbZmWrM5lncdcuiXuo5E2HT/CIOp0rLF8ksfSwiCVJ3twlgVRyTGThGA==} - - hast-util-to-estree@2.3.3: - resolution: {integrity: sha512-ihhPIUPxN0v0w6M5+IiAZZrn0LH2uZomeWwhn7uP7avZC6TE7lIiEh2yBMPr5+zi1aUCXq6VoYRgs2Bw9xmycQ==} - - hast-util-to-parse5@8.0.0: - resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==} - - hast-util-to-text@4.0.0: - resolution: {integrity: sha512-EWiE1FSArNBPUo1cKWtzqgnuRQwEeQbQtnFJRYV1hb1BWDgrAlBU0ExptvZMM/KSA82cDpm2sFGf3Dmc5Mza3w==} - - hast-util-whitespace@2.0.1: - resolution: {integrity: sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==} - - hastscript@8.0.0: - resolution: {integrity: sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==} - - heap@0.2.7: - resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} - hook-std@3.0.0: resolution: {integrity: sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2931,9 +2280,6 @@ packages: resolution: {integrity: sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - html-void-elements@3.0.0: - resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} @@ -2954,10 +2300,6 @@ packages: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - ignore-walk@5.0.1: resolution: {integrity: sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -3003,33 +2345,14 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - inline-style-parser@0.1.1: - resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} - internal-slot@1.0.7: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} - internmap@1.0.1: - resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} - - internmap@2.0.3: - resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} - engines: {node: '>=12'} - - intersection-observer@0.12.2: - resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==} - into-stream@6.0.0: resolution: {integrity: sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==} engines: {node: '>=10'} - is-alphabetical@2.0.1: - resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} - - is-alphanumerical@2.0.1: - resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} - is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} @@ -3056,10 +2379,6 @@ packages: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} - is-buffer@2.0.5: - resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} - engines: {node: '>=4'} - is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -3078,13 +2397,6 @@ packages: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} - is-decimal@2.0.1: - resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} - - is-extendable@0.1.1: - resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} - engines: {node: '>=0.10.0'} - is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -3104,9 +2416,6 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-hexadecimal@2.0.1: - resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} - is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -3127,10 +2436,6 @@ packages: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} - is-obj@3.0.0: - resolution: {integrity: sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==} - engines: {node: '>=12'} - is-path-cwd@2.2.0: resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} engines: {node: '>=6'} @@ -3143,21 +2448,10 @@ packages: resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} engines: {node: '>=0.10.0'} - is-plain-obj@3.0.0: - resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==} - engines: {node: '>=10'} - - is-plain-obj@4.1.0: - resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} - engines: {node: '>=12'} - is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} - is-reference@3.0.2: - resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} - is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -3170,9 +2464,6 @@ packages: resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} engines: {node: '>= 0.4'} - is-ssh@1.4.0: - resolution: {integrity: sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==} - is-stream@1.1.0: resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} engines: {node: '>=0.10.0'} @@ -3240,10 +2531,6 @@ packages: resolution: {integrity: sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==} engines: {node: '>= 0.6.0'} - jiti@1.21.0: - resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} - hasBin: true - joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -3251,10 +2538,6 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true @@ -3292,9 +2575,6 @@ packages: engines: {node: '>=6'} hasBin: true - jsonc-parser@3.2.0: - resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} - jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} @@ -3306,21 +2586,10 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} - katex@0.16.9: - resolution: {integrity: sha512-fsSYjWS0EEOwvy81j3vRA8TEAhQhKiqO+FQaKWp0m39qwOzHVBgAUBIXWj1pB+O2W3fIpNa6Y9KSKCVbfPhyAQ==} - hasBin: true - - khroma@2.1.0: - resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} - kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - kleur@4.1.5: - resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} - engines: {node: '>=6'} - language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -3328,20 +2597,10 @@ packages: resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} engines: {node: '>=0.10'} - layout-base@1.0.2: - resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} - - layout-base@2.0.1: - resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} - levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} - lilconfig@3.0.0: resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==} engines: {node: '>=14'} @@ -3385,9 +2644,6 @@ packages: lodash.escaperegexp@4.1.2: resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} - lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - lodash.ismatch@4.4.0: resolution: {integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==} @@ -3409,9 +2665,6 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - longest-streak@3.1.0: - resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -3448,13 +2701,6 @@ packages: resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} engines: {node: '>=8'} - markdown-extensions@1.1.1: - resolution: {integrity: sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q==} - engines: {node: '>=0.10.0'} - - markdown-table@3.0.3: - resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} - marked-terminal@5.1.1: resolution: {integrity: sha512-+cKTOx9P4l7HwINYhzbrBSyzgxO2HaHKGZGuB1orZsMIgXYaJyfidT81VXRdpelW/PcHEWxywscePVgI/oUF6g==} engines: {node: '>=14.13.1 || >=16.0.0'} @@ -3477,66 +2723,6 @@ packages: engines: {node: '>= 16'} hasBin: true - match-sorter@6.3.1: - resolution: {integrity: sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==} - - mdast-util-definitions@5.1.2: - resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==} - - mdast-util-find-and-replace@2.2.2: - resolution: {integrity: sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==} - - mdast-util-from-markdown@1.3.1: - resolution: {integrity: sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==} - - mdast-util-gfm-autolink-literal@1.0.3: - resolution: {integrity: sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==} - - mdast-util-gfm-footnote@1.0.2: - resolution: {integrity: sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==} - - mdast-util-gfm-strikethrough@1.0.3: - resolution: {integrity: sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==} - - mdast-util-gfm-table@1.0.7: - resolution: {integrity: sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==} - - mdast-util-gfm-task-list-item@1.0.2: - resolution: {integrity: sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==} - - mdast-util-gfm@2.0.2: - resolution: {integrity: sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==} - - mdast-util-math@2.0.2: - resolution: {integrity: sha512-8gmkKVp9v6+Tgjtq6SYx9kGPpTf6FVYRa53/DLh479aldR9AyP48qeVOgNZ5X7QUK7nOy4yw7vg6mbiGcs9jWQ==} - - mdast-util-mdx-expression@1.3.2: - resolution: {integrity: sha512-xIPmR5ReJDu/DHH1OoIT1HkuybIfRGYRywC+gJtI7qHjCJp/M9jrmBEJW22O8lskDWm562BX2W8TiAwRTb0rKA==} - - mdast-util-mdx-jsx@2.1.4: - resolution: {integrity: sha512-DtMn9CmVhVzZx3f+optVDF8yFgQVt7FghCRNdlIaS3X5Bnym3hZwPbg/XW86vdpKjlc1PVj26SpnLGeJBXD3JA==} - - mdast-util-mdx@2.0.1: - resolution: {integrity: sha512-38w5y+r8nyKlGvNjSEqWrhG0w5PmnRA+wnBvm+ulYCct7nsGYhFVb0lljS9bQav4psDAS1eGkP2LMVcZBi/aqw==} - - mdast-util-mdxjs-esm@1.3.1: - resolution: {integrity: sha512-SXqglS0HrEvSdUEfoXFtcg7DRl7S2cwOXc7jkuusG472Mmjag34DUDeOJUZtl+BVnyeO1frIgVpHlNRWc2gk/w==} - - mdast-util-phrasing@3.0.1: - resolution: {integrity: sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg==} - - mdast-util-to-hast@12.3.0: - resolution: {integrity: sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==} - - mdast-util-to-hast@13.0.2: - resolution: {integrity: sha512-U5I+500EOOw9e3ZrclN3Is3fRpw8c19SMyNZlZ2IS+7vLsNzb2Om11VpIVOR+/0137GhZsFEF6YiKD5+0Hr2Og==} - - mdast-util-to-markdown@1.5.0: - resolution: {integrity: sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==} - - mdast-util-to-string@3.2.0: - resolution: {integrity: sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==} - meow@8.1.2: resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==} engines: {node: '>=10'} @@ -3548,132 +2734,6 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - mermaid@10.6.1: - resolution: {integrity: sha512-Hky0/RpOw/1il9X8AvzOEChfJtVvmXm+y7JML5C//ePYMy0/9jCEmW1E1g86x9oDfW9+iVEdTV/i+M6KWRNs4A==} - - micromark-core-commonmark@1.1.0: - resolution: {integrity: sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==} - - micromark-extension-gfm-autolink-literal@1.0.5: - resolution: {integrity: sha512-z3wJSLrDf8kRDOh2qBtoTRD53vJ+CWIyo7uyZuxf/JAbNJjiHsOpG1y5wxk8drtv3ETAHutCu6N3thkOOgueWg==} - - micromark-extension-gfm-footnote@1.1.2: - resolution: {integrity: sha512-Yxn7z7SxgyGWRNa4wzf8AhYYWNrwl5q1Z8ii+CSTTIqVkmGZF1CElX2JI8g5yGoM3GAman9/PVCUFUSJ0kB/8Q==} - - micromark-extension-gfm-strikethrough@1.0.7: - resolution: {integrity: sha512-sX0FawVE1o3abGk3vRjOH50L5TTLr3b5XMqnP9YDRb34M0v5OoZhG+OHFz1OffZ9dlwgpTBKaT4XW/AsUVnSDw==} - - micromark-extension-gfm-table@1.0.7: - resolution: {integrity: sha512-3ZORTHtcSnMQEKtAOsBQ9/oHp9096pI/UvdPtN7ehKvrmZZ2+bbWhi0ln+I9drmwXMt5boocn6OlwQzNXeVeqw==} - - micromark-extension-gfm-tagfilter@1.0.2: - resolution: {integrity: sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==} - - micromark-extension-gfm-task-list-item@1.0.5: - resolution: {integrity: sha512-RMFXl2uQ0pNQy6Lun2YBYT9g9INXtWJULgbt01D/x8/6yJ2qpKyzdZD3pi6UIkzF++Da49xAelVKUeUMqd5eIQ==} - - micromark-extension-gfm@2.0.3: - resolution: {integrity: sha512-vb9OoHqrhCmbRidQv/2+Bc6pkP0FrtlhurxZofvOEy5o8RtuuvTq+RQ1Vw5ZDNrVraQZu3HixESqbG+0iKk/MQ==} - - micromark-extension-math@2.1.2: - resolution: {integrity: sha512-es0CcOV89VNS9wFmyn+wyFTKweXGW4CEvdaAca6SWRWPyYCbBisnjaHLjWO4Nszuiud84jCpkHsqAJoa768Pvg==} - - micromark-extension-mdx-expression@1.0.8: - resolution: {integrity: sha512-zZpeQtc5wfWKdzDsHRBY003H2Smg+PUi2REhqgIhdzAa5xonhP03FcXxqFSerFiNUr5AWmHpaNPQTBVOS4lrXw==} - - micromark-extension-mdx-jsx@1.0.5: - resolution: {integrity: sha512-gPH+9ZdmDflbu19Xkb8+gheqEDqkSpdCEubQyxuz/Hn8DOXiXvrXeikOoBA71+e8Pfi0/UYmU3wW3H58kr7akA==} - - micromark-extension-mdx-md@1.0.1: - resolution: {integrity: sha512-7MSuj2S7xjOQXAjjkbjBsHkMtb+mDGVW6uI2dBL9snOBCbZmoNgDAeZ0nSn9j3T42UE/g2xVNMn18PJxZvkBEA==} - - micromark-extension-mdxjs-esm@1.0.5: - resolution: {integrity: sha512-xNRBw4aoURcyz/S69B19WnZAkWJMxHMT5hE36GtDAyhoyn/8TuAeqjFJQlwk+MKQsUD7b3l7kFX+vlfVWgcX1w==} - - micromark-extension-mdxjs@1.0.1: - resolution: {integrity: sha512-7YA7hF6i5eKOfFUzZ+0z6avRG52GpWR8DL+kN47y3f2KhxbBZMhmxe7auOeaTBrW2DenbbZTf1ea9tA2hDpC2Q==} - - micromark-factory-destination@1.1.0: - resolution: {integrity: sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==} - - micromark-factory-label@1.1.0: - resolution: {integrity: sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==} - - micromark-factory-mdx-expression@1.0.9: - resolution: {integrity: sha512-jGIWzSmNfdnkJq05c7b0+Wv0Kfz3NJ3N4cBjnbO4zjXIlxJr+f8lk+5ZmwFvqdAbUy2q6B5rCY//g0QAAaXDWA==} - - micromark-factory-space@1.1.0: - resolution: {integrity: sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==} - - micromark-factory-title@1.1.0: - resolution: {integrity: sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==} - - micromark-factory-whitespace@1.1.0: - resolution: {integrity: sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==} - - micromark-util-character@1.2.0: - resolution: {integrity: sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==} - - micromark-util-character@2.0.1: - resolution: {integrity: sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==} - - micromark-util-chunked@1.1.0: - resolution: {integrity: sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==} - - micromark-util-classify-character@1.1.0: - resolution: {integrity: sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==} - - micromark-util-combine-extensions@1.1.0: - resolution: {integrity: sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==} - - micromark-util-decode-numeric-character-reference@1.1.0: - resolution: {integrity: sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==} - - micromark-util-decode-string@1.1.0: - resolution: {integrity: sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==} - - micromark-util-encode@1.1.0: - resolution: {integrity: sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==} - - micromark-util-encode@2.0.0: - resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==} - - micromark-util-events-to-acorn@1.2.3: - resolution: {integrity: sha512-ij4X7Wuc4fED6UoLWkmo0xJQhsktfNh1J0m8g4PbIMPlx+ek/4YdW5mvbye8z/aZvAPUoxgXHrwVlXAPKMRp1w==} - - micromark-util-html-tag-name@1.2.0: - resolution: {integrity: sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==} - - micromark-util-normalize-identifier@1.1.0: - resolution: {integrity: sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==} - - micromark-util-resolve-all@1.1.0: - resolution: {integrity: sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==} - - micromark-util-sanitize-uri@1.2.0: - resolution: {integrity: sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==} - - micromark-util-sanitize-uri@2.0.0: - resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==} - - micromark-util-subtokenize@1.1.0: - resolution: {integrity: sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==} - - micromark-util-symbol@1.1.0: - resolution: {integrity: sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==} - - micromark-util-symbol@2.0.0: - resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==} - - micromark-util-types@1.1.0: - resolution: {integrity: sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==} - - micromark-util-types@2.0.0: - resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==} - - micromark@3.2.0: - resolution: {integrity: sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==} - micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} @@ -3752,58 +2812,6 @@ packages: nerf-dart@1.0.0: resolution: {integrity: sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==} - next-mdx-remote@4.4.1: - resolution: {integrity: sha512-1BvyXaIou6xy3XoNF4yaMZUCb6vD2GTAa5ciOa6WoO+gAUTYsb1K4rI/HSC2ogAWLrb/7VSV52skz07vOzmqIQ==} - engines: {node: '>=14', npm: '>=7'} - peerDependencies: - react: '>=16.x <=18.x' - react-dom: '>=16.x <=18.x' - - next-seo@6.4.0: - resolution: {integrity: sha512-XQFxkOL2hw0YE+P100HbI3EAvcludlHPxuzMgaIjKb7kPK0CvjGvLFjd9hszZFEDc5oiQkGFA8+cuWcnip7eYA==} - peerDependencies: - next: ^8.1.1-canary.54 || >=9.0.0 - react: '>=16.0.0' - react-dom: '>=16.0.0' - - next-themes@0.2.1: - resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==} - peerDependencies: - next: '*' - react: '*' - react-dom: '*' - - next@14.0.4: - resolution: {integrity: sha512-qbwypnM7327SadwFtxXnQdGiKpkuhaRLE2uq62/nRul9cj9KhQ5LhHmlziTNqUidZotw/Q1I9OjirBROdUJNgA==} - engines: {node: '>=18.17.0'} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - react: ^18.2.0 - react-dom: ^18.2.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - sass: - optional: true - - nextra-theme-docs@2.13.2: - resolution: {integrity: sha512-yE4umXaImp1/kf/sFciPj2+EFrNSwd9Db26hi98sIIiujzGf3+9eUgAz45vF9CwBw50FSXxm1QGRcY+slQ4xQQ==} - peerDependencies: - next: '>=9.5.3' - nextra: 2.13.2 - react: '>=16.13.1' - react-dom: '>=16.13.1' - - nextra@2.13.2: - resolution: {integrity: sha512-pIgOSXNUqTz1laxV4ChFZOU7lzJAoDHHaBPj8L09PuxrLKqU1BU/iZtXAG6bQeKCx8EPdBsoXxEuENnL9QGnGA==} - engines: {node: '>=16'} - peerDependencies: - next: '>=9.5.3' - react: '>=16.13.1' - react-dom: '>=16.13.1' - node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} @@ -3823,9 +2831,6 @@ packages: node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - non-layered-tidy-tree-layout@2.0.2: - resolution: {integrity: sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==} - normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -3837,10 +2842,6 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} - normalize-url@6.1.0: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} @@ -3870,10 +2871,6 @@ packages: resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - npm-to-yarn@2.1.0: - resolution: {integrity: sha512-2C1IgJLdJngq1bSER7K7CGFszRr9s2rijEwvENPEgI0eK9xlD3tNwDc0UJnRj7FIT2aydWm72jB88uVswAhXHA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - npm@8.19.3: resolution: {integrity: sha512-0QjmyPtDxSyMWWD8I91QGbrgx9KzbV6C9FK1liEb/K0zppiZkr5KxXc990G+LzPwBHDfRjUBlO9T1qZ08vl9mA==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -3957,10 +2954,6 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} - object-inspect@1.13.2: resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} engines: {node: '>= 0.4'} @@ -4092,9 +3085,6 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parse-entities@4.0.1: - resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==} - parse-json@4.0.0: resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} @@ -4103,18 +3093,6 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} - parse-numeric-range@1.3.0: - resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} - - parse-path@7.0.0: - resolution: {integrity: sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==} - - parse-url@8.1.0: - resolution: {integrity: sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==} - - parse5@7.1.2: - resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} - path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} @@ -4161,9 +3139,6 @@ packages: resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} engines: {node: '>= 14.16'} - periscopic@3.1.0: - resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} - picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -4174,10 +3149,6 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - pify@3.0.0: resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} engines: {node: '>=4'} @@ -4198,18 +3169,6 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} - postcss-import@15.1.0: - resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} - engines: {node: '>=14.0.0'} - peerDependencies: - postcss: ^8.0.0 - - postcss-js@4.0.1: - resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.4.21 - postcss-load-config@4.0.2: resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} engines: {node: '>= 14'} @@ -4222,23 +3181,6 @@ packages: ts-node: optional: true - postcss-nested@6.0.1: - resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.2.14 - - postcss-selector-parser@6.0.15: - resolution: {integrity: sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==} - engines: {node: '>=4'} - - postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.4.33: resolution: {integrity: sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==} engines: {node: ^10 || ^12 || >=14} @@ -4258,15 +3200,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - property-information@6.4.0: - resolution: {integrity: sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==} - proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - protocols@2.0.1: - resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==} - pseudomap@1.0.2: resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} @@ -4301,21 +3237,9 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - react-dom@18.2.0: - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} - peerDependencies: - react: ^18.2.0 - react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} - engines: {node: '>=0.10.0'} - - read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - read-pkg-up@7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} engines: {node: '>=8'} @@ -4343,9 +3267,6 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - reading-time@1.5.0: - resolution: {integrity: sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==} - redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -4393,39 +3314,6 @@ packages: resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} hasBin: true - rehype-katex@7.0.0: - resolution: {integrity: sha512-h8FPkGE00r2XKU+/acgqwWUlyzve1IiOKwsEkg4pDL3k48PiE0Pt+/uLtVHDVkN1yA4iurZN6UES8ivHVEQV6Q==} - - rehype-pretty-code@0.9.11: - resolution: {integrity: sha512-Eq90eCYXQJISktfRZ8PPtwc5SUyH6fJcxS8XOMnHPUQZBtC6RYo67gGlley9X2nR8vlniPj0/7oCDEYHKQa/oA==} - engines: {node: '>=16'} - peerDependencies: - shiki: '*' - - rehype-raw@7.0.0: - resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} - - remark-gfm@3.0.1: - resolution: {integrity: sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==} - - remark-math@5.1.1: - resolution: {integrity: sha512-cE5T2R/xLVtfFI4cCePtiRn+e6jKMtFDR3P8V3qpv8wpKjwvHoBA4eJzvX+nVrnlNy0911bdGmuspCSwetfYHw==} - - remark-mdx@2.3.0: - resolution: {integrity: sha512-g53hMkpM0I98MU266IzDFMrTD980gNF3BJnkyFcmN+dD873mQeD5rdMO3Y2X+x8umQfbSE0PcoEDl7ledSA+2g==} - - remark-parse@10.0.2: - resolution: {integrity: sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==} - - remark-reading-time@2.0.1: - resolution: {integrity: sha512-fy4BKy9SRhtYbEHvp6AItbRTnrhiDGbqLQTSYVbQPGuRCncU1ubSsh9p/W5QZSxtYcUXv8KGL0xBgPLyNJA1xw==} - - remark-rehype@10.1.0: - resolution: {integrity: sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==} - - remove-accents@0.4.2: - resolution: {integrity: sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==} - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -4462,9 +3350,6 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - robust-predicates@3.0.2: - resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} - rollup@4.9.0: resolution: {integrity: sha512-bUHW/9N21z64gw8s6tP4c88P382Bq/L5uZDowHlHx6s/QWpjJXivIAbEw6LZthgSvlEizZBfLC4OAvWe7aoF7A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -4473,9 +3358,6 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rw@1.3.3: - resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} - sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -4494,24 +3376,11 @@ packages: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass@1.69.7: resolution: {integrity: sha512-rzj2soDeZ8wtE2egyLXgOOHQvaC2iosZrkF6v3EUG+tBwEvhqUCzm0VP3k9gHF9LXbSrRhT5SksoI56Iw8NPnQ==} engines: {node: '>=14.0.0'} hasBin: true - scheduler@0.23.0: - resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} - - scroll-into-view-if-needed@3.1.0: - resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} - - section-matter@1.0.0: - resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} - engines: {node: '>=4'} - semantic-release-monorepo@7.0.5: resolution: {integrity: sha512-riOYD8eZ5PIST7o97Ltc01l8VQW7q01NmPDRPOBycaeZczJowyKkzkBfo92kTIWDFWbdO3G8A695JrrYjoTaiw==} peerDependencies: @@ -4577,9 +3446,6 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@0.14.6: - resolution: {integrity: sha512-R4koBBlQP33cC8cpzX0hAoOURBHJILp4Aaduh2eYi+Vj8ZBqtK/5SWNEHBS3qwUMu8dqOtI/ftno3ESfNeVW9g==} - side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} @@ -4606,10 +3472,6 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - sort-keys@5.0.0: - resolution: {integrity: sha512-Pdz01AvCAottHTPQGzndktFNdbRA75BgOfeT1hH+AMnJFv8lynkPi42rfeEhpx1saTEI3YNMWxfqu0sFD1G8pw==} - engines: {node: '>=12'} - source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} @@ -4618,17 +3480,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - source-map@0.7.4: - resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} - engines: {node: '>= 8'} - source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} - space-separated-tokens@2.0.2: - resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - spawn-error-forwarder@1.0.0: resolution: {integrity: sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==} @@ -4653,9 +3508,6 @@ packages: split@1.0.1: resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -4669,10 +3521,6 @@ packages: stream-combiner2@1.1.1: resolution: {integrity: sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==} - streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} - string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -4705,9 +3553,6 @@ packages: string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - stringify-entities@4.0.3: - resolution: {integrity: sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==} - strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -4716,10 +3561,6 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} - strip-bom-string@1.0.0: - resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} - engines: {node: '>=0.10.0'} - strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -4748,34 +3589,11 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - style-to-object@0.4.4: - resolution: {integrity: sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==} - - styled-jsx@5.1.1: - resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true - - stylis@4.3.0: - resolution: {integrity: sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==} - sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} hasBin: true - supports-color@4.5.0: - resolution: {integrity: sha512-ycQR/UbvI9xIlEdQT1TQqwoXtEldExbCEAJgRo5YXlmSKjv6ThHnP9/vwGa1gr19Gfw+LkFd7KqYMhzrRC5JYw==} - engines: {node: '>=4'} - supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -4796,11 +3614,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - tailwindcss@3.4.1: - resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==} - engines: {node: '>=14.0.0'} - hasBin: true - tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} @@ -4851,14 +3664,6 @@ packages: resolution: {integrity: sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==} engines: {node: '>=14.0.0'} - title@3.5.3: - resolution: {integrity: sha512-20JyowYglSEeCvZv3EZ0nZ046vLarO37prvV0mbtQV7C8DJPGgN967r8SJkqd3XK3K3lD3/Iyfp3avjfil8Q2Q==} - hasBin: true - - titleize@1.0.0: - resolution: {integrity: sha512-TARUb7z1pGvlLxgPk++7wJ6aycXF3GJ0sNSBTAsTuJrQG5QuZlkUQP+zl+nbjAh4gMX9yDw9ZYklMd7vAfJKEw==} - engines: {node: '>=0.10.0'} - to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} @@ -4880,26 +3685,16 @@ packages: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true - trim-lines@3.0.1: - resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} - trim-newlines@3.0.1: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} engines: {node: '>=8'} - trough@2.1.0: - resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} - ts-api-utils@1.3.0: resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' - ts-dedent@2.2.0: - resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} - engines: {node: '>=6.10'} - ts-expose-internals-conditionally@1.0.0-empty.0: resolution: {integrity: sha512-F8m9NOF6ZhdOClDVdlM8gj3fDCav4ZIFSs/EI3ksQbAAXVSCN/Jh5OCJDDZWBuBy9psFc6jULGDlPwjMYMhJDw==} @@ -4909,9 +3704,6 @@ packages: tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - tslib@2.4.1: - resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} - tsup@8.1.0: resolution: {integrity: sha512-UFdfCAXukax+U6KzeTNO2kAARHcWxmKsnvSPXUcfA1D+kU05XDccCrkffCQpFaWDsZfV0jMyTsxU39VfCp6EOg==} engines: {node: '>=18'} @@ -5059,97 +3851,31 @@ packages: resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} engines: {node: '>=4'} - unified@10.1.2: - resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==} - unique-string@2.0.0: resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} engines: {node: '>=8'} - unist-util-find-after@5.0.0: - resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + universal-user-agent@6.0.0: + resolution: {integrity: sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==} - unist-util-generated@2.0.1: - resolution: {integrity: sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==} + universalify@2.0.0: + resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + engines: {node: '>= 10.0.0'} - unist-util-is@5.2.1: - resolution: {integrity: sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==} + update-browserslist-db@1.0.13: + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' - unist-util-is@6.0.0: - resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - unist-util-position-from-estree@1.1.2: - resolution: {integrity: sha512-poZa0eXpS+/XpoQwGwl79UUdea4ol2ZuCYguVaJS4qzIOMDzbqz8a3erUCOmubSZkaOuGamb3tX790iwOIROww==} + url-join@4.0.1: + resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} - unist-util-position@4.0.4: - resolution: {integrity: sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==} - - unist-util-position@5.0.0: - resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} - - unist-util-remove-position@4.0.2: - resolution: {integrity: sha512-TkBb0HABNmxzAcfLf4qsIbFbaPDvMO6wa3b3j4VcEzFVaw1LBKwnW4/sRJ/atSLSzoIg41JWEdnE7N6DIhGDGQ==} - - unist-util-remove-position@5.0.0: - resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} - - unist-util-remove@4.0.0: - resolution: {integrity: sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg==} - - unist-util-stringify-position@3.0.3: - resolution: {integrity: sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==} - - unist-util-stringify-position@4.0.0: - resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} - - unist-util-visit-parents@4.1.1: - resolution: {integrity: sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw==} - - unist-util-visit-parents@5.1.3: - resolution: {integrity: sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==} - - unist-util-visit-parents@6.0.1: - resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} - - unist-util-visit@3.1.0: - resolution: {integrity: sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA==} - - unist-util-visit@4.1.2: - resolution: {integrity: sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==} - - unist-util-visit@5.0.0: - resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} - - universal-user-agent@6.0.0: - resolution: {integrity: sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==} - - universalify@2.0.0: - resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} - engines: {node: '>= 10.0.0'} - - update-browserslist-db@1.0.13: - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - url-join@4.0.1: - resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - - uvu@0.5.6: - resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==} - engines: {node: '>=8'} - hasBin: true + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} @@ -5158,24 +3884,6 @@ packages: resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - vfile-location@5.0.2: - resolution: {integrity: sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==} - - vfile-matter@3.0.1: - resolution: {integrity: sha512-CAAIDwnh6ZdtrqAuxdElUqQRQDQgbbIrYtDYI8gCjXS1qQ+1XdLoK8FIZWxJwn0/I+BkSSZpar3SOgjemQz4fg==} - - vfile-message@3.1.4: - resolution: {integrity: sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==} - - vfile-message@4.0.2: - resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} - - vfile@5.3.7: - resolution: {integrity: sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==} - - vfile@6.0.1: - resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==} - vite-node@2.0.5: resolution: {integrity: sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==} engines: {node: ^18.0.0 || >=20.0.0} @@ -5234,22 +3942,6 @@ packages: jsdom: optional: true - vscode-oniguruma@1.7.0: - resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} - - vscode-textmate@8.0.0: - resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} - - watchpack@2.4.0: - resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} - engines: {node: '>=10.13.0'} - - web-namespaces@2.0.1: - resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} - - web-worker@1.2.0: - resolution: {integrity: sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==} - webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -5350,21 +4042,8 @@ packages: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} - zod-to-json-schema@3.22.3: - resolution: {integrity: sha512-9isG8SqRe07p+Aio2ruBZmLm2Q6Sq4EqmXOiNpDxp+7f0LV6Q/LX65fs5Nn+FV/CzfF3NLBoksXbS2jNYIfpKw==} - peerDependencies: - zod: ^3.22.4 - - zod@3.22.4: - resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} - - zwitch@2.0.4: - resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - snapshots: - '@alloc/quick-lru@5.2.0': {} - '@ampproject/remapping@2.2.0': dependencies: '@jridgewell/gen-mapping': 0.1.1 @@ -6106,8 +4785,6 @@ snapshots: '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 - '@braintree/sanitize-url@6.0.4': {} - '@cloudinary/transformation-builder-sdk@1.10.1': dependencies: '@cloudinary/url-gen': 1.15.0 @@ -6293,12 +4970,6 @@ snapshots: '@eslint/js@8.57.0': {} - '@headlessui/react@1.7.17(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': - dependencies: - client-only: 0.0.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 @@ -6359,114 +5030,10 @@ snapshots: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.15 - '@mdx-js/mdx@2.3.0': - dependencies: - '@types/estree-jsx': 1.0.3 - '@types/mdx': 2.0.10 - estree-util-build-jsx: 2.2.2 - estree-util-is-identifier-name: 2.1.0 - estree-util-to-js: 1.2.0 - estree-walker: 3.0.3 - hast-util-to-estree: 2.3.3 - markdown-extensions: 1.1.1 - periscopic: 3.1.0 - remark-mdx: 2.3.0 - remark-parse: 10.0.2 - remark-rehype: 10.1.0 - unified: 10.1.2 - unist-util-position-from-estree: 1.1.2 - unist-util-stringify-position: 3.0.3 - unist-util-visit: 4.1.2 - vfile: 5.3.7 - transitivePeerDependencies: - - supports-color - - '@mdx-js/react@2.3.0(react@18.2.0)': - dependencies: - '@types/mdx': 2.0.10 - '@types/react': 18.0.25 - react: 18.2.0 - - '@napi-rs/simple-git-android-arm-eabi@0.1.9': - optional: true - - '@napi-rs/simple-git-android-arm64@0.1.9': - optional: true - - '@napi-rs/simple-git-darwin-arm64@0.1.9': - optional: true - - '@napi-rs/simple-git-darwin-x64@0.1.9': - optional: true - - '@napi-rs/simple-git-linux-arm-gnueabihf@0.1.9': - optional: true - - '@napi-rs/simple-git-linux-arm64-gnu@0.1.9': - optional: true - - '@napi-rs/simple-git-linux-arm64-musl@0.1.9': - optional: true - - '@napi-rs/simple-git-linux-x64-gnu@0.1.9': - optional: true - - '@napi-rs/simple-git-linux-x64-musl@0.1.9': - optional: true - - '@napi-rs/simple-git-win32-arm64-msvc@0.1.9': - optional: true - - '@napi-rs/simple-git-win32-x64-msvc@0.1.9': - optional: true - - '@napi-rs/simple-git@0.1.9': - optionalDependencies: - '@napi-rs/simple-git-android-arm-eabi': 0.1.9 - '@napi-rs/simple-git-android-arm64': 0.1.9 - '@napi-rs/simple-git-darwin-arm64': 0.1.9 - '@napi-rs/simple-git-darwin-x64': 0.1.9 - '@napi-rs/simple-git-linux-arm-gnueabihf': 0.1.9 - '@napi-rs/simple-git-linux-arm64-gnu': 0.1.9 - '@napi-rs/simple-git-linux-arm64-musl': 0.1.9 - '@napi-rs/simple-git-linux-x64-gnu': 0.1.9 - '@napi-rs/simple-git-linux-x64-musl': 0.1.9 - '@napi-rs/simple-git-win32-arm64-msvc': 0.1.9 - '@napi-rs/simple-git-win32-x64-msvc': 0.1.9 - - '@next/env@14.0.4': {} - '@next/eslint-plugin-next@14.2.4': dependencies: glob: 10.3.10 - '@next/swc-darwin-arm64@14.0.4': - optional: true - - '@next/swc-darwin-x64@14.0.4': - optional: true - - '@next/swc-linux-arm64-gnu@14.0.4': - optional: true - - '@next/swc-linux-arm64-musl@14.0.4': - optional: true - - '@next/swc-linux-x64-gnu@14.0.4': - optional: true - - '@next/swc-linux-x64-musl@14.0.4': - optional: true - - '@next/swc-win32-arm64-msvc@14.0.4': - optional: true - - '@next/swc-win32-ia32-msvc@14.0.4': - optional: true - - '@next/swc-win32-x64-msvc@14.0.4': - optional: true - '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -6568,8 +5135,6 @@ snapshots: '@pnpm/network.ca-file': 1.0.2 config-chain: 1.1.13 - '@popperjs/core@2.11.8': {} - '@rollup/rollup-android-arm-eabi@4.9.0': optional: true @@ -6706,99 +5271,25 @@ snapshots: '@sindresorhus/is@4.6.0': {} - '@swc/helpers@0.5.2': - dependencies: - tslib: 2.4.1 - - '@theguild/remark-mermaid@0.0.5(react@18.2.0)': - dependencies: - mermaid: 10.6.1 - react: 18.2.0 - unist-util-visit: 5.0.0 - transitivePeerDependencies: - - supports-color - - '@theguild/remark-npm2yarn@0.2.1': - dependencies: - npm-to-yarn: 2.1.0 - unist-util-visit: 5.0.0 - '@tootallnate/once@2.0.0': {} - '@types/acorn@4.0.6': - dependencies: - '@types/estree': 1.0.5 - - '@types/d3-scale-chromatic@3.0.3': {} - - '@types/d3-scale@4.0.8': - dependencies: - '@types/d3-time': 3.0.3 - - '@types/d3-time@3.0.3': {} - - '@types/debug@4.1.12': - dependencies: - '@types/ms': 0.7.34 - - '@types/estree-jsx@1.0.3': - dependencies: - '@types/estree': 1.0.5 - '@types/estree@1.0.5': {} - '@types/hast@2.3.8': - dependencies: - '@types/unist': 2.0.10 - - '@types/hast@3.0.3': - dependencies: - '@types/unist': 3.0.2 - - '@types/js-yaml@4.0.9': {} - '@types/json5@0.0.29': {} - '@types/katex@0.16.7': {} - - '@types/mdast@3.0.15': - dependencies: - '@types/unist': 2.0.10 - - '@types/mdast@4.0.3': - dependencies: - '@types/unist': 3.0.2 - - '@types/mdx@2.0.10': {} - '@types/minimist@1.2.2': {} - '@types/ms@0.7.34': {} - '@types/node@17.0.45': {} '@types/node@20.10.8': dependencies: undici-types: 5.26.5 + optional: true '@types/normalize-package-data@2.4.1': {} - '@types/prop-types@15.7.5': {} - - '@types/react@18.0.25': - dependencies: - '@types/prop-types': 15.7.5 - '@types/scheduler': 0.16.2 - csstype: 3.1.1 - '@types/retry@0.12.0': {} - '@types/scheduler@0.16.2': {} - - '@types/unist@2.0.10': {} - - '@types/unist@3.0.2': {} - '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2)': dependencies: '@eslint-community/regexpp': 4.11.0 @@ -6999,8 +5490,6 @@ snapshots: ansi-regex@6.0.1: {} - ansi-sequence-parser@1.1.1: {} - ansi-styles@3.2.1: dependencies: color-convert: 1.9.3 @@ -7020,16 +5509,6 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - arch@2.2.0: {} - - arg@1.0.0: {} - - arg@5.0.2: {} - - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - argparse@2.0.1: {} argv-formatter@1.0.0: {} @@ -7120,18 +5599,6 @@ snapshots: ast-types-flow@0.0.8: {} - astring@1.8.6: {} - - autoprefixer@10.4.16(postcss@8.4.33): - dependencies: - browserslist: 4.22.2 - caniuse-lite: 1.0.30001576 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.0.0 - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 @@ -7166,8 +5633,6 @@ snapshots: transitivePeerDependencies: - supports-color - bail@2.0.2: {} - balanced-match@1.0.2: {} before-after-hook@2.2.3: {} @@ -7201,10 +5666,6 @@ snapshots: esbuild: 0.21.5 load-tsconfig: 0.2.3 - busboy@1.6.0: - dependencies: - streamsearch: 1.1.0 - cac@6.7.14: {} call-bind@1.0.7: @@ -7217,8 +5678,6 @@ snapshots: callsites@3.1.0: {} - camelcase-css@2.0.1: {} - camelcase-keys@6.2.2: dependencies: camelcase: 5.3.1 @@ -7234,8 +5693,6 @@ snapshots: ansicolors: 0.3.2 redeyed: 2.1.1 - ccount@2.0.1: {} - chai@5.1.1: dependencies: assertion-error: 2.0.1 @@ -7244,12 +5701,6 @@ snapshots: loupe: 3.1.1 pathval: 2.0.0 - chalk@2.3.0: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 4.5.0 - chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -7267,14 +5718,6 @@ snapshots: char-regex@1.0.2: {} - character-entities-html4@2.1.0: {} - - character-entities-legacy@3.0.0: {} - - character-entities@2.0.2: {} - - character-reference-invalid@2.0.1: {} - check-error@2.1.1: {} chokidar@3.5.3: @@ -7301,21 +5744,12 @@ snapshots: optionalDependencies: '@colors/colors': 1.5.0 - client-only@0.0.1: {} - - clipboardy@1.2.2: - dependencies: - arch: 2.2.0 - execa: 0.8.0 - cliui@8.0.1: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - clsx@2.0.0: {} - color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -7328,23 +5762,15 @@ snapshots: color-name@1.1.4: {} - comma-separated-tokens@2.0.3: {} - commander@10.0.1: {} commander@4.1.1: {} - commander@7.2.0: {} - - commander@8.3.0: {} - compare-func@2.0.0: dependencies: array-ify: 1.0.0 dot-prop: 5.3.0 - compute-scroll-into-view@3.1.0: {} - concat-map@0.0.1: {} config-chain@1.1.13: @@ -7391,14 +5817,6 @@ snapshots: core-util-is@1.0.3: {} - cose-base@1.0.3: - dependencies: - layout-base: 1.0.2 - - cose-base@2.2.0: - dependencies: - layout-base: 2.0.1 - cosmiconfig@8.0.0: dependencies: import-fresh: 3.3.0 @@ -7420,284 +5838,87 @@ snapshots: crypto-random-string@2.0.0: {} - cssesc@3.0.0: {} - - csstype@3.1.1: {} - - cytoscape-cose-bilkent@4.1.0(cytoscape@3.28.0): - dependencies: - cose-base: 1.0.3 - cytoscape: 3.28.0 - - cytoscape-fcose@2.2.0(cytoscape@3.28.0): - dependencies: - cose-base: 2.2.0 - cytoscape: 3.28.0 + damerau-levenshtein@1.0.8: {} - cytoscape@3.28.0: + data-view-buffer@1.0.1: dependencies: - heap: 0.2.7 - lodash: 4.17.21 + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 - d3-array@2.12.1: + data-view-byte-length@1.0.1: dependencies: - internmap: 1.0.1 + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 - d3-array@3.2.4: + data-view-byte-offset@1.0.0: dependencies: - internmap: 2.0.3 + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 - d3-axis@3.0.0: {} + dateformat@3.0.3: {} - d3-brush@3.0.0: + debug@3.2.7: dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) + ms: 2.1.3 - d3-chord@3.0.1: + debug@4.3.4: dependencies: - d3-path: 3.1.0 - - d3-color@3.1.0: {} + ms: 2.1.2 - d3-contour@4.0.2: + debug@4.3.6: dependencies: - d3-array: 3.2.4 + ms: 2.1.2 - d3-delaunay@6.0.4: + decamelize-keys@1.1.1: dependencies: - delaunator: 5.0.0 + decamelize: 1.2.0 + map-obj: 1.0.1 - d3-dispatch@3.0.1: {} + decamelize@1.2.0: {} - d3-drag@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-selection: 3.0.0 + deep-eql@5.0.2: {} - d3-dsv@3.0.1: + deep-equal@2.2.3: dependencies: - commander: 7.2.0 - iconv-lite: 0.6.3 - rw: 1.3.3 + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + es-get-iterator: 1.1.3 + get-intrinsic: 1.2.4 + is-arguments: 1.1.1 + is-array-buffer: 3.0.4 + is-date-object: 1.0.5 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + isarray: 2.0.5 + object-is: 1.1.6 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + side-channel: 1.0.6 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.2 + which-typed-array: 1.1.15 - d3-ease@3.0.1: {} + deep-extend@0.6.0: {} - d3-fetch@3.0.1: - dependencies: - d3-dsv: 3.0.1 + deep-is@0.1.4: {} - d3-force@3.0.0: + define-data-property@1.1.4: dependencies: - d3-dispatch: 3.0.1 - d3-quadtree: 3.0.1 - d3-timer: 3.0.1 - - d3-format@3.1.0: {} + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 - d3-geo@3.1.0: + define-properties@1.2.1: dependencies: - d3-array: 3.2.4 - - d3-hierarchy@3.1.2: {} + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 - d3-interpolate@3.0.1: - dependencies: - d3-color: 3.1.0 - - d3-path@1.0.9: {} - - d3-path@3.1.0: {} - - d3-polygon@3.0.1: {} - - d3-quadtree@3.0.1: {} - - d3-random@3.0.1: {} - - d3-sankey@0.12.3: - dependencies: - d3-array: 2.12.1 - d3-shape: 1.3.7 - - d3-scale-chromatic@3.0.0: - dependencies: - d3-color: 3.1.0 - d3-interpolate: 3.0.1 - - d3-scale@4.0.2: - dependencies: - d3-array: 3.2.4 - d3-format: 3.1.0 - d3-interpolate: 3.0.1 - d3-time: 3.1.0 - d3-time-format: 4.1.0 - - d3-selection@3.0.0: {} - - d3-shape@1.3.7: - dependencies: - d3-path: 1.0.9 - - d3-shape@3.2.0: - dependencies: - d3-path: 3.1.0 - - d3-time-format@4.1.0: - dependencies: - d3-time: 3.1.0 - - d3-time@3.1.0: - dependencies: - d3-array: 3.2.4 - - d3-timer@3.0.1: {} - - d3-transition@3.0.1(d3-selection@3.0.0): - dependencies: - d3-color: 3.1.0 - d3-dispatch: 3.0.1 - d3-ease: 3.0.1 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-timer: 3.0.1 - - d3-zoom@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) - - d3@7.8.5: - dependencies: - d3-array: 3.2.4 - d3-axis: 3.0.0 - d3-brush: 3.0.0 - d3-chord: 3.0.1 - d3-color: 3.1.0 - d3-contour: 4.0.2 - d3-delaunay: 6.0.4 - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-dsv: 3.0.1 - d3-ease: 3.0.1 - d3-fetch: 3.0.1 - d3-force: 3.0.0 - d3-format: 3.1.0 - d3-geo: 3.1.0 - d3-hierarchy: 3.1.2 - d3-interpolate: 3.0.1 - d3-path: 3.1.0 - d3-polygon: 3.0.1 - d3-quadtree: 3.0.1 - d3-random: 3.0.1 - d3-scale: 4.0.2 - d3-scale-chromatic: 3.0.0 - d3-selection: 3.0.0 - d3-shape: 3.2.0 - d3-time: 3.1.0 - d3-time-format: 4.1.0 - d3-timer: 3.0.1 - d3-transition: 3.0.1(d3-selection@3.0.0) - d3-zoom: 3.0.0 - - dagre-d3-es@7.0.10: - dependencies: - d3: 7.8.5 - lodash-es: 4.17.21 - - damerau-levenshtein@1.0.8: {} - - data-view-buffer@1.0.1: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-data-view: 1.0.1 - - data-view-byte-length@1.0.1: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-data-view: 1.0.1 - - data-view-byte-offset@1.0.0: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-data-view: 1.0.1 - - dateformat@3.0.3: {} - - dayjs@1.11.10: {} - - debug@3.2.7: - dependencies: - ms: 2.1.3 - - debug@4.3.4: - dependencies: - ms: 2.1.2 - - debug@4.3.6: - dependencies: - ms: 2.1.2 - - decamelize-keys@1.1.1: - dependencies: - decamelize: 1.2.0 - map-obj: 1.0.1 - - decamelize@1.2.0: {} - - decode-named-character-reference@1.0.2: - dependencies: - character-entities: 2.0.2 - - deep-eql@5.0.2: {} - - deep-equal@2.2.3: - dependencies: - array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 - es-get-iterator: 1.1.3 - get-intrinsic: 1.2.4 - is-arguments: 1.1.1 - is-array-buffer: 3.0.4 - is-date-object: 1.0.5 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.3 - isarray: 2.0.5 - object-is: 1.1.6 - object-keys: 1.1.1 - object.assign: 4.1.5 - regexp.prototype.flags: 1.5.2 - side-channel: 1.0.6 - which-boxed-primitive: 1.0.2 - which-collection: 1.0.2 - which-typed-array: 1.1.15 - - deep-extend@0.6.0: {} - - deep-is@0.1.4: {} - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - gopd: 1.0.1 - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - - del@6.1.1: + del@6.1.1: dependencies: globby: 11.1.0 graceful-fs: 4.2.11 @@ -7708,28 +5929,12 @@ snapshots: rimraf: 3.0.2 slash: 3.0.0 - delaunator@5.0.0: - dependencies: - robust-predicates: 3.0.2 - deprecation@2.3.1: {} - dequal@2.0.3: {} - - devlop@1.1.0: - dependencies: - dequal: 2.0.3 - - didyoumean@1.2.2: {} - - diff@5.1.0: {} - dir-glob@3.0.1: dependencies: path-type: 4.0.0 - dlv@1.1.3: {} - doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -7738,8 +5943,6 @@ snapshots: dependencies: esutils: 2.0.3 - dompurify@3.0.6: {} - dot-prop@5.3.0: dependencies: is-obj: 2.0.0 @@ -7752,8 +5955,6 @@ snapshots: electron-to-chromium@1.4.626: {} - elkjs@0.8.2: {} - emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -7765,8 +5966,6 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.2.1 - entities@4.5.0: {} - env-ci@8.0.0: dependencies: execa: 6.1.0 @@ -8179,33 +6378,6 @@ snapshots: estraverse@5.3.0: {} - estree-util-attach-comments@2.1.1: - dependencies: - '@types/estree': 1.0.5 - - estree-util-build-jsx@2.2.2: - dependencies: - '@types/estree-jsx': 1.0.3 - estree-util-is-identifier-name: 2.1.0 - estree-walker: 3.0.3 - - estree-util-is-identifier-name@2.1.0: {} - - estree-util-to-js@1.2.0: - dependencies: - '@types/estree-jsx': 1.0.3 - astring: 1.8.6 - source-map: 0.7.4 - - estree-util-value-to-estree@1.3.0: - dependencies: - is-plain-obj: 3.0.0 - - estree-util-visit@1.2.1: - dependencies: - '@types/estree-jsx': 1.0.3 - '@types/unist': 2.0.10 - estree-walker@3.0.3: dependencies: '@types/estree': 1.0.5 @@ -8258,12 +6430,6 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 - extend-shallow@2.0.1: - dependencies: - is-extendable: 0.1.1 - - extend@3.0.2: {} - fast-deep-equal@3.1.3: {} fast-glob@3.2.12: @@ -8339,10 +6505,6 @@ snapshots: flatted@3.2.7: {} - flexsearch@0.7.31: {} - - focus-visible@5.2.0: {} - for-each@0.3.3: dependencies: is-callable: 1.2.7 @@ -8352,8 +6514,6 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 - fraction.js@4.3.7: {} - from2@2.3.0: dependencies: inherits: 2.0.4 @@ -8428,17 +6588,6 @@ snapshots: through2: 2.0.5 traverse: 0.6.7 - git-up@7.0.0: - dependencies: - is-ssh: 1.4.0 - parse-url: 8.1.0 - - git-url-parse@13.1.1: - dependencies: - git-up: 7.0.0 - - github-slugger@2.0.0: {} - glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -8447,8 +6596,6 @@ snapshots: dependencies: is-glob: 4.0.3 - glob-to-regexp@0.4.1: {} - glob@10.3.10: dependencies: foreground-child: 3.1.1 @@ -8504,13 +6651,6 @@ snapshots: graphemer@1.4.0: {} - gray-matter@4.0.3: - dependencies: - js-yaml: 3.14.1 - kind-of: 6.0.3 - section-matter: 1.0.0 - strip-bom-string: 1.0.0 - handlebars@4.7.7: dependencies: minimist: 1.2.7 @@ -8524,8 +6664,6 @@ snapshots: has-bigints@1.0.2: {} - has-flag@2.0.0: {} - has-flag@3.0.0: {} has-flag@4.0.0: {} @@ -8546,12 +6684,6 @@ snapshots: dependencies: function-bind: 1.1.1 - hash-obj@4.0.0: - dependencies: - is-obj: 3.0.0 - sort-keys: 5.0.0 - type-fest: 1.4.0 - hasown@2.0.0: dependencies: function-bind: 1.1.2 @@ -8560,112 +6692,6 @@ snapshots: dependencies: function-bind: 1.1.2 - hast-util-from-dom@5.0.0: - dependencies: - '@types/hast': 3.0.3 - hastscript: 8.0.0 - web-namespaces: 2.0.1 - - hast-util-from-html-isomorphic@2.0.0: - dependencies: - '@types/hast': 3.0.3 - hast-util-from-dom: 5.0.0 - hast-util-from-html: 2.0.1 - unist-util-remove-position: 5.0.0 - - hast-util-from-html@2.0.1: - dependencies: - '@types/hast': 3.0.3 - devlop: 1.1.0 - hast-util-from-parse5: 8.0.1 - parse5: 7.1.2 - vfile: 6.0.1 - vfile-message: 4.0.2 - - hast-util-from-parse5@8.0.1: - dependencies: - '@types/hast': 3.0.3 - '@types/unist': 3.0.2 - devlop: 1.1.0 - hastscript: 8.0.0 - property-information: 6.4.0 - vfile: 6.0.1 - vfile-location: 5.0.2 - web-namespaces: 2.0.1 - - hast-util-is-element@3.0.0: - dependencies: - '@types/hast': 3.0.3 - - hast-util-parse-selector@4.0.0: - dependencies: - '@types/hast': 3.0.3 - - hast-util-raw@9.0.1: - dependencies: - '@types/hast': 3.0.3 - '@types/unist': 3.0.2 - '@ungap/structured-clone': 1.2.0 - hast-util-from-parse5: 8.0.1 - hast-util-to-parse5: 8.0.0 - html-void-elements: 3.0.0 - mdast-util-to-hast: 13.0.2 - parse5: 7.1.2 - unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 - vfile: 6.0.1 - web-namespaces: 2.0.1 - zwitch: 2.0.4 - - hast-util-to-estree@2.3.3: - dependencies: - '@types/estree': 1.0.5 - '@types/estree-jsx': 1.0.3 - '@types/hast': 2.3.8 - '@types/unist': 2.0.10 - comma-separated-tokens: 2.0.3 - estree-util-attach-comments: 2.1.1 - estree-util-is-identifier-name: 2.1.0 - hast-util-whitespace: 2.0.1 - mdast-util-mdx-expression: 1.3.2 - mdast-util-mdxjs-esm: 1.3.1 - property-information: 6.4.0 - space-separated-tokens: 2.0.2 - style-to-object: 0.4.4 - unist-util-position: 4.0.4 - zwitch: 2.0.4 - transitivePeerDependencies: - - supports-color - - hast-util-to-parse5@8.0.0: - dependencies: - '@types/hast': 3.0.3 - comma-separated-tokens: 2.0.3 - devlop: 1.1.0 - property-information: 6.4.0 - space-separated-tokens: 2.0.2 - web-namespaces: 2.0.1 - zwitch: 2.0.4 - - hast-util-to-text@4.0.0: - dependencies: - '@types/hast': 3.0.3 - '@types/unist': 3.0.2 - hast-util-is-element: 3.0.0 - unist-util-find-after: 5.0.0 - - hast-util-whitespace@2.0.1: {} - - hastscript@8.0.0: - dependencies: - '@types/hast': 3.0.3 - comma-separated-tokens: 2.0.3 - hast-util-parse-selector: 4.0.0 - property-information: 6.4.0 - space-separated-tokens: 2.0.2 - - heap@0.2.7: {} - hook-std@3.0.0: {} hosted-git-info@2.8.9: {} @@ -8678,8 +6704,6 @@ snapshots: dependencies: lru-cache: 7.14.1 - html-void-elements@3.0.0: {} - http-proxy-agent@5.0.0: dependencies: '@tootallnate/once': 2.0.0 @@ -8701,10 +6725,6 @@ snapshots: human-signals@5.0.0: {} - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - ignore-walk@5.0.1: dependencies: minimatch: 5.1.6 @@ -8713,7 +6733,8 @@ snapshots: ignore@5.3.1: {} - immutable@4.3.4: {} + immutable@4.3.4: + optional: true import-fresh@3.3.0: dependencies: @@ -8737,32 +6758,17 @@ snapshots: ini@1.3.8: {} - inline-style-parser@0.1.1: {} - internal-slot@1.0.7: dependencies: es-errors: 1.3.0 hasown: 2.0.2 side-channel: 1.0.6 - internmap@1.0.1: {} - - internmap@2.0.3: {} - - intersection-observer@0.12.2: {} - into-stream@6.0.0: dependencies: from2: 2.3.0 p-is-promise: 3.0.0 - is-alphabetical@2.0.1: {} - - is-alphanumerical@2.0.1: - dependencies: - is-alphabetical: 2.0.1 - is-decimal: 2.0.1 - is-arguments@1.1.1: dependencies: call-bind: 1.0.7 @@ -8792,8 +6798,6 @@ snapshots: call-bind: 1.0.7 has-tostringtag: 1.0.2 - is-buffer@2.0.5: {} - is-callable@1.2.7: {} is-core-module@2.11.0: @@ -8812,10 +6816,6 @@ snapshots: dependencies: has-tostringtag: 1.0.2 - is-decimal@2.0.1: {} - - is-extendable@0.1.1: {} - is-extglob@2.1.1: {} is-finalizationregistry@1.0.2: @@ -8832,8 +6832,6 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-hexadecimal@2.0.1: {} - is-map@2.0.3: {} is-negative-zero@2.0.3: {} @@ -8846,24 +6844,14 @@ snapshots: is-obj@2.0.0: {} - is-obj@3.0.0: {} - is-path-cwd@2.2.0: {} is-path-inside@3.0.3: {} is-plain-obj@1.1.0: {} - is-plain-obj@3.0.0: {} - - is-plain-obj@4.1.0: {} - is-plain-object@5.0.0: {} - is-reference@3.0.2: - dependencies: - '@types/estree': 1.0.5 - is-regex@1.1.4: dependencies: call-bind: 1.0.7 @@ -8875,10 +6863,6 @@ snapshots: dependencies: call-bind: 1.0.7 - is-ssh@1.4.0: - dependencies: - protocols: 2.0.1 - is-stream@1.1.0: {} is-stream@2.0.1: {} @@ -8944,17 +6928,10 @@ snapshots: java-properties@1.0.2: {} - jiti@1.21.0: {} - joycon@3.1.1: {} js-tokens@4.0.0: {} - js-yaml@3.14.1: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - js-yaml@4.1.0: dependencies: argparse: 2.0.1 @@ -8979,8 +6956,6 @@ snapshots: json5@2.2.3: {} - jsonc-parser@3.2.0: {} - jsonfile@6.1.0: dependencies: universalify: 2.0.0 @@ -8996,33 +6971,19 @@ snapshots: object.assign: 4.1.5 object.values: 1.2.0 - katex@0.16.9: - dependencies: - commander: 8.3.0 - - khroma@2.1.0: {} - kind-of@6.0.3: {} - kleur@4.1.5: {} - language-subtag-registry@0.3.23: {} language-tags@1.0.9: dependencies: language-subtag-registry: 0.3.23 - layout-base@1.0.2: {} - - layout-base@2.0.1: {} - levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - lilconfig@2.1.0: {} - lilconfig@3.0.0: {} lines-and-columns@1.2.4: {} @@ -9061,8 +7022,6 @@ snapshots: lodash.escaperegexp@4.1.2: {} - lodash.get@4.4.2: {} - lodash.ismatch@4.4.0: {} lodash.isplainobject@4.0.6: {} @@ -9077,8 +7036,6 @@ snapshots: lodash@4.17.21: {} - longest-streak@3.1.0: {} - loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -9110,543 +7067,49 @@ snapshots: map-obj@1.0.1: {} - map-obj@4.3.0: {} - - markdown-extensions@1.1.1: {} - - markdown-table@3.0.3: {} - - marked-terminal@5.1.1(marked@4.2.12): - dependencies: - ansi-escapes: 5.0.0 - cardinal: 2.1.1 - chalk: 5.2.0 - cli-table3: 0.6.3 - marked: 4.2.12 - node-emoji: 1.11.0 - supports-hyperlinks: 2.3.0 - - marked-terminal@6.2.0(marked@9.1.6): - dependencies: - ansi-escapes: 6.2.1 - cardinal: 2.1.1 - chalk: 5.3.0 - cli-table3: 0.6.3 - marked: 9.1.6 - node-emoji: 2.1.3 - supports-hyperlinks: 3.0.0 - - marked@4.2.12: {} - - marked@9.1.6: {} - - match-sorter@6.3.1: - dependencies: - '@babel/runtime': 7.23.2 - remove-accents: 0.4.2 - - mdast-util-definitions@5.1.2: - dependencies: - '@types/mdast': 3.0.15 - '@types/unist': 2.0.10 - unist-util-visit: 4.1.2 - - mdast-util-find-and-replace@2.2.2: - dependencies: - '@types/mdast': 3.0.15 - escape-string-regexp: 5.0.0 - unist-util-is: 5.2.1 - unist-util-visit-parents: 5.1.3 - - mdast-util-from-markdown@1.3.1: - dependencies: - '@types/mdast': 3.0.15 - '@types/unist': 2.0.10 - decode-named-character-reference: 1.0.2 - mdast-util-to-string: 3.2.0 - micromark: 3.2.0 - micromark-util-decode-numeric-character-reference: 1.1.0 - micromark-util-decode-string: 1.1.0 - micromark-util-normalize-identifier: 1.1.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - unist-util-stringify-position: 3.0.3 - uvu: 0.5.6 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-autolink-literal@1.0.3: - dependencies: - '@types/mdast': 3.0.15 - ccount: 2.0.1 - mdast-util-find-and-replace: 2.2.2 - micromark-util-character: 1.2.0 - - mdast-util-gfm-footnote@1.0.2: - dependencies: - '@types/mdast': 3.0.15 - mdast-util-to-markdown: 1.5.0 - micromark-util-normalize-identifier: 1.1.0 - - mdast-util-gfm-strikethrough@1.0.3: - dependencies: - '@types/mdast': 3.0.15 - mdast-util-to-markdown: 1.5.0 - - mdast-util-gfm-table@1.0.7: - dependencies: - '@types/mdast': 3.0.15 - markdown-table: 3.0.3 - mdast-util-from-markdown: 1.3.1 - mdast-util-to-markdown: 1.5.0 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-task-list-item@1.0.2: - dependencies: - '@types/mdast': 3.0.15 - mdast-util-to-markdown: 1.5.0 - - mdast-util-gfm@2.0.2: - dependencies: - mdast-util-from-markdown: 1.3.1 - mdast-util-gfm-autolink-literal: 1.0.3 - mdast-util-gfm-footnote: 1.0.2 - mdast-util-gfm-strikethrough: 1.0.3 - mdast-util-gfm-table: 1.0.7 - mdast-util-gfm-task-list-item: 1.0.2 - mdast-util-to-markdown: 1.5.0 - transitivePeerDependencies: - - supports-color - - mdast-util-math@2.0.2: - dependencies: - '@types/mdast': 3.0.15 - longest-streak: 3.1.0 - mdast-util-to-markdown: 1.5.0 - - mdast-util-mdx-expression@1.3.2: - dependencies: - '@types/estree-jsx': 1.0.3 - '@types/hast': 2.3.8 - '@types/mdast': 3.0.15 - mdast-util-from-markdown: 1.3.1 - mdast-util-to-markdown: 1.5.0 - transitivePeerDependencies: - - supports-color - - mdast-util-mdx-jsx@2.1.4: - dependencies: - '@types/estree-jsx': 1.0.3 - '@types/hast': 2.3.8 - '@types/mdast': 3.0.15 - '@types/unist': 2.0.10 - ccount: 2.0.1 - mdast-util-from-markdown: 1.3.1 - mdast-util-to-markdown: 1.5.0 - parse-entities: 4.0.1 - stringify-entities: 4.0.3 - unist-util-remove-position: 4.0.2 - unist-util-stringify-position: 3.0.3 - vfile-message: 3.1.4 - transitivePeerDependencies: - - supports-color - - mdast-util-mdx@2.0.1: - dependencies: - mdast-util-from-markdown: 1.3.1 - mdast-util-mdx-expression: 1.3.2 - mdast-util-mdx-jsx: 2.1.4 - mdast-util-mdxjs-esm: 1.3.1 - mdast-util-to-markdown: 1.5.0 - transitivePeerDependencies: - - supports-color - - mdast-util-mdxjs-esm@1.3.1: - dependencies: - '@types/estree-jsx': 1.0.3 - '@types/hast': 2.3.8 - '@types/mdast': 3.0.15 - mdast-util-from-markdown: 1.3.1 - mdast-util-to-markdown: 1.5.0 - transitivePeerDependencies: - - supports-color - - mdast-util-phrasing@3.0.1: - dependencies: - '@types/mdast': 3.0.15 - unist-util-is: 5.2.1 - - mdast-util-to-hast@12.3.0: - dependencies: - '@types/hast': 2.3.8 - '@types/mdast': 3.0.15 - mdast-util-definitions: 5.1.2 - micromark-util-sanitize-uri: 1.2.0 - trim-lines: 3.0.1 - unist-util-generated: 2.0.1 - unist-util-position: 4.0.4 - unist-util-visit: 4.1.2 - - mdast-util-to-hast@13.0.2: - dependencies: - '@types/hast': 3.0.3 - '@types/mdast': 4.0.3 - '@ungap/structured-clone': 1.2.0 - devlop: 1.1.0 - micromark-util-sanitize-uri: 2.0.0 - trim-lines: 3.0.1 - unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 - - mdast-util-to-markdown@1.5.0: - dependencies: - '@types/mdast': 3.0.15 - '@types/unist': 2.0.10 - longest-streak: 3.1.0 - mdast-util-phrasing: 3.0.1 - mdast-util-to-string: 3.2.0 - micromark-util-decode-string: 1.1.0 - unist-util-visit: 4.1.2 - zwitch: 2.0.4 - - mdast-util-to-string@3.2.0: - dependencies: - '@types/mdast': 3.0.15 - - meow@8.1.2: - dependencies: - '@types/minimist': 1.2.2 - camelcase-keys: 6.2.2 - decamelize-keys: 1.1.1 - hard-rejection: 2.1.0 - minimist-options: 4.1.0 - normalize-package-data: 3.0.3 - read-pkg-up: 7.0.1 - redent: 3.0.0 - trim-newlines: 3.0.1 - type-fest: 0.18.1 - yargs-parser: 20.2.9 - - merge-stream@2.0.0: {} - - merge2@1.4.1: {} - - mermaid@10.6.1: - dependencies: - '@braintree/sanitize-url': 6.0.4 - '@types/d3-scale': 4.0.8 - '@types/d3-scale-chromatic': 3.0.3 - cytoscape: 3.28.0 - cytoscape-cose-bilkent: 4.1.0(cytoscape@3.28.0) - cytoscape-fcose: 2.2.0(cytoscape@3.28.0) - d3: 7.8.5 - d3-sankey: 0.12.3 - dagre-d3-es: 7.0.10 - dayjs: 1.11.10 - dompurify: 3.0.6 - elkjs: 0.8.2 - khroma: 2.1.0 - lodash-es: 4.17.21 - mdast-util-from-markdown: 1.3.1 - non-layered-tidy-tree-layout: 2.0.2 - stylis: 4.3.0 - ts-dedent: 2.2.0 - uuid: 9.0.1 - web-worker: 1.2.0 - transitivePeerDependencies: - - supports-color - - micromark-core-commonmark@1.1.0: - dependencies: - decode-named-character-reference: 1.0.2 - micromark-factory-destination: 1.1.0 - micromark-factory-label: 1.1.0 - micromark-factory-space: 1.1.0 - micromark-factory-title: 1.1.0 - micromark-factory-whitespace: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-chunked: 1.1.0 - micromark-util-classify-character: 1.1.0 - micromark-util-html-tag-name: 1.2.0 - micromark-util-normalize-identifier: 1.1.0 - micromark-util-resolve-all: 1.1.0 - micromark-util-subtokenize: 1.1.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - - micromark-extension-gfm-autolink-literal@1.0.5: - dependencies: - micromark-util-character: 1.2.0 - micromark-util-sanitize-uri: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - - micromark-extension-gfm-footnote@1.1.2: - dependencies: - micromark-core-commonmark: 1.1.0 - micromark-factory-space: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-normalize-identifier: 1.1.0 - micromark-util-sanitize-uri: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - - micromark-extension-gfm-strikethrough@1.0.7: - dependencies: - micromark-util-chunked: 1.1.0 - micromark-util-classify-character: 1.1.0 - micromark-util-resolve-all: 1.1.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - - micromark-extension-gfm-table@1.0.7: - dependencies: - micromark-factory-space: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - - micromark-extension-gfm-tagfilter@1.0.2: - dependencies: - micromark-util-types: 1.1.0 - - micromark-extension-gfm-task-list-item@1.0.5: - dependencies: - micromark-factory-space: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - - micromark-extension-gfm@2.0.3: - dependencies: - micromark-extension-gfm-autolink-literal: 1.0.5 - micromark-extension-gfm-footnote: 1.1.2 - micromark-extension-gfm-strikethrough: 1.0.7 - micromark-extension-gfm-table: 1.0.7 - micromark-extension-gfm-tagfilter: 1.0.2 - micromark-extension-gfm-task-list-item: 1.0.5 - micromark-util-combine-extensions: 1.1.0 - micromark-util-types: 1.1.0 - - micromark-extension-math@2.1.2: - dependencies: - '@types/katex': 0.16.7 - katex: 0.16.9 - micromark-factory-space: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - - micromark-extension-mdx-expression@1.0.8: - dependencies: - '@types/estree': 1.0.5 - micromark-factory-mdx-expression: 1.0.9 - micromark-factory-space: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-events-to-acorn: 1.2.3 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - - micromark-extension-mdx-jsx@1.0.5: - dependencies: - '@types/acorn': 4.0.6 - '@types/estree': 1.0.5 - estree-util-is-identifier-name: 2.1.0 - micromark-factory-mdx-expression: 1.0.9 - micromark-factory-space: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - vfile-message: 3.1.4 - - micromark-extension-mdx-md@1.0.1: - dependencies: - micromark-util-types: 1.1.0 - - micromark-extension-mdxjs-esm@1.0.5: - dependencies: - '@types/estree': 1.0.5 - micromark-core-commonmark: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-events-to-acorn: 1.2.3 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - unist-util-position-from-estree: 1.1.2 - uvu: 0.5.6 - vfile-message: 3.1.4 - - micromark-extension-mdxjs@1.0.1: - dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) - micromark-extension-mdx-expression: 1.0.8 - micromark-extension-mdx-jsx: 1.0.5 - micromark-extension-mdx-md: 1.0.1 - micromark-extension-mdxjs-esm: 1.0.5 - micromark-util-combine-extensions: 1.1.0 - micromark-util-types: 1.1.0 - - micromark-factory-destination@1.1.0: - dependencies: - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - - micromark-factory-label@1.1.0: - dependencies: - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - - micromark-factory-mdx-expression@1.0.9: - dependencies: - '@types/estree': 1.0.5 - micromark-util-character: 1.2.0 - micromark-util-events-to-acorn: 1.2.3 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - unist-util-position-from-estree: 1.1.2 - uvu: 0.5.6 - vfile-message: 3.1.4 - - micromark-factory-space@1.1.0: - dependencies: - micromark-util-character: 1.2.0 - micromark-util-types: 1.1.0 - - micromark-factory-title@1.1.0: - dependencies: - micromark-factory-space: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - - micromark-factory-whitespace@1.1.0: - dependencies: - micromark-factory-space: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - - micromark-util-character@1.2.0: - dependencies: - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - - micromark-util-character@2.0.1: - dependencies: - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 - - micromark-util-chunked@1.1.0: - dependencies: - micromark-util-symbol: 1.1.0 - - micromark-util-classify-character@1.1.0: - dependencies: - micromark-util-character: 1.2.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - - micromark-util-combine-extensions@1.1.0: - dependencies: - micromark-util-chunked: 1.1.0 - micromark-util-types: 1.1.0 - - micromark-util-decode-numeric-character-reference@1.1.0: - dependencies: - micromark-util-symbol: 1.1.0 - - micromark-util-decode-string@1.1.0: - dependencies: - decode-named-character-reference: 1.0.2 - micromark-util-character: 1.2.0 - micromark-util-decode-numeric-character-reference: 1.1.0 - micromark-util-symbol: 1.1.0 - - micromark-util-encode@1.1.0: {} - - micromark-util-encode@2.0.0: {} - - micromark-util-events-to-acorn@1.2.3: - dependencies: - '@types/acorn': 4.0.6 - '@types/estree': 1.0.5 - '@types/unist': 2.0.10 - estree-util-visit: 1.2.1 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - vfile-message: 3.1.4 - - micromark-util-html-tag-name@1.2.0: {} - - micromark-util-normalize-identifier@1.1.0: - dependencies: - micromark-util-symbol: 1.1.0 - - micromark-util-resolve-all@1.1.0: - dependencies: - micromark-util-types: 1.1.0 - - micromark-util-sanitize-uri@1.2.0: - dependencies: - micromark-util-character: 1.2.0 - micromark-util-encode: 1.1.0 - micromark-util-symbol: 1.1.0 + map-obj@4.3.0: {} - micromark-util-sanitize-uri@2.0.0: + marked-terminal@5.1.1(marked@4.2.12): dependencies: - micromark-util-character: 2.0.1 - micromark-util-encode: 2.0.0 - micromark-util-symbol: 2.0.0 + ansi-escapes: 5.0.0 + cardinal: 2.1.1 + chalk: 5.2.0 + cli-table3: 0.6.3 + marked: 4.2.12 + node-emoji: 1.11.0 + supports-hyperlinks: 2.3.0 - micromark-util-subtokenize@1.1.0: + marked-terminal@6.2.0(marked@9.1.6): dependencies: - micromark-util-chunked: 1.1.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 + ansi-escapes: 6.2.1 + cardinal: 2.1.1 + chalk: 5.3.0 + cli-table3: 0.6.3 + marked: 9.1.6 + node-emoji: 2.1.3 + supports-hyperlinks: 3.0.0 - micromark-util-symbol@1.1.0: {} + marked@4.2.12: {} - micromark-util-symbol@2.0.0: {} + marked@9.1.6: {} - micromark-util-types@1.1.0: {} + meow@8.1.2: + dependencies: + '@types/minimist': 1.2.2 + camelcase-keys: 6.2.2 + decamelize-keys: 1.1.1 + hard-rejection: 2.1.0 + minimist-options: 4.1.0 + normalize-package-data: 3.0.3 + read-pkg-up: 7.0.1 + redent: 3.0.0 + trim-newlines: 3.0.1 + type-fest: 0.18.1 + yargs-parser: 20.2.9 - micromark-util-types@2.0.0: {} + merge-stream@2.0.0: {} - micromark@3.2.0: - dependencies: - '@types/debug': 4.1.12 - debug: 4.3.6 - decode-named-character-reference: 1.0.2 - micromark-core-commonmark: 1.1.0 - micromark-factory-space: 1.1.0 - micromark-util-character: 1.2.0 - micromark-util-chunked: 1.1.0 - micromark-util-combine-extensions: 1.1.0 - micromark-util-decode-numeric-character-reference: 1.1.0 - micromark-util-encode: 1.1.0 - micromark-util-normalize-identifier: 1.1.0 - micromark-util-resolve-all: 1.1.0 - micromark-util-sanitize-uri: 1.2.0 - micromark-util-subtokenize: 1.1.0 - micromark-util-symbol: 1.1.0 - micromark-util-types: 1.1.0 - uvu: 0.5.6 - transitivePeerDependencies: - - supports-color + merge2@1.4.1: {} micromatch@4.0.5: dependencies: @@ -9709,110 +7172,6 @@ snapshots: nerf-dart@1.0.0: {} - next-mdx-remote@4.4.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): - dependencies: - '@mdx-js/mdx': 2.3.0 - '@mdx-js/react': 2.3.0(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - vfile: 5.3.7 - vfile-matter: 3.0.1 - transitivePeerDependencies: - - supports-color - - next-seo@6.4.0(next@14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): - dependencies: - next: 14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - - next-themes@0.2.1(next@14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): - dependencies: - next: 14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - - next@14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7): - dependencies: - '@next/env': 14.0.4 - '@swc/helpers': 0.5.2 - busboy: 1.6.0 - caniuse-lite: 1.0.30001576 - graceful-fs: 4.2.11 - postcss: 8.4.31 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.1.1(@babel/core@7.20.12)(react@18.2.0) - watchpack: 2.4.0 - optionalDependencies: - '@next/swc-darwin-arm64': 14.0.4 - '@next/swc-darwin-x64': 14.0.4 - '@next/swc-linux-arm64-gnu': 14.0.4 - '@next/swc-linux-arm64-musl': 14.0.4 - '@next/swc-linux-x64-gnu': 14.0.4 - '@next/swc-linux-x64-musl': 14.0.4 - '@next/swc-win32-arm64-msvc': 14.0.4 - '@next/swc-win32-ia32-msvc': 14.0.4 - '@next/swc-win32-x64-msvc': 14.0.4 - sass: 1.69.7 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - - nextra-theme-docs@2.13.2(next@14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7))(nextra@2.13.2(next@14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): - dependencies: - '@headlessui/react': 1.7.17(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@popperjs/core': 2.11.8 - clsx: 2.0.0 - escape-string-regexp: 5.0.0 - flexsearch: 0.7.31 - focus-visible: 5.2.0 - git-url-parse: 13.1.1 - intersection-observer: 0.12.2 - match-sorter: 6.3.1 - next: 14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7) - next-seo: 6.4.0(next@14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - next-themes: 0.2.1(next@14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - nextra: 2.13.2(next@14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - scroll-into-view-if-needed: 3.1.0 - zod: 3.22.4 - - nextra@2.13.2(next@14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): - dependencies: - '@headlessui/react': 1.7.17(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@mdx-js/mdx': 2.3.0 - '@mdx-js/react': 2.3.0(react@18.2.0) - '@napi-rs/simple-git': 0.1.9 - '@theguild/remark-mermaid': 0.0.5(react@18.2.0) - '@theguild/remark-npm2yarn': 0.2.1 - clsx: 2.0.0 - github-slugger: 2.0.0 - graceful-fs: 4.2.11 - gray-matter: 4.0.3 - katex: 0.16.9 - lodash.get: 4.4.2 - next: 14.0.4(@babel/core@7.20.12)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.69.7) - next-mdx-remote: 4.4.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - p-limit: 3.1.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - rehype-katex: 7.0.0 - rehype-pretty-code: 0.9.11(shiki@0.14.6) - rehype-raw: 7.0.0 - remark-gfm: 3.0.1 - remark-math: 5.1.1 - remark-reading-time: 2.0.1 - shiki: 0.14.6 - slash: 3.0.0 - title: 3.5.3 - unist-util-remove: 4.0.0 - unist-util-visit: 5.0.0 - zod: 3.22.4 - transitivePeerDependencies: - - supports-color - node-emoji@1.11.0: dependencies: lodash: 4.17.21 @@ -9830,8 +7189,6 @@ snapshots: node-releases@2.0.14: {} - non-layered-tidy-tree-layout@2.0.2: {} - normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 @@ -9848,8 +7205,6 @@ snapshots: normalize-path@3.0.0: {} - normalize-range@0.1.2: {} - normalize-url@6.1.0: {} npm-bundled@2.0.1: @@ -9877,14 +7232,10 @@ snapshots: dependencies: path-key: 4.0.0 - npm-to-yarn@2.1.0: {} - npm@8.19.3: {} object-assign@4.1.1: {} - object-hash@3.0.0: {} - object-inspect@1.13.2: {} object-is@1.1.6: @@ -10018,17 +7369,6 @@ snapshots: dependencies: callsites: 3.1.0 - parse-entities@4.0.1: - dependencies: - '@types/unist': 2.0.10 - character-entities: 2.0.2 - character-entities-legacy: 3.0.0 - character-reference-invalid: 2.0.1 - decode-named-character-reference: 1.0.2 - is-alphanumerical: 2.0.1 - is-decimal: 2.0.1 - is-hexadecimal: 2.0.1 - parse-json@4.0.0: dependencies: error-ex: 1.3.2 @@ -10041,20 +7381,6 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - parse-numeric-range@1.3.0: {} - - parse-path@7.0.0: - dependencies: - protocols: 2.0.1 - - parse-url@8.1.0: - dependencies: - parse-path: 7.0.0 - - parse5@7.1.2: - dependencies: - entities: 4.5.0 - path-exists@3.0.0: {} path-exists@4.0.0: {} @@ -10082,20 +7408,12 @@ snapshots: pathval@2.0.0: {} - periscopic@3.1.0: - dependencies: - '@types/estree': 1.0.5 - estree-walker: 3.0.3 - is-reference: 3.0.2 - picocolors@1.0.0: {} picocolors@1.0.1: {} picomatch@2.3.1: {} - pify@2.3.0: {} - pify@3.0.0: {} pirates@4.0.5: {} @@ -10111,18 +7429,6 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-import@15.1.0(postcss@8.4.33): - dependencies: - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.8 - - postcss-js@4.0.1(postcss@8.4.33): - dependencies: - camelcase-css: 2.0.1 - postcss: 8.4.33 - postcss-load-config@4.0.2(postcss@8.4.33): dependencies: lilconfig: 3.0.0 @@ -10130,24 +7436,6 @@ snapshots: optionalDependencies: postcss: 8.4.33 - postcss-nested@6.0.1(postcss@8.4.33): - dependencies: - postcss: 8.4.33 - postcss-selector-parser: 6.0.15 - - postcss-selector-parser@6.0.15: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - - postcss-value-parser@4.2.0: {} - - postcss@8.4.31: - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.0.2 - postcss@8.4.33: dependencies: nanoid: 3.3.7 @@ -10166,12 +7454,8 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 - property-information@6.4.0: {} - proto-list@1.2.4: {} - protocols@2.0.1: {} - pseudomap@1.0.2: {} publint@0.2.9: @@ -10197,22 +7481,8 @@ snapshots: minimist: 1.2.7 strip-json-comments: 2.0.1 - react-dom@18.2.0(react@18.2.0): - dependencies: - loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.23.0 - react-is@16.13.1: {} - react@18.2.0: - dependencies: - loose-envify: 1.4.0 - - read-cache@1.0.0: - dependencies: - pify: 2.3.0 - read-pkg-up@7.0.1: dependencies: find-up: 4.1.0 @@ -10259,8 +7529,6 @@ snapshots: dependencies: picomatch: 2.3.1 - reading-time@1.5.0: {} - redent@3.0.0: dependencies: indent-string: 4.0.0 @@ -10322,76 +7590,6 @@ snapshots: dependencies: jsesc: 0.5.0 - rehype-katex@7.0.0: - dependencies: - '@types/hast': 3.0.3 - '@types/katex': 0.16.7 - hast-util-from-html-isomorphic: 2.0.0 - hast-util-to-text: 4.0.0 - katex: 0.16.9 - unist-util-visit-parents: 6.0.1 - vfile: 6.0.1 - - rehype-pretty-code@0.9.11(shiki@0.14.6): - dependencies: - '@types/hast': 2.3.8 - hash-obj: 4.0.0 - parse-numeric-range: 1.3.0 - shiki: 0.14.6 - - rehype-raw@7.0.0: - dependencies: - '@types/hast': 3.0.3 - hast-util-raw: 9.0.1 - vfile: 6.0.1 - - remark-gfm@3.0.1: - dependencies: - '@types/mdast': 3.0.15 - mdast-util-gfm: 2.0.2 - micromark-extension-gfm: 2.0.3 - unified: 10.1.2 - transitivePeerDependencies: - - supports-color - - remark-math@5.1.1: - dependencies: - '@types/mdast': 3.0.15 - mdast-util-math: 2.0.2 - micromark-extension-math: 2.1.2 - unified: 10.1.2 - - remark-mdx@2.3.0: - dependencies: - mdast-util-mdx: 2.0.1 - micromark-extension-mdxjs: 1.0.1 - transitivePeerDependencies: - - supports-color - - remark-parse@10.0.2: - dependencies: - '@types/mdast': 3.0.15 - mdast-util-from-markdown: 1.3.1 - unified: 10.1.2 - transitivePeerDependencies: - - supports-color - - remark-reading-time@2.0.1: - dependencies: - estree-util-is-identifier-name: 2.1.0 - estree-util-value-to-estree: 1.3.0 - reading-time: 1.5.0 - unist-util-visit: 3.1.0 - - remark-rehype@10.1.0: - dependencies: - '@types/hast': 2.3.8 - '@types/mdast': 3.0.15 - mdast-util-to-hast: 12.3.0 - unified: 10.1.2 - - remove-accents@0.4.2: {} - require-directory@2.1.1: {} resolve-from@4.0.0: {} @@ -10420,8 +7618,6 @@ snapshots: dependencies: glob: 7.2.3 - robust-predicates@3.0.2: {} - rollup@4.9.0: optionalDependencies: '@rollup/rollup-android-arm-eabi': 4.9.0 @@ -10443,8 +7639,6 @@ snapshots: dependencies: queue-microtask: 1.2.3 - rw@1.3.3: {} - sade@1.8.1: dependencies: mri: 1.2.0 @@ -10466,26 +7660,12 @@ snapshots: es-errors: 1.3.0 is-regex: 1.1.4 - safer-buffer@2.1.2: {} - sass@1.69.7: dependencies: chokidar: 3.5.3 immutable: 4.3.4 source-map-js: 1.0.2 - - scheduler@0.23.0: - dependencies: - loose-envify: 1.4.0 - - scroll-into-view-if-needed@3.1.0: - dependencies: - compute-scroll-into-view: 3.1.0 - - section-matter@1.0.0: - dependencies: - extend-shallow: 2.0.1 - kind-of: 6.0.3 + optional: true semantic-release-monorepo@7.0.5(semantic-release@20.1.0): dependencies: @@ -10582,13 +7762,6 @@ snapshots: shebang-regex@3.0.0: {} - shiki@0.14.6: - dependencies: - ansi-sequence-parser: 1.1.1 - jsonc-parser: 3.2.0 - vscode-oniguruma: 1.7.0 - vscode-textmate: 8.0.0 - side-channel@1.0.6: dependencies: call-bind: 1.0.7 @@ -10614,22 +7787,14 @@ snapshots: slash@3.0.0: {} - sort-keys@5.0.0: - dependencies: - is-plain-obj: 4.1.0 - source-map-js@1.0.2: {} source-map@0.6.1: {} - source-map@0.7.4: {} - source-map@0.8.0-beta.0: dependencies: whatwg-url: 7.1.0 - space-separated-tokens@2.0.2: {} - spawn-error-forwarder@1.0.0: {} spdx-correct@3.1.1: @@ -10658,8 +7823,6 @@ snapshots: dependencies: through: 2.3.8 - sprintf-js@1.0.3: {} - stackback@0.0.2: {} std-env@3.7.0: {} @@ -10673,8 +7836,6 @@ snapshots: duplexer2: 0.1.4 readable-stream: 2.3.7 - streamsearch@1.1.0: {} - string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -10734,11 +7895,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - stringify-entities@4.0.3: - dependencies: - character-entities-html4: 2.1.0 - character-entities-legacy: 3.0.0 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -10747,8 +7903,6 @@ snapshots: dependencies: ansi-regex: 6.0.1 - strip-bom-string@1.0.0: {} - strip-bom@3.0.0: {} strip-eof@1.0.0: {} @@ -10765,19 +7919,6 @@ snapshots: strip-json-comments@3.1.1: {} - style-to-object@0.4.4: - dependencies: - inline-style-parser: 0.1.1 - - styled-jsx@5.1.1(@babel/core@7.20.12)(react@18.2.0): - dependencies: - client-only: 0.0.1 - react: 18.2.0 - optionalDependencies: - '@babel/core': 7.20.12 - - stylis@4.3.0: {} - sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.2 @@ -10788,10 +7929,6 @@ snapshots: pirates: 4.0.5 ts-interface-checker: 0.1.13 - supports-color@4.5.0: - dependencies: - has-flag: 2.0.0 - supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -10812,33 +7949,6 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - tailwindcss@3.4.1: - dependencies: - '@alloc/quick-lru': 5.2.0 - arg: 5.0.2 - chokidar: 3.5.3 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.3.2 - glob-parent: 6.0.2 - is-glob: 4.0.3 - jiti: 1.21.0 - lilconfig: 2.1.0 - micromatch: 4.0.5 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.0.0 - postcss: 8.4.33 - postcss-import: 15.1.0(postcss@8.4.33) - postcss-js: 4.0.1(postcss@8.4.33) - postcss-load-config: 4.0.2(postcss@8.4.33) - postcss-nested: 6.0.1(postcss@8.4.33) - postcss-selector-parser: 6.0.15 - resolve: 1.22.8 - sucrase: 3.35.0 - transitivePeerDependencies: - - ts-node - tapable@2.2.1: {} temp-dir@2.0.0: {} @@ -10882,15 +7992,6 @@ snapshots: tinyspy@3.0.0: {} - title@3.5.3: - dependencies: - arg: 1.0.0 - chalk: 2.3.0 - clipboardy: 1.2.2 - titleize: 1.0.0 - - titleize@1.0.0: {} - to-fast-properties@2.0.0: {} to-regex-range@5.0.1: @@ -10907,18 +8008,12 @@ snapshots: tree-kill@1.2.2: {} - trim-lines@3.0.1: {} - trim-newlines@3.0.1: {} - trough@2.1.0: {} - ts-api-utils@1.3.0(typescript@5.5.2): dependencies: typescript: 5.5.2 - ts-dedent@2.2.0: {} - ts-expose-internals-conditionally@1.0.0-empty.0: {} ts-interface-checker@0.1.13: {} @@ -10930,8 +8025,6 @@ snapshots: minimist: 1.2.7 strip-bom: 3.0.0 - tslib@2.4.1: {} - tsup@8.1.0(postcss@8.4.33)(typescript@5.5.2): dependencies: bundle-require: 4.0.2(esbuild@0.21.5) @@ -11053,7 +8146,8 @@ snapshots: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - undici-types@5.26.5: {} + undici-types@5.26.5: + optional: true unicode-canonical-property-names-ecmascript@2.0.0: {} @@ -11068,104 +8162,10 @@ snapshots: unicode-property-aliases-ecmascript@2.1.0: {} - unified@10.1.2: - dependencies: - '@types/unist': 2.0.10 - bail: 2.0.2 - extend: 3.0.2 - is-buffer: 2.0.5 - is-plain-obj: 4.1.0 - trough: 2.1.0 - vfile: 5.3.7 - unique-string@2.0.0: dependencies: crypto-random-string: 2.0.0 - unist-util-find-after@5.0.0: - dependencies: - '@types/unist': 3.0.2 - unist-util-is: 6.0.0 - - unist-util-generated@2.0.1: {} - - unist-util-is@5.2.1: - dependencies: - '@types/unist': 2.0.10 - - unist-util-is@6.0.0: - dependencies: - '@types/unist': 3.0.2 - - unist-util-position-from-estree@1.1.2: - dependencies: - '@types/unist': 2.0.10 - - unist-util-position@4.0.4: - dependencies: - '@types/unist': 2.0.10 - - unist-util-position@5.0.0: - dependencies: - '@types/unist': 3.0.2 - - unist-util-remove-position@4.0.2: - dependencies: - '@types/unist': 2.0.10 - unist-util-visit: 4.1.2 - - unist-util-remove-position@5.0.0: - dependencies: - '@types/unist': 3.0.2 - unist-util-visit: 5.0.0 - - unist-util-remove@4.0.0: - dependencies: - '@types/unist': 3.0.2 - unist-util-is: 6.0.0 - unist-util-visit-parents: 6.0.1 - - unist-util-stringify-position@3.0.3: - dependencies: - '@types/unist': 2.0.10 - - unist-util-stringify-position@4.0.0: - dependencies: - '@types/unist': 3.0.2 - - unist-util-visit-parents@4.1.1: - dependencies: - '@types/unist': 2.0.10 - unist-util-is: 5.2.1 - - unist-util-visit-parents@5.1.3: - dependencies: - '@types/unist': 2.0.10 - unist-util-is: 5.2.1 - - unist-util-visit-parents@6.0.1: - dependencies: - '@types/unist': 3.0.2 - unist-util-is: 6.0.0 - - unist-util-visit@3.1.0: - dependencies: - '@types/unist': 2.0.10 - unist-util-is: 5.2.1 - unist-util-visit-parents: 4.1.1 - - unist-util-visit@4.1.2: - dependencies: - '@types/unist': 2.0.10 - unist-util-is: 5.2.1 - unist-util-visit-parents: 5.1.3 - - unist-util-visit@5.0.0: - dependencies: - '@types/unist': 3.0.2 - unist-util-is: 6.0.0 - unist-util-visit-parents: 6.0.1 - universal-user-agent@6.0.0: {} universalify@2.0.0: {} @@ -11184,15 +8184,6 @@ snapshots: util-deprecate@1.0.2: {} - uuid@9.0.1: {} - - uvu@0.5.6: - dependencies: - dequal: 2.0.3 - diff: 5.1.0 - kleur: 4.1.5 - sade: 1.8.1 - validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.1.1 @@ -11200,40 +8191,6 @@ snapshots: validate-npm-package-name@5.0.1: {} - vfile-location@5.0.2: - dependencies: - '@types/unist': 3.0.2 - vfile: 6.0.1 - - vfile-matter@3.0.1: - dependencies: - '@types/js-yaml': 4.0.9 - is-buffer: 2.0.5 - js-yaml: 4.1.0 - - vfile-message@3.1.4: - dependencies: - '@types/unist': 2.0.10 - unist-util-stringify-position: 3.0.3 - - vfile-message@4.0.2: - dependencies: - '@types/unist': 3.0.2 - unist-util-stringify-position: 4.0.0 - - vfile@5.3.7: - dependencies: - '@types/unist': 2.0.10 - is-buffer: 2.0.5 - unist-util-stringify-position: 3.0.3 - vfile-message: 3.1.4 - - vfile@6.0.1: - dependencies: - '@types/unist': 3.0.2 - unist-util-stringify-position: 4.0.0 - vfile-message: 4.0.2 - vite-node@2.0.5(@types/node@20.10.8)(sass@1.69.7): dependencies: cac: 6.7.14 @@ -11293,19 +8250,6 @@ snapshots: - supports-color - terser - vscode-oniguruma@1.7.0: {} - - vscode-textmate@8.0.0: {} - - watchpack@2.4.0: - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - - web-namespaces@2.0.1: {} - - web-worker@1.2.0: {} - webidl-conversions@3.0.1: {} webidl-conversions@4.0.2: {} @@ -11419,11 +8363,3 @@ snapshots: yocto-queue@0.1.0: {} yocto-queue@1.0.0: {} - - zod-to-json-schema@3.22.3(zod@3.22.4): - dependencies: - zod: 3.22.4 - - zod@3.22.4: {} - - zwitch@2.0.4: {} From b122ab2f003751d786ddca3263a5b1e04e2ed1e3 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Oct 2024 19:03:00 +0000 Subject: [PATCH 17/21] chore(release): 6.0.0-beta.6 [skip ci] # [@cloudinary-util/url-loader-v6.0.0-beta.6](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.5...@cloudinary-util/url-loader-v6.0.0-beta.6) (2024-10-31) ### Bug Fixes * remove applyWhen in favor of explicit props overlap check with alwaysApply exception ([#228](https://github.com/cloudinary-community/cloudinary-util/issues/228)) ([90d07c2](https://github.com/cloudinary-community/cloudinary-util/commit/90d07c2a302a628e6c6e0352d479608131d45d65)) --- packages/url-loader/CHANGELOG.md | 7 +++++++ packages/url-loader/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/url-loader/CHANGELOG.md b/packages/url-loader/CHANGELOG.md index b8e22582..a6bde1ea 100644 --- a/packages/url-loader/CHANGELOG.md +++ b/packages/url-loader/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cloudinary-util/url-loader-v6.0.0-beta.6](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.5...@cloudinary-util/url-loader-v6.0.0-beta.6) (2024-10-31) + + +### Bug Fixes + +* remove applyWhen in favor of explicit props overlap check with alwaysApply exception ([#228](https://github.com/cloudinary-community/cloudinary-util/issues/228)) ([90d07c2](https://github.com/cloudinary-community/cloudinary-util/commit/90d07c2a302a628e6c6e0352d479608131d45d65)) + # [@cloudinary-util/url-loader-v6.0.0-beta.5](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.4...@cloudinary-util/url-loader-v6.0.0-beta.5) (2024-10-31) ### Bug Fixes diff --git a/packages/url-loader/package.json b/packages/url-loader/package.json index 6e687f4f..762f043f 100644 --- a/packages/url-loader/package.json +++ b/packages/url-loader/package.json @@ -1,6 +1,6 @@ { "name": "@cloudinary-util/url-loader", - "version": "6.0.0-beta.5", + "version": "6.0.0-beta.6", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", From 6f321c1ff9f764cef6b7e8393060ad468e0f7c48 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Oct 2024 19:03:28 +0000 Subject: [PATCH 18/21] chore(release): 2.0.0-beta.3 [skip ci] # [@cloudinary-util/types-v2.0.0-beta.3](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v2.0.0-beta.2...@cloudinary-util/types-v2.0.0-beta.3) (2024-10-31) ### Bug Fixes * remove applyWhen in favor of explicit props overlap check with alwaysApply exception ([#228](https://github.com/cloudinary-community/cloudinary-util/issues/228)) ([90d07c2](https://github.com/cloudinary-community/cloudinary-util/commit/90d07c2a302a628e6c6e0352d479608131d45d65)) --- packages/types/CHANGELOG.md | 7 +++++++ packages/types/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 7d044d01..b2bc5fc4 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cloudinary-util/types-v2.0.0-beta.3](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v2.0.0-beta.2...@cloudinary-util/types-v2.0.0-beta.3) (2024-10-31) + + +### Bug Fixes + +* remove applyWhen in favor of explicit props overlap check with alwaysApply exception ([#228](https://github.com/cloudinary-community/cloudinary-util/issues/228)) ([90d07c2](https://github.com/cloudinary-community/cloudinary-util/commit/90d07c2a302a628e6c6e0352d479608131d45d65)) + # [@cloudinary-util/types-v2.0.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v2.0.0-beta.1...@cloudinary-util/types-v2.0.0-beta.2) (2024-10-22) ### Bug Fixes diff --git a/packages/types/package.json b/packages/types/package.json index e8ce96b8..3b5f081c 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@cloudinary-util/types", - "version": "2.0.0-beta.2", + "version": "2.0.0-beta.3", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", From 4f02f798a39c8e5081b1738ddb38f30aa36afca1 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Oct 2024 19:03:48 +0000 Subject: [PATCH 19/21] chore(release): 5.0.0-beta.2 [skip ci] # [@cloudinary-util/util-v5.0.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v5.0.0-beta.1...@cloudinary-util/util-v5.0.0-beta.2) (2024-10-31) ### Bug Fixes * remove applyWhen in favor of explicit props overlap check with alwaysApply exception ([#228](https://github.com/cloudinary-community/cloudinary-util/issues/228)) ([90d07c2](https://github.com/cloudinary-community/cloudinary-util/commit/90d07c2a302a628e6c6e0352d479608131d45d65)) --- packages/util/CHANGELOG.md | 7 +++++++ packages/util/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/util/CHANGELOG.md b/packages/util/CHANGELOG.md index ef19c468..c9590d54 100644 --- a/packages/util/CHANGELOG.md +++ b/packages/util/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cloudinary-util/util-v5.0.0-beta.2](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v5.0.0-beta.1...@cloudinary-util/util-v5.0.0-beta.2) (2024-10-31) + + +### Bug Fixes + +* remove applyWhen in favor of explicit props overlap check with alwaysApply exception ([#228](https://github.com/cloudinary-community/cloudinary-util/issues/228)) ([90d07c2](https://github.com/cloudinary-community/cloudinary-util/commit/90d07c2a302a628e6c6e0352d479608131d45d65)) + # [@cloudinary-util/util-v5.0.0-beta.1](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/util-v4.0.0...@cloudinary-util/util-v5.0.0-beta.1) (2024-10-18) ### Features diff --git a/packages/util/package.json b/packages/util/package.json index 1e21ea38..75e96705 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@cloudinary-util/util", - "version": "5.0.0-beta.1", + "version": "5.0.0-beta.2", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", From b6a5563e3d35c79eac953468697cb66f01b1879d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 31 Oct 2024 20:58:26 +0100 Subject: [PATCH 20/21] fix: make all individual plugin declarations tree-shakeable (#229) similar to https://github.com/cloudinary-community/cloudinary-util/pull/227 --- packages/url-loader/src/plugins/abr.ts | 2 +- packages/url-loader/src/plugins/cropping.ts | 2 +- packages/url-loader/src/plugins/default-image.ts | 2 +- packages/url-loader/src/plugins/effects.ts | 2 +- packages/url-loader/src/plugins/enhance.ts | 2 +- packages/url-loader/src/plugins/extract.ts | 2 +- packages/url-loader/src/plugins/fill-background.ts | 2 +- packages/url-loader/src/plugins/flags.ts | 2 +- packages/url-loader/src/plugins/named-transformations.ts | 2 +- packages/url-loader/src/plugins/overlays.ts | 2 +- packages/url-loader/src/plugins/preserve-transformations.ts | 2 +- packages/url-loader/src/plugins/raw-transformations.ts | 2 +- packages/url-loader/src/plugins/recolor.ts | 2 +- packages/url-loader/src/plugins/remove-background.ts | 2 +- packages/url-loader/src/plugins/remove.ts | 2 +- packages/url-loader/src/plugins/replace-background.ts | 2 +- packages/url-loader/src/plugins/replace.ts | 2 +- packages/url-loader/src/plugins/restore.ts | 2 +- packages/url-loader/src/plugins/sanitize.ts | 2 +- packages/url-loader/src/plugins/seo.ts | 2 +- packages/url-loader/src/plugins/underlays.ts | 2 +- packages/url-loader/src/plugins/version.ts | 2 +- packages/url-loader/src/plugins/zoompan.ts | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/url-loader/src/plugins/abr.ts b/packages/url-loader/src/plugins/abr.ts index edf12992..5be19e9a 100644 --- a/packages/url-loader/src/plugins/abr.ts +++ b/packages/url-loader/src/plugins/abr.ts @@ -10,7 +10,7 @@ export declare namespace AbrPlugin { } } -export const AbrPlugin = plugin({ +export const AbrPlugin = /* #__PURE__ */ plugin({ name: "Abr", supports: "video", inferOwnOptions: {} as AbrPlugin.Options, diff --git a/packages/url-loader/src/plugins/cropping.ts b/packages/url-loader/src/plugins/cropping.ts index ec971843..0721f5d9 100644 --- a/packages/url-loader/src/plugins/cropping.ts +++ b/packages/url-loader/src/plugins/cropping.ts @@ -48,7 +48,7 @@ export declare namespace CroppingPlugin { } } -export const CroppingPlugin = plugin({ +export const CroppingPlugin = /* #__PURE__ */ plugin({ name: "Cropping", supports: "all", inferOwnOptions: {} as CroppingPlugin.Options, diff --git a/packages/url-loader/src/plugins/default-image.ts b/packages/url-loader/src/plugins/default-image.ts index 3b4a4e5c..f63934db 100644 --- a/packages/url-loader/src/plugins/default-image.ts +++ b/packages/url-loader/src/plugins/default-image.ts @@ -11,7 +11,7 @@ export declare namespace DefaultImagePlugin { } } -export const DefaultImagePlugin = plugin({ +export const DefaultImagePlugin = /* #__PURE__ */ plugin({ name: "DefaultImage", supports: "image", inferOwnOptions: {} as DefaultImagePlugin.Options, diff --git a/packages/url-loader/src/plugins/effects.ts b/packages/url-loader/src/plugins/effects.ts index 5826dce8..964a99bc 100644 --- a/packages/url-loader/src/plugins/effects.ts +++ b/packages/url-loader/src/plugins/effects.ts @@ -17,7 +17,7 @@ export declare namespace EffectsPlugin { } } -export const EffectsPlugin = plugin({ +export const EffectsPlugin = /* #__PURE__ */ plugin({ name: "Effects", supports: "all", inferOwnOptions: {} as EffectsPlugin.Options, diff --git a/packages/url-loader/src/plugins/enhance.ts b/packages/url-loader/src/plugins/enhance.ts index ca17c85a..1c58ddee 100644 --- a/packages/url-loader/src/plugins/enhance.ts +++ b/packages/url-loader/src/plugins/enhance.ts @@ -10,7 +10,7 @@ export declare namespace EnhancePlugin { } } -export const EnhancePlugin = plugin({ +export const EnhancePlugin = /* #__PURE__ */ plugin({ name: "Enhance", supports: "image", inferOwnOptions: {} as EnhancePlugin.Options, diff --git a/packages/url-loader/src/plugins/extract.ts b/packages/url-loader/src/plugins/extract.ts index 8408204f..c9f4adb2 100644 --- a/packages/url-loader/src/plugins/extract.ts +++ b/packages/url-loader/src/plugins/extract.ts @@ -23,7 +23,7 @@ export declare namespace ExtractPlugin { } } -export const ExtractPlugin = plugin({ +export const ExtractPlugin = /* #__PURE__ */ plugin({ name: "Extract", supports: "image", inferOwnOptions: {} as ExtractPlugin.Options, diff --git a/packages/url-loader/src/plugins/fill-background.ts b/packages/url-loader/src/plugins/fill-background.ts index 74df677c..b5f7407c 100644 --- a/packages/url-loader/src/plugins/fill-background.ts +++ b/packages/url-loader/src/plugins/fill-background.ts @@ -24,7 +24,7 @@ export declare namespace FillBackgroundPlugin { } } -export const FillBackgroundPlugin = plugin({ +export const FillBackgroundPlugin = /* #__PURE__ */ plugin({ name: "FillBackground", supports: "image", inferOwnOptions: {} as FillBackgroundPlugin.Options, diff --git a/packages/url-loader/src/plugins/flags.ts b/packages/url-loader/src/plugins/flags.ts index 79120195..c0c16f81 100644 --- a/packages/url-loader/src/plugins/flags.ts +++ b/packages/url-loader/src/plugins/flags.ts @@ -8,7 +8,7 @@ export declare namespace FlagsPlugin { } } -export const FlagsPlugin = plugin({ +export const FlagsPlugin = /* #__PURE__ */ plugin({ name: "Flags", supports: "all", inferOwnOptions: {} as FlagsPlugin.Options, diff --git a/packages/url-loader/src/plugins/named-transformations.ts b/packages/url-loader/src/plugins/named-transformations.ts index 5a0f5294..3aa9d8ba 100644 --- a/packages/url-loader/src/plugins/named-transformations.ts +++ b/packages/url-loader/src/plugins/named-transformations.ts @@ -17,7 +17,7 @@ export declare namespace NamedTransformationsPlugin { } } -export const NamedTransformationsPlugin = plugin({ +export const NamedTransformationsPlugin = /* #__PURE__ */ plugin({ name: "NamedTransformations", strict: true, supports: "all", diff --git a/packages/url-loader/src/plugins/overlays.ts b/packages/url-loader/src/plugins/overlays.ts index 76d403e8..9916cfdd 100644 --- a/packages/url-loader/src/plugins/overlays.ts +++ b/packages/url-loader/src/plugins/overlays.ts @@ -69,7 +69,7 @@ export const DEFAULT_TEXT_OPTIONS = { fontWeight: "bold", }; -export const OverlaysPlugin = plugin({ +export const OverlaysPlugin = /* #__PURE__ */ plugin({ name: "Overlays", supports: "all", inferOwnOptions: {} as OverlaysPlugin.Options, diff --git a/packages/url-loader/src/plugins/preserve-transformations.ts b/packages/url-loader/src/plugins/preserve-transformations.ts index 6bfd0f8e..d6fce7ee 100644 --- a/packages/url-loader/src/plugins/preserve-transformations.ts +++ b/packages/url-loader/src/plugins/preserve-transformations.ts @@ -10,7 +10,7 @@ export declare namespace PreserveTransformationsPlugin { } } -export const PreserveTransformationsPlugin = plugin({ +export const PreserveTransformationsPlugin = /* #__PURE__ */ plugin({ name: "PreserveTransformations", supports: "all", inferOwnOptions: {} as PreserveTransformationsPlugin.Options, diff --git a/packages/url-loader/src/plugins/raw-transformations.ts b/packages/url-loader/src/plugins/raw-transformations.ts index 4f08a277..6780f0ec 100644 --- a/packages/url-loader/src/plugins/raw-transformations.ts +++ b/packages/url-loader/src/plugins/raw-transformations.ts @@ -11,7 +11,7 @@ export declare namespace RawTransformationsPlugin { } } -export const RawTransformationsPlugin = plugin({ +export const RawTransformationsPlugin = /* #__PURE__ */ plugin({ name: "RawTransformations", supports: "all", inferOwnOptions: {} as RawTransformationsPlugin.Options, diff --git a/packages/url-loader/src/plugins/recolor.ts b/packages/url-loader/src/plugins/recolor.ts index 890e5c0f..4021bcc9 100644 --- a/packages/url-loader/src/plugins/recolor.ts +++ b/packages/url-loader/src/plugins/recolor.ts @@ -23,7 +23,7 @@ export declare namespace RecolorPlugin { } } -export const RecolorPlugin = plugin({ +export const RecolorPlugin = /* #__PURE__ */ plugin({ name: "Recolor", supports: "image", inferOwnOptions: {} as RecolorPlugin.Options, diff --git a/packages/url-loader/src/plugins/remove-background.ts b/packages/url-loader/src/plugins/remove-background.ts index e2177a95..d9b6634f 100644 --- a/packages/url-loader/src/plugins/remove-background.ts +++ b/packages/url-loader/src/plugins/remove-background.ts @@ -10,7 +10,7 @@ export declare namespace RemoveBackgroundPlugin { } } -export const RemoveBackgroundPlugin = plugin({ +export const RemoveBackgroundPlugin = /* #__PURE__ */ plugin({ name: "RemoveBackground", supports: "image", inferOwnOptions: {} as RemoveBackgroundPlugin.Options, diff --git a/packages/url-loader/src/plugins/remove.ts b/packages/url-loader/src/plugins/remove.ts index e611f124..16f6908a 100644 --- a/packages/url-loader/src/plugins/remove.ts +++ b/packages/url-loader/src/plugins/remove.ts @@ -20,7 +20,7 @@ export declare namespace RemovePlugin { } } -export const RemovePlugin = plugin({ +export const RemovePlugin = /* #__PURE__ */ plugin({ name: "Remove", supports: "image", inferOwnOptions: {} as RemovePlugin.Options, diff --git a/packages/url-loader/src/plugins/replace-background.ts b/packages/url-loader/src/plugins/replace-background.ts index b69945f8..de125e1c 100644 --- a/packages/url-loader/src/plugins/replace-background.ts +++ b/packages/url-loader/src/plugins/replace-background.ts @@ -15,7 +15,7 @@ export declare namespace ReplaceBackgroundPlugin { } } -export const ReplaceBackgroundPlugin = plugin({ +export const ReplaceBackgroundPlugin = /* #__PURE__ */ plugin({ name: "ReplaceBackground", supports: "image", inferOwnOptions: {} as ReplaceBackgroundPlugin.Options, diff --git a/packages/url-loader/src/plugins/replace.ts b/packages/url-loader/src/plugins/replace.ts index e2e880ff..4d15da4d 100644 --- a/packages/url-loader/src/plugins/replace.ts +++ b/packages/url-loader/src/plugins/replace.ts @@ -17,7 +17,7 @@ export declare namespace ReplacePlugin { } } -export const ReplacePlugin = plugin({ +export const ReplacePlugin = /* #__PURE__ */ plugin({ name: "Replace", supports: "image", inferOwnOptions: {} as ReplacePlugin.Options, diff --git a/packages/url-loader/src/plugins/restore.ts b/packages/url-loader/src/plugins/restore.ts index 4ed987a6..a8bc47b3 100644 --- a/packages/url-loader/src/plugins/restore.ts +++ b/packages/url-loader/src/plugins/restore.ts @@ -10,7 +10,7 @@ export declare namespace RestorePlugin { } } -export const RestorePlugin = plugin({ +export const RestorePlugin = /* #__PURE__ */ plugin({ name: "Restore", supports: "image", inferOwnOptions: {} as RestorePlugin.Options, diff --git a/packages/url-loader/src/plugins/sanitize.ts b/packages/url-loader/src/plugins/sanitize.ts index 3c5836c8..6734c82d 100644 --- a/packages/url-loader/src/plugins/sanitize.ts +++ b/packages/url-loader/src/plugins/sanitize.ts @@ -10,7 +10,7 @@ export declare namespace SanitizePlugin { } } -export const SanitizePlugin = plugin({ +export const SanitizePlugin = /* #__PURE__ */ plugin({ name: "Sanitize", supports: "image", inferOwnOptions: {} as SanitizePlugin.Options, diff --git a/packages/url-loader/src/plugins/seo.ts b/packages/url-loader/src/plugins/seo.ts index 8df5c59b..c1505649 100644 --- a/packages/url-loader/src/plugins/seo.ts +++ b/packages/url-loader/src/plugins/seo.ts @@ -10,7 +10,7 @@ export declare namespace SeoPlugin { } } -export const SeoPlugin = plugin({ +export const SeoPlugin = /* #__PURE__ */ plugin({ name: "Seo", supports: "all", inferOwnOptions: {} as SeoPlugin.Options, diff --git a/packages/url-loader/src/plugins/underlays.ts b/packages/url-loader/src/plugins/underlays.ts index 3a172bef..d5e96a79 100644 --- a/packages/url-loader/src/plugins/underlays.ts +++ b/packages/url-loader/src/plugins/underlays.ts @@ -42,7 +42,7 @@ export declare namespace UnderlaysPlugin { } } -export const UnderlaysPlugin = plugin({ +export const UnderlaysPlugin = /* #__PURE__ */ plugin({ name: "Underlays", supports: "all", inferOwnOptions: {} as UnderlaysPlugin.Options, diff --git a/packages/url-loader/src/plugins/version.ts b/packages/url-loader/src/plugins/version.ts index 5c9ac871..3feec565 100644 --- a/packages/url-loader/src/plugins/version.ts +++ b/packages/url-loader/src/plugins/version.ts @@ -10,7 +10,7 @@ export declare namespace VersionPlugin { } } -export const VersionPlugin = plugin({ +export const VersionPlugin = /* #__PURE__ */ plugin({ name: "Version", supports: "all", inferOwnOptions: {} as VersionPlugin.Options, diff --git a/packages/url-loader/src/plugins/zoompan.ts b/packages/url-loader/src/plugins/zoompan.ts index a3e75d73..0a2b469d 100644 --- a/packages/url-loader/src/plugins/zoompan.ts +++ b/packages/url-loader/src/plugins/zoompan.ts @@ -17,7 +17,7 @@ export declare namespace ZoompanPlugin { } } -export const ZoompanPlugin = plugin({ +export const ZoompanPlugin = /* #__PURE__ */ plugin({ name: "Zoompan", supports: "image", inferOwnOptions: {} as ZoompanPlugin.Options, From 72f8a1d1ad033ed4b77cf495691e7f4880e713d2 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Oct 2024 19:59:46 +0000 Subject: [PATCH 21/21] chore(release): 6.0.0-beta.7 [skip ci] # [@cloudinary-util/url-loader-v6.0.0-beta.7](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.6...@cloudinary-util/url-loader-v6.0.0-beta.7) (2024-10-31) ### Bug Fixes * make all individual plugin declarations tree-shakeable ([#229](https://github.com/cloudinary-community/cloudinary-util/issues/229)) ([b6a5563](https://github.com/cloudinary-community/cloudinary-util/commit/b6a5563e3d35c79eac953468697cb66f01b1879d)) --- packages/url-loader/CHANGELOG.md | 7 +++++++ packages/url-loader/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/url-loader/CHANGELOG.md b/packages/url-loader/CHANGELOG.md index a6bde1ea..fdc983dc 100644 --- a/packages/url-loader/CHANGELOG.md +++ b/packages/url-loader/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cloudinary-util/url-loader-v6.0.0-beta.7](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.6...@cloudinary-util/url-loader-v6.0.0-beta.7) (2024-10-31) + + +### Bug Fixes + +* make all individual plugin declarations tree-shakeable ([#229](https://github.com/cloudinary-community/cloudinary-util/issues/229)) ([b6a5563](https://github.com/cloudinary-community/cloudinary-util/commit/b6a5563e3d35c79eac953468697cb66f01b1879d)) + # [@cloudinary-util/url-loader-v6.0.0-beta.6](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/url-loader-v6.0.0-beta.5...@cloudinary-util/url-loader-v6.0.0-beta.6) (2024-10-31) diff --git a/packages/url-loader/package.json b/packages/url-loader/package.json index 762f043f..938330d7 100644 --- a/packages/url-loader/package.json +++ b/packages/url-loader/package.json @@ -1,6 +1,6 @@ { "name": "@cloudinary-util/url-loader", - "version": "6.0.0-beta.6", + "version": "6.0.0-beta.7", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts",