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/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/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..b2bc5fc4 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,148 +1,146 @@ -# [@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) +# [@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 -* 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)) +* 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-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) +# [@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) + +### 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 -* Adds videojs dispose method to Video Player type ([2fd75c1](https://github.com/cloudinary-community/cloudinary-util/commit/2fd75c1c6ceac2496f2fa258d466e1e0d2d1f9cd)) +- 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.9](https://github.com/cloudinary-community/cloudinary-util/compare/@cloudinary-util/types-v1.5.8...@cloudinary-util/types-v1.5.9) (2024-09-16) +# [@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)) + +# [@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 +148,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/package.json b/packages/types/package.json index c0c2de04..3b5f081c 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.3", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index a30c58ba..2bd33ffe 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,22 @@ 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 { CloudinaryProductGallery } from "./types/cloudinary-product-gallery.js"; + export type { CloudinaryAssetConfiguration, CloudinaryAssetConfigurationAuthToken, CloudinaryAssetConfigurationCloud, - CloudinaryAssetConfigurationUrl + CloudinaryAssetConfigurationUrl, } from "./types/configuration.js"; - 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"; +} 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 9de4309b..fdc983dc 100644 --- a/packages/url-loader/CHANGELOG.md +++ b/packages/url-loader/CHANGELOG.md @@ -1,165 +1,188 @@ -# [@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) +# [@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 -* 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) +* 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-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) +# [@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 -* 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) +* 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-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) +# [@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) ### Bug Fixes -* format file url-loader index, force build/deploy ([71a535c](https://github.com/cloudinary-community/cloudinary-util/commit/71a535cf1a2fa6234755127e1201a9e3aad240a6)) +- 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-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) +# [@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) ### Bug Fixes -* reordering to force deploy ([443e1f7](https://github.com/cloudinary-community/cloudinary-util/commit/443e1f75da6963ce52d236913c786cdcb1d504fa)) +- 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.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) +# [@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.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 -* updating type of radius property to include number ([f5c260f](https://github.com/cloudinary-community/cloudinary-util/commit/f5c260ffe97fb977c9d5bb79251aa77e33ea9b1d)) +- 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.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) +# [@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) + +# [@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 -* 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) +- format file url-loader index, force build/deploy ([71a535c](https://github.com/cloudinary-community/cloudinary-util/commit/71a535cf1a2fa6234755127e1201a9e3aad240a6)) -# [@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) +# [@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)) +# [@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)) + +# [@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) + +# [@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 f158569c..938330d7 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.6", + "version": "6.0.0-beta.7", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", @@ -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..66bdab6e 100644 --- a/packages/url-loader/src/constants/parameters.ts +++ b/packages/url-loader/src/constants/parameters.ts @@ -1,309 +1,238 @@ -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 = + | "auto" + | "auto:image" + | "auto:animated" + | "gif" + | "png" + | "jpg" + | "bmp" + | "ico" + | "pdf" + | "tiff" + | "eps" + | "jpc" + | "jp2" + | "psd" + | "webp" + | "zip" + | "svg" + | "webm" + | "wdp" + | "hpx" + | "djvu" + | "ai" + | "flif" + | "bpg" + | "miff" + | "tga" + | "heic" + | "default" // library specific feature to turn off automatic optimization + | (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..45c50a00 100644 --- a/packages/url-loader/src/index.ts +++ b/packages/url-loader/src/index.ts @@ -1,9 +1,13 @@ // URL Construction & Plugins export { + cloudinaryPluginKeys, + cloudinaryPluginProps, constructCloudinaryUrl, transformationPlugins, - type ConstructUrlProps + type AnalyticsOptions, + type ConfigOptions, + type ConstructUrlProps, } from "./lib/cloudinary.js"; // Upload Widget @@ -15,12 +19,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 +32,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..a0be824f 100644 --- a/packages/url-loader/src/lib/cloudinary.ts +++ b/packages/url-loader/src/lib/cloudinary.ts @@ -1,130 +1,150 @@ +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, + 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 { + CloudinaryKey, + CtxParam, TransformationPlugin, -} from "../types/plugins.js"; +} from "./plugin.js"; +import { entriesOf, throwError } from "./utils.js"; export const transformationPlugins = [ // 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 +] 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); + +export const cloudinaryPluginKeys: readonly CloudinaryKey[] = /* #__PURE__ */ Object.keys( + cloudinaryPluginProps +) as never; + +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 } & CtxParam; +} + +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 +159,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 +193,55 @@ 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, supports, props }: TransformationPlugin) => { + const shouldApply = Object.keys(props).some( + (key) => options[key as never] !== undefined + ); + + 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, - }); + // 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 { 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 +302,7 @@ export function constructCloudinaryUrl({ } return cldAsset.toURL({ - trackedAnalytics: analytics, + trackedAnalytics: typeof analytics === "object" ? analytics : undefined, }); } @@ -330,7 +318,7 @@ interface SearchAssetRawTransformationsOptions { export function searchAssetRawTransformations( query: string, asset: CloudinaryImage | CloudinaryVideo, - options?: SearchAssetRawTransformationsOptions, + options?: SearchAssetRawTransformationsOptions ) { if (typeof asset.transformation === "undefined") return; @@ -344,7 +332,7 @@ export function searchAssetRawTransformations( .toString() .split("/") .flatMap((seg) => seg.split(",")); - }, + } ); const matches = transformations.filter((transformation) => { @@ -357,3 +345,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, + readonly [ + ...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..e38f4439 --- /dev/null +++ b/packages/url-loader/src/lib/plugin.ts @@ -0,0 +1,106 @@ +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"; + +export interface AllOptions extends AssetOptions, ImageOptions, VideoOptions {} + +export type CloudinaryKey = keyof AllOptions & {}; + +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, + name extends string, + options extends object, + alwaysApply extends boolean, +> { + name: name; + supports: assetType; + apply: PluginApplicationDefinition; + inferOwnOptions: options; + props: Record; + alwaysApply?: alwaysApply; + strict?: boolean; +} + +export interface TransformationPlugin< + assetType extends SupportedAssetType = SupportedAssetType, + name extends string = string, + opts extends object = object, + alwaysApply extends boolean = boolean, +> { + name: name; + supports: assetType; + apply: PluginApplication; + inferOwnOptions: opts; + props: Record; + alwaysApply: alwaysApply; + strict?: boolean; +} + +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; + +// 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, + 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, + name extends string, + opts extends object, + alwaysApply extends boolean, +>( + 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/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..7e22db4b 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..df102233 --- /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..bcea13ef 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, @@ -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,25 +85,21 @@ 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.", ); } - // 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..5be19e9a 100644 --- a/packages/url-loader/src/plugins/abr.ts +++ b/packages/url-loader/src/plugins/abr.ts @@ -1,30 +1,27 @@ -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; +export const AbrPlugin = /* #__PURE__ */ plugin({ + name: "Abr", + supports: "video", + inferOwnOptions: {} as AbrPlugin.Options, + props: { + streamingProfile: true, + }, + apply: (asset, opts) => { + if (typeof opts.streamingProfile !== "string") return {}; - if (typeof streamingProfile === "string") { - cldAsset.addTransformation(`sp_${streamingProfile}`); - } + 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..0721f5d9 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,71 @@ 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; + /** + * @description Height of the given asset. + */ + height?: string | number; + /** + * @description Width of the given asset. + */ + width?: string | number; + } -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 interface NestedOptions { + type: CropMode; + aspectRatio?: AspectRatio; + gravity?: Gravity; + height?: Height; + width?: Width; + x?: X; + y?: Y; + zoom?: Zoom; + source?: boolean; + } +} + +export const CroppingPlugin = /* #__PURE__ */ plugin({ + name: "Cropping", + supports: "all", + inferOwnOptions: {} as CroppingPlugin.Options, + props: { + aspectRatio: true, + crop: true, + gravity: true, + zoom: true, + height: true, + width: true, + }, + // 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 +92,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 +117,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 +155,7 @@ export const croppingPlugin = { sourceTransformations.forEach((transformation) => { if (transformation.length > 0) { - cldAsset.addTransformation(transformation.join(",")); + asset.addTransformation(transformation.join(",")); } }); @@ -160,14 +173,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 +196,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 +228,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 +241,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..f63934db 100644 --- a/packages/url-loader/src/plugins/default-image.ts +++ b/packages/url-loader/src/plugins/default-image.ts @@ -1,38 +1,34 @@ -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 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 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 const DefaultImagePlugin = /* #__PURE__ */ plugin({ + name: "DefaultImage", + supports: "image", + inferOwnOptions: {} as DefaultImagePlugin.Options, + props: { defaultImage: true }, + apply: (asset, opts) => { + const { defaultImage } = opts; -export const defaultImagePlugin = { - props: defaultImageProps, - assetTypes: ["image", "images"], - plugin: (settings) => { - const { cldAsset, options } = settings; - const { defaultImage } = options; + if (typeof defaultImage !== "string") return {}; - 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, ":"); - cldAsset.addTransformation(`d_${defaultImageId}`); + 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 {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/effects.ts b/packages/url-loader/src/plugins/effects.ts index 8adaf0ef..964a99bc 100644 --- a/packages/url-loader/src/plugins/effects.ts +++ b/packages/url-loader/src/plugins/effects.ts @@ -1,101 +1,107 @@ -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 = /* #__PURE__ */ 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, opts) => { // Handle any top-level effect props const transformationStrings = constructTransformationString({ effects: qualifiersEffects, - options, + options: opts, }); - 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)) { - options?.effects.forEach((effectsSet) => { + if (isArray(opts?.effects)) { + opts?.effects.forEach((effectsSet) => { const transformationString = constructTransformationString({ effects: qualifiersEffects, options: effectsSet, }) .filter((t) => !!t) .join(","); - cldAsset.effect(transformationString); + cldAsset.addTransformation(transformationString); }); } @@ -123,4 +129,4 @@ export const effectsPlugin = { return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/enhance.ts b/packages/url-loader/src/plugins/enhance.ts index 683d543e..1c58ddee 100644 --- a/packages/url-loader/src/plugins/enhance.ts +++ b/packages/url-loader/src/plugins/enhance.ts @@ -1,30 +1,27 @@ -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 = /* #__PURE__ */ plugin({ + name: "Enhance", + supports: "image", + inferOwnOptions: {} as EnhancePlugin.Options, + props: { + enhance: true, + }, + apply: (cldAsset, opts) => { + if (opts.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..c9f4adb2 100644 --- a/packages/url-loader/src/plugins/extract.ts +++ b/packages/url-loader/src/plugins/extract.ts @@ -1,83 +1,81 @@ -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 = /* #__PURE__ */ plugin({ + name: "Extract", + supports: "image", + inferOwnOptions: {} as ExtractPlugin.Options, + props: { + extract: true, + }, + 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..b5f7407c 100644 --- a/packages/url-loader/src/plugins/fill-background.ts +++ b/packages/url-loader/src/plugins/fill-background.ts @@ -1,44 +1,46 @@ -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; - const { fillBackground } = options; + export interface NestedOptions { + crop?: CropMode; + gravity?: Gravity; + prompt?: ListablePrompts; + } +} + +export const FillBackgroundPlugin = /* #__PURE__ */ plugin({ + name: "FillBackground", + supports: "image", + inferOwnOptions: {} as FillBackgroundPlugin.Options, + props: { + fillBackground: true, + }, + 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}`; @@ -81,4 +83,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..c0c16f81 100644 --- a/packages/url-loader/src/plugins/flags.ts +++ b/packages/url-loader/src/plugins/flags.ts @@ -1,50 +1,34 @@ -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 = /* #__PURE__ */ plugin({ + name: "Flags", + supports: "all", + 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 // 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 +38,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..3aa9d8ba 100644 --- a/packages/url-loader/src/plugins/named-transformations.ts +++ b/packages/url-loader/src/plugins/named-transformations.ts @@ -1,56 +1,50 @@ -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 = /* #__PURE__ */ plugin({ + name: "NamedTransformations", strict: true, - assetTypes: ["image", "images", "video", "videos"], - plugin: ({ cldAsset, options }) => { - const { transformations, namedTransformations } = options; + supports: "all", + inferOwnOptions: {} as NamedTransformationsPlugin.Options, + props: { + namedTransformations: true, + transformations: true, + }, + 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.", ); } 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..9916cfdd 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,21 @@ 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 }) => { - const { text, overlays = [] } = options; +export const OverlaysPlugin = /* #__PURE__ */ plugin({ + name: "Overlays", + supports: "all", + inferOwnOptions: {} as OverlaysPlugin.Options, + props: { + overlays: true, + text: true, + }, + apply: (cldAsset, opts) => { + const { text, overlays = [] } = opts; const type = "overlay"; const typeQualifier = "l"; - if (Array.isArray(overlays)) { + if (isArray(overlays)) { overlays.forEach(applyOverlay); } @@ -119,12 +99,6 @@ export const overlaysPlugin = { }); } - /** - * applyOverlay - */ - - type ApplyOverlaySettings = z.infer; - function applyOverlay({ publicId, url, @@ -135,7 +109,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"; @@ -156,7 +130,7 @@ export const overlaysPlugin = { } else if (hasPublicId) { layerTransformation = `${typeQualifier}_${publicId.replace( /\//g, - ":" + ":", )}`; } else if (hasUrl) { layerTransformation = `${typeQualifier}_fetch:${encodeBase64(url)}`; @@ -168,12 +142,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 +225,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 +235,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 +256,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"); @@ -360,31 +314,27 @@ export const overlaysPlugin = { )?.forEach((character: string) => { layerText = layerText?.replace( character, - specialCharacters[character] + specialCharacters[character], ); }); } layerTransformation = `${layerTransformation}:${textTransformations.join( - "_" + "_", )}:${layerText}`; } // 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 +365,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..d6fce7ee 100644 --- a/packages/url-loader/src/plugins/preserve-transformations.ts +++ b/packages/url-loader/src/plugins/preserve-transformations.ts @@ -1,23 +1,24 @@ 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 }) => { - const { preserveTransformations = false } = options; +export const PreserveTransformationsPlugin = /* #__PURE__ */ plugin({ + name: "PreserveTransformations", + supports: "all", + inferOwnOptions: {} as PreserveTransformationsPlugin.Options, + props: { + preserveTransformations: true, + }, + 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 @@ -25,15 +26,22 @@ export const preserveTransformationsPlugin = { if (preserveTransformations) { try { - const transformations = getTransformations(options.src).map(t => t.join(',')); + if (ctx.src === undefined) { + throw new Error("options.src was undefined"); + } + 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}`) + } 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..6780f0ec 100644 --- a/packages/url-loader/src/plugins/raw-transformations.ts +++ b/packages/url-loader/src/plugins/raw-transformations.ts @@ -1,35 +1,34 @@ -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 }) => { - let { rawTransformations = [] } = options; +export const RawTransformationsPlugin = /* #__PURE__ */ plugin({ + name: "RawTransformations", + supports: "all", + inferOwnOptions: {} as RawTransformationsPlugin.Options, + props: { + rawTransformations: true, + }, + apply: (cldAsset, opts) => { + let { rawTransformations = [] } = opts; - 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..4021bcc9 100644 --- a/packages/url-loader/src/plugins/recolor.ts +++ b/packages/url-loader/src/plugins/recolor.ts @@ -1,37 +1,37 @@ -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; - const { recolor } = options; +export const RecolorPlugin = /* #__PURE__ */ plugin({ + name: "Recolor", + supports: "image", + inferOwnOptions: {} as RecolorPlugin.Options, + props: { + recolor: true, + }, + apply: (cldAsset, opts) => { + const { recolor } = opts; const recolorOptions: Record = { prompt: undefined, @@ -39,8 +39,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 +54,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 +78,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..d9b6634f 100644 --- a/packages/url-loader/src/plugins/remove-background.ts +++ b/packages/url-loader/src/plugins/remove-background.ts @@ -1,28 +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 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 = /* #__PURE__ */ plugin({ + name: "RemoveBackground", + supports: "image", + inferOwnOptions: {} as RemoveBackgroundPlugin.Options, + props: { + removeBackground: true, + }, + apply: (cldAsset, opts) => { + if (opts.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..16f6908a 100644 --- a/packages/url-loader/src/plugins/remove.ts +++ b/packages/url-loader/src/plugins/remove.ts @@ -1,39 +1,34 @@ -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 }) => { - const { remove } = options; +export const RemovePlugin = /* #__PURE__ */ plugin({ + name: "Remove", + supports: "image", + inferOwnOptions: {} as RemovePlugin.Options, + props: { + remove: true, + }, + apply: (cldAsset, opts) => { + const { remove } = opts; const removeOptions: Record = { prompt: undefined, @@ -44,16 +39,16 @@ 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( - "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", ); } @@ -61,13 +56,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,14 +86,14 @@ export const removePlugin = { return {}; }, -} satisfies TransformationPlugin; +}); /** * regionArrayToString */ function regionArrayToString( - regionArray: Array> + regionArray: Array>, ): string { const indexes: Record = { 0: "x", @@ -109,7 +104,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..de125e1c 100644 --- a/packages/url-loader/src/plugins/replace-background.ts +++ b/packages/url-loader/src/plugins/replace-background.ts @@ -1,58 +1,54 @@ -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; - const { replaceBackground } = options; - - if (!replaceBackground || typeof replaceBackground === "undefined") return {}; +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 | string | boolean; + } + + export interface NestedOptions { + prompt?: string; + seed?: number; + } +} + +export const ReplaceBackgroundPlugin = /* #__PURE__ */ plugin({ + name: "ReplaceBackground", + supports: "image", + inferOwnOptions: {} as ReplaceBackgroundPlugin.Options, + props: { + replaceBackground: true, + }, + apply: (cldAsset, opts) => { + const { replaceBackground } = opts; - const properties = []; + if (!replaceBackground) return {}; - if ( typeof replaceBackground === 'object' ) { + const properties = []; - 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..4d15da4d 100644 --- a/packages/url-loader/src/plugins/replace.ts +++ b/packages/url-loader/src/plugins/replace.ts @@ -1,58 +1,57 @@ -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 }) => { - const { replace = null } = options; - - if (replace) { - let from: string, - to: string, - preserveGeometry: boolean = false; - - if (Array.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.effect(properties.join(";")); +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 = /* #__PURE__ */ plugin({ + name: "Replace", + supports: "image", + inferOwnOptions: {} as ReplacePlugin.Options, + props: { + replace: true, + }, + 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 {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/restore.ts b/packages/url-loader/src/plugins/restore.ts index a0754145..a8bc47b3 100644 --- a/packages/url-loader/src/plugins/restore.ts +++ b/packages/url-loader/src/plugins/restore.ts @@ -1,29 +1,29 @@ -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 }) => { - const { restore = false } = options; +export const RestorePlugin = /* #__PURE__ */ plugin({ + name: "Restore", + supports: "image", + inferOwnOptions: {} as RestorePlugin.Options, + props: { + restore: true, + }, + apply: (cldAsset, opts) => { + const { restore } = opts; 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..6734c82d 100644 --- a/packages/url-loader/src/plugins/sanitize.ts +++ b/packages/url-loader/src/plugins/sanitize.ts @@ -1,33 +1,35 @@ -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 }) => { - const { sanitize = true } = options; +export const SanitizePlugin = /* #__PURE__ */ plugin({ + name: "Sanitize", + supports: "image", + inferOwnOptions: {} as SanitizePlugin.Options, + props: { + sanitize: true, + }, + alwaysApply: true, + apply: (cldAsset, opts, ctx) => { + const { sanitize = true } = opts; const shouldApplySanitizer: boolean = sanitize && - (options.format === "svg" || cldAsset.publicID.endsWith(".svg")); + (ctx.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..c1505649 100644 --- a/packages/url-loader/src/plugins/seo.ts +++ b/packages/url-loader/src/plugins/seo.ts @@ -1,34 +1,33 @@ -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 }) => { - const { seoSuffix } = options; +export const SeoPlugin = /* #__PURE__ */ plugin({ + name: "Seo", + supports: "all", + inferOwnOptions: {} as SeoPlugin.Options, + props: { + seoSuffix: true, + }, + apply: (cldAsset, opts, ctx) => { + const { seoSuffix } = opts; + + if (typeof seoSuffix !== "string") return {}; - 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 (ctx.deliveryType === "fetch") { + console.warn("SEO suffix is not supported with a delivery type of fetch"); + } else { + cldAsset.setSuffix(seoSuffix); } return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/underlays.ts b/packages/url-loader/src/plugins/underlays.ts index ee9b96d3..d5e96a79 100644 --- a/packages/url-loader/src/plugins/underlays.ts +++ b/packages/url-loader/src/plugins/underlays.ts @@ -1,78 +1,66 @@ 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 }) => { - const { underlay, underlays = [] } = 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 = /* #__PURE__ */ plugin({ + name: "Underlays", + supports: "all", + inferOwnOptions: {} as UnderlaysPlugin.Options, + props: { + underlay: true, + underlays: true, + }, + apply: (cldAsset, opts) => { + const { underlay, underlays = [] } = opts; 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 +75,6 @@ export const underlaysPlugin = { * applyUnderlay */ - type ApplyUnderlaySettings = z.infer; - function applyUnderlay({ publicId, type, @@ -97,7 +83,7 @@ export const underlaysPlugin = { flags: layerFlags = [], appliedFlags = [], ...options - }: ApplyUnderlaySettings) { + }: UnderlaysPlugin.NestedOptions) { const hasPublicId = typeof publicId === "string"; const hasPosition = typeof position === "object"; @@ -110,7 +96,7 @@ export const underlaysPlugin = { let layerTransformation = `${typeQualifier}_${publicId.replace( /\//g, - ":" + ":", )}`; // Begin organizing transformations based on what it is and the location @@ -121,10 +107,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 +126,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 +170,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..3feec565 100644 --- a/packages/url-loader/src/plugins/version.ts +++ b/packages/url-loader/src/plugins/version.ts @@ -1,30 +1,31 @@ -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 }) => { - const { version } = options; +export const VersionPlugin = /* #__PURE__ */ plugin({ + name: "Version", + supports: "all", + inferOwnOptions: {} as VersionPlugin.Options, + props: { + version: true, + }, + apply: (cldAsset, opts) => { + const { version } = opts; + + if (typeof version !== "string" && typeof version !== "number") return {}; - 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", "")); - } + // Replace a `v` in the string just in case the caller + // passes it in + cldAsset.setVersion(`${version}`.replace("v", "")); return {}; }, -} satisfies TransformationPlugin; +}); diff --git a/packages/url-loader/src/plugins/zoompan.ts b/packages/url-loader/src/plugins/zoompan.ts index f13b377e..0a2b469d 100644 --- a/packages/url-loader/src/plugins/zoompan.ts +++ b/packages/url-loader/src/plugins/zoompan.ts @@ -1,45 +1,44 @@ -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 }) => { - const { zoompan = false } = options; + export interface NestedOptions { + loop?: QualifierOptions["loop"]; + options: string; + } +} + +export const ZoompanPlugin = /* #__PURE__ */ plugin({ + name: "Zoompan", + supports: "image", + inferOwnOptions: {} as ZoompanPlugin.Options, + props: { + zoompan: true, + }, + apply: (cldAsset, opts) => { + const { zoompan = false } = opts; const overrides: PluginOptions = { format: undefined, }; 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 +47,7 @@ export const zoompanPlugin = { zoompanEffect = `${zoompanEffect}:${zoompan.options}`; } - cldAsset.effect(zoompanEffect); + cldAsset.addTransformation(zoompanEffect); let loopEffect; @@ -62,7 +61,7 @@ export const zoompanPlugin = { } if (loopEffect) { - cldAsset.effect(loopEffect); + cldAsset.addTransformation(loopEffect); } } @@ -74,4 +73,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 53a27a6f..443ee9cc 100644 --- a/packages/url-loader/src/types/asset.ts +++ b/packages/url-loader/src/types/asset.ts @@ -1,145 +1,74 @@ -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 +import type { Format } from "../constants/parameters.js"; -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 - .enum([ - "auto", - "auto:image", - "auto:animated", - "gif", - "png", - "jpg", - "bmp", - "ico", - "pdf", - "tiff", - "eps", - "jpc", - "jp2", - "psd", - "webp", - "zip", - "svg", - "webm", - "wdp", - "hpx", - "djvu", - "ai", - "flif", - "bpg", - "miff", - "tga", - "heic", - "default" // library specific feature to turn off automatic optimization - ]) - .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 type SupportedAssetTypeInput = SupportedAssetType | "videos" | "images"; - // 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, -}); +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?: Format; + /** + * @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; +} -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..ef01c82b --- /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..701b3d5f --- /dev/null +++ b/packages/url-loader/tests/plugins/remove-background.spec.ts @@ -0,0 +1,29 @@ +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`); + }); + }); +}); 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 68% rename from packages/url-loader/tests/plugins/replace.spec.js rename to packages/url-loader/tests/plugins/replace.spec.ts index 5519f64b..e31a9beb 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,28 +65,15 @@ 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: {}, - }); - - 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..f98f752e --- /dev/null +++ b/packages/url-loader/tests/plugins/restore.spec.ts @@ -0,0 +1,29 @@ +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`); + }); + }); +}); 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..795dd2f7 --- /dev/null +++ b/packages/url-loader/tests/plugins/zoompan.spec.ts @@ -0,0 +1,106 @@ +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 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..c9590d54 100644 --- a/packages/util/CHANGELOG.md +++ b/packages/util/CHANGELOG.md @@ -1,77 +1,79 @@ -# [@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) +# [@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 -* Change to Force Deploy ([#216](https://github.com/cloudinary-community/cloudinary-util/issues/216)) ([78e44a0](https://github.com/cloudinary-community/cloudinary-util/commit/78e44a043da447394280bdc9065910d0194517b8)) +- 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-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) +# [@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)) +# [@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) - ### 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/package.json b/packages/util/package.json index bf67b153..75e96705 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.2", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", 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/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 1bc4a7f2..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: @@ -140,16 +94,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: @@ -159,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'} @@ -735,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==} @@ -1042,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'} @@ -1105,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'} @@ -1318,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] @@ -1433,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==} @@ -1508,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} @@ -1681,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'} @@ -1706,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==} @@ -1780,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'} @@ -1817,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==} @@ -1854,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'} @@ -1870,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'} @@ -1889,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'} @@ -1920,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'} @@ -1952,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==} @@ -1980,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'} @@ -1991,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==} @@ -2038,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'} @@ -2059,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==} @@ -2241,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: @@ -2278,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'} @@ -2308,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'} @@ -2343,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'} @@ -2359,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==} @@ -2375,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} @@ -2562,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==} @@ -2604,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==} @@ -2677,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==} @@ -2690,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==} @@ -2762,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'} @@ -2779,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'} @@ -2824,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'} @@ -2840,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'} @@ -2871,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'} @@ -2883,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} @@ -2937,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'} @@ -2960,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} @@ -3009,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'} @@ -3062,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'} @@ -3084,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'} @@ -3110,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'} @@ -3133,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'} @@ -3149,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'} @@ -3176,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'} @@ -3246,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'} @@ -3257,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 @@ -3298,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==} @@ -3312,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==} @@ -3334,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'} @@ -3391,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==} @@ -3415,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 @@ -3454,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'} @@ -3483,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'} @@ -3554,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'} @@ -3758,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==} @@ -3829,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==} @@ -3843,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'} @@ -3876,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} @@ -3963,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'} @@ -4098,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'} @@ -4109,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'} @@ -4167,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==} @@ -4180,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'} @@ -4204,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'} @@ -4228,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} @@ -4264,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==} @@ -4307,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'} @@ -4349,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'} @@ -4399,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'} @@ -4468,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'} @@ -4479,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'} @@ -4500,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: @@ -4583,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'} @@ -4612,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'} @@ -4624,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==} @@ -4659,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==} @@ -4675,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'} @@ -4711,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'} @@ -4722,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'} @@ -4754,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'} @@ -4802,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'} @@ -4857,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'} @@ -4886,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==} @@ -4915,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'} @@ -5065,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==} @@ -5164,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} @@ -5240,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==} @@ -5356,27 +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-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==} - - 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 @@ -6118,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 @@ -6305,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 @@ -6371,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 @@ -6580,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 @@ -6718,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 @@ -7011,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 @@ -7032,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: {} @@ -7132,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 @@ -7178,8 +5633,6 @@ snapshots: transitivePeerDependencies: - supports-color - bail@2.0.2: {} - balanced-match@1.0.2: {} before-after-hook@2.2.3: {} @@ -7213,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: @@ -7229,8 +5678,6 @@ snapshots: callsites@3.1.0: {} - camelcase-css@2.0.1: {} - camelcase-keys@6.2.2: dependencies: camelcase: 5.3.1 @@ -7246,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 @@ -7256,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 @@ -7279,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: @@ -7313,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 @@ -7340,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: @@ -7403,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 @@ -7432,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 @@ -7720,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 @@ -7750,8 +5943,6 @@ snapshots: dependencies: esutils: 2.0.3 - dompurify@3.0.6: {} - dot-prop@5.3.0: dependencies: is-obj: 2.0.0 @@ -7764,8 +5955,6 @@ snapshots: electron-to-chromium@1.4.626: {} - elkjs@0.8.2: {} - emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -7777,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 @@ -7958,8 +6145,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 +6170,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 +6197,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 +6235,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 +6245,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 @@ -8191,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 @@ -8270,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: @@ -8351,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 @@ -8364,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 @@ -8440,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 @@ -8459,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 @@ -8516,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 @@ -8536,8 +6664,6 @@ snapshots: has-bigints@1.0.2: {} - has-flag@2.0.0: {} - has-flag@3.0.0: {} has-flag@4.0.0: {} @@ -8558,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 @@ -8572,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: {} @@ -8690,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 @@ -8713,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 @@ -8725,7 +6733,8 @@ snapshots: ignore@5.3.1: {} - immutable@4.3.4: {} + immutable@4.3.4: + optional: true import-fresh@3.3.0: dependencies: @@ -8749,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 @@ -8804,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: @@ -8824,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: @@ -8844,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: {} @@ -8858,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 @@ -8887,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: {} @@ -8956,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 @@ -8991,8 +6956,6 @@ snapshots: json5@2.2.3: {} - jsonc-parser@3.2.0: {} - jsonfile@6.1.0: dependencies: universalify: 2.0.0 @@ -9008,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: {} @@ -9073,8 +7022,6 @@ snapshots: lodash.escaperegexp@4.1.2: {} - lodash.get@4.4.2: {} - lodash.ismatch@4.4.0: {} lodash.isplainobject@4.0.6: {} @@ -9089,8 +7036,6 @@ snapshots: lodash@4.17.21: {} - longest-streak@3.1.0: {} - loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -9124,541 +7069,47 @@ snapshots: 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 - - micromark-util-sanitize-uri@2.0.0: - 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: @@ -9721,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 @@ -9842,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 @@ -9860,8 +7205,6 @@ snapshots: normalize-path@3.0.0: {} - normalize-range@0.1.2: {} - normalize-url@6.1.0: {} npm-bundled@2.0.1: @@ -9889,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: @@ -10030,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 @@ -10053,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: {} @@ -10094,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: {} @@ -10123,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 @@ -10142,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 @@ -10178,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: @@ -10209,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 @@ -10271,8 +7529,6 @@ snapshots: dependencies: picomatch: 2.3.1 - reading-time@1.5.0: {} - redent@3.0.0: dependencies: indent-string: 4.0.0 @@ -10334,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: {} @@ -10432,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 @@ -10455,8 +7639,6 @@ snapshots: dependencies: queue-microtask: 1.2.3 - rw@1.3.3: {} - sade@1.8.1: dependencies: mri: 1.2.0 @@ -10478,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: @@ -10594,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 @@ -10626,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: @@ -10670,8 +7823,6 @@ snapshots: dependencies: through: 2.3.8 - sprintf-js@1.0.3: {} - stackback@0.0.2: {} std-env@3.7.0: {} @@ -10685,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 @@ -10746,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 @@ -10759,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: {} @@ -10777,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 @@ -10800,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 @@ -10824,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: {} @@ -10894,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: @@ -10919,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: {} @@ -10942,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) @@ -11065,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: {} @@ -11080,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: {} @@ -11196,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 @@ -11212,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 @@ -11305,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: {} @@ -11431,16 +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-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,