diff --git a/README.md b/README.md index fe5dd65..30d26bd 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,7 @@ is not auto-detected. - Bunny.net - Storyblok - Cloudflare +- Kontent.ai ## FAQs diff --git a/data/subdomains.json b/data/subdomains.json index 51d2d17..cc4c973 100644 --- a/data/subdomains.json +++ b/data/subdomains.json @@ -2,5 +2,6 @@ "imgix.net": "imgix", "files.wordpress.com": "wordpress", "b-cdn.net": "bunny", - "storyblok.com": "storyblok" + "storyblok.com": "storyblok", + "kc-usercontent.com": "kontent.ai" } diff --git a/demo/src/examples.json b/demo/src/examples.json index 2e81dd5..0556972 100644 --- a/demo/src/examples.json +++ b/demo/src/examples.json @@ -34,5 +34,9 @@ [ "Cloudflare", "https://assets.brevity.io/cdn-cgi/image/background=red,width=128,height=128,f=auto/uploads/generic/avatar-sample.jpeg" + ], + [ + "Kontent.ai", + "https://assets-us-01.kc-usercontent.com/b744f382-bfc7-434d-93e7-a65d51249bc7/cc0afdc7-23d7-4fde-be2c-f58ad54d2934/daylight.jpg" ] ] diff --git a/src/transform.ts b/src/transform.ts index b00a0f6..124c99a 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -8,6 +8,7 @@ import { transform as cloudinary } from "./transformers/cloudinary.ts"; import { transform as cloudflare } from "./transformers/cloudflare.ts"; import { transform as bunny } from "./transformers/bunny.ts"; import { transform as storyblok } from "./transformers/storyblok.ts"; +import { transform as kontentai } from "./transformers/kontentai.ts"; import { ImageCdn, SupportedImageCdn, UrlTransformer } from "./types.ts"; export const transformers = { @@ -20,6 +21,7 @@ export const transformers = { bunny, storyblok, cloudflare, + "kontent.ai": kontentai }; export const cdnIsSupportedForTransform = ( diff --git a/src/transformers/kontentai.test.ts b/src/transformers/kontentai.test.ts new file mode 100644 index 0000000..a541232 --- /dev/null +++ b/src/transformers/kontentai.test.ts @@ -0,0 +1,65 @@ +import { assertEquals } from "https://deno.land/std@0.172.0/testing/asserts.ts"; + +import { transform } from "./kontentai.ts"; + +const img = + "https://assets-us-01.kc-usercontent.com/b744f382-bfc7-434d-93e7-a65d51249bc7/cc0afdc7-23d7-4fde-be2c-f58ad54d2934/daylight.jpg" + +Deno.test("kontent.ai", async (t) => { + await t.step("should format a URL", () => { + const result = transform({ + url: img, + width: 200, + height: 100, + format: 'webp' + }); + assertEquals( + result?.toString(), + "https://assets-us-01.kc-usercontent.com/b744f382-bfc7-434d-93e7-a65d51249bc7/cc0afdc7-23d7-4fde-be2c-f58ad54d2934/daylight.jpg?w=200&h=100&fm=webp&fit=crop", + ); + }); + await t.step("should not set height if not provided", () => { + const result = transform({ url: img, width: 200 }); + assertEquals( + result?.toString(), + "https://assets-us-01.kc-usercontent.com/b744f382-bfc7-434d-93e7-a65d51249bc7/cc0afdc7-23d7-4fde-be2c-f58ad54d2934/daylight.jpg?w=200&fit=crop", + ); + }); + + await t.step("should round non-integer params", () => { + const result = transform({ + url: img, + width: 200.6, + height: 100.2, + }); + assertEquals( + result?.toString(), + "https://assets-us-01.kc-usercontent.com/b744f382-bfc7-434d-93e7-a65d51249bc7/cc0afdc7-23d7-4fde-be2c-f58ad54d2934/daylight.jpg?w=201&h=100&fit=crop", + ); + }); + + await t.step("should add fit=scale when height or width (or both) provided and no other fit setting", () => { + const result = transform({ + url: img, + width: 200, + height: 100, + }); + assertEquals( + result?.toString(), + "https://assets-us-01.kc-usercontent.com/b744f382-bfc7-434d-93e7-a65d51249bc7/cc0afdc7-23d7-4fde-be2c-f58ad54d2934/daylight.jpg?w=200&h=100&fit=crop", + ); + }); + await t.step("should not set fit=scale if another value exists", () => { + const url = new URL(img); + url.searchParams.set("fit", "scale"); + const result = transform({ + url: url, + width: 200, + height: 100 + }); + assertEquals( + result?.toString(), + "https://assets-us-01.kc-usercontent.com/b744f382-bfc7-434d-93e7-a65d51249bc7/cc0afdc7-23d7-4fde-be2c-f58ad54d2934/daylight.jpg?fit=scale&w=200&h=100", + ); + }); +}); diff --git a/src/transformers/kontentai.ts b/src/transformers/kontentai.ts new file mode 100644 index 0000000..6fb8a46 --- /dev/null +++ b/src/transformers/kontentai.ts @@ -0,0 +1,39 @@ +import { UrlParser, UrlTransformer } from "../types.ts"; +import { + getNumericParam, + setParamIfDefined, + setParamIfUndefined +} from "../utils.ts"; + +export const parse: UrlParser<{ fit?: string }> = (url) => { + const parsedUrl = new URL(url); + + const fit = parsedUrl.searchParams.get("fit") || undefined; + const width = getNumericParam(parsedUrl, "w"); + const height = getNumericParam(parsedUrl, "h"); + const quality = getNumericParam(parsedUrl, "q"); + const format = parsedUrl.searchParams.get("fm") || undefined; + + parsedUrl.search = ""; + return { + width, + height, + format, + base: parsedUrl.toString(), + params: { fit, quality }, + cdn: "kontent.ai", + }; +}; + +export const transform: UrlTransformer = ( + { url: originalUrl, width, height, format }, +) => { + const url = new URL(originalUrl); + setParamIfDefined(url, "w", width, true, true); + setParamIfDefined(url, "h", height, true, true); + setParamIfDefined(url, "fm", format, true); + if (width || height) { + setParamIfUndefined(url, "fit", "crop"); + } + return url; +}; diff --git a/src/types.ts b/src/types.ts index 5a85175..eea4bf8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -61,6 +61,7 @@ export type ImageCdn = | "shopify" | "wordpress" | "bunny" - | "storyblok"; + | "storyblok" + | "kontent.ai"; export type SupportedImageCdn = ImageCdn;