diff --git a/README.md b/README.md index 64b33eb..dd0ca49 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ is not auto-detected. - Storyblok - Vercel / Next.js - WordPress.com and Jetpack Site Accelerator +- BaseHub ## Delegated URLs diff --git a/data/domains.json b/data/domains.json index 2ae07b9..79bcd29 100644 --- a/data/domains.json +++ b/data/domains.json @@ -11,5 +11,6 @@ "assets.caisy.io": "bunny", "images.contentstack.io": "contentstack", "ucarecdn.com": "uploadcare", - "imagedelivery.net": "cloudflare_images" + "imagedelivery.net": "cloudflare_images", + "assets.basehub.com": "basehub" } diff --git a/demo/src/examples.json b/demo/src/examples.json index fc865e6..f4e752c 100644 --- a/demo/src/examples.json +++ b/demo/src/examples.json @@ -87,5 +87,9 @@ "hygraph": [ "Hygraph", "https://us-west-2.graphassets.com/cm2apl1zp07l506n66dmd9xo8/cm2tr64fx7gvu07n85chjmuno" + ], + "basehub": [ + "BaseHub", + "https://assets.basehub.com/fa068a12/qZeFxPJWNB7UQdwUzjX3e/features-streamlined-team-communication-real-time-messaging-(light-mode)3x.jpg" ] } diff --git a/src/parse.ts b/src/parse.ts index 4e8892c..132e14d 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -25,6 +25,7 @@ import { parse as imagekit } from "./transformers/imagekit.ts"; import { parse as uploadcare } from "./transformers/uploadcare.ts"; import { parse as supabase } from "./transformers/supabase.ts"; import { parse as hygraph } from "./transformers/hygraph.ts"; +import { parse as basehub } from "./transformers/basehub.ts"; import { ImageCdn, ParsedUrl, SupportedImageCdn, UrlParser } from "./types.ts"; export const parsers = { @@ -54,6 +55,7 @@ export const parsers = { uploadcare, supabase, hygraph, + basehub, }; export const cdnIsSupportedForParse = ( diff --git a/src/transform.ts b/src/transform.ts index bc3d387..e74f49c 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -25,6 +25,7 @@ import { transform as imagekit } from "./transformers/imagekit.ts"; import { transform as uploadcare } from "./transformers/uploadcare.ts"; import { transform as supabase } from "./transformers/supabase.ts"; import { transform as hygraph } from "./transformers/hygraph.ts"; +import { transform as basehub } from "./transformers/basehub.ts"; import { ImageCdn, UrlTransformer } from "./types.ts"; import { getCanonicalCdnForUrl } from "./canonical.ts"; @@ -55,6 +56,7 @@ export const getTransformer = (cdn: ImageCdn) => ({ uploadcare, supabase, hygraph, + basehub, }[cdn]); /** diff --git a/src/transformers/basehub.test.ts b/src/transformers/basehub.test.ts new file mode 100644 index 0000000..408ad43 --- /dev/null +++ b/src/transformers/basehub.test.ts @@ -0,0 +1,50 @@ +import { assertEquals } from "jsr:@std/assert"; + +import { transform } from "./basehub.ts"; + +const img = + "https://assets.basehub.com/fa068a12/qZeFxPJWNB7UQdwUzjX3e/features-streamlined-team-communication-real-time-messaging-(light-mode)3x.jpg"; + +Deno.test("basehub", async (t) => { + await t.step("should format a URL", () => { + const result = transform({ + url: img, + width: 200, + height: 100, + }); + assertEquals( + result?.toString(), + "https://assets.basehub.com/fa068a12/qZeFxPJWNB7UQdwUzjX3e/features-streamlined-team-communication-real-time-messaging-(light-mode)3x.jpg?w=200&h=100&fit=cover", + ); + }); + await t.step("should not set height if not provided", () => { + const result = transform({ url: img, width: 200 }); + assertEquals( + result?.toString(), + "https://assets.basehub.com/fa068a12/qZeFxPJWNB7UQdwUzjX3e/features-streamlined-team-communication-real-time-messaging-(light-mode)3x.jpg?w=200", + ); + }); + + await t.step("should delete height if not set", () => { + const url = new URL(img); + url.searchParams.set("h", "100"); + const result = transform({ url, width: 200 }); + assertEquals( + result?.toString(), + "https://assets.basehub.com/fa068a12/qZeFxPJWNB7UQdwUzjX3e/features-streamlined-team-communication-real-time-messaging-(light-mode)3x.jpg?w=200", + ); + }); + + await t.step("should round non-integer params", () => { + const result = transform({ + url: img, + width: 200.6, + height: 100.2, + format: "webp", + }); + assertEquals( + result?.toString(), + "https://assets.basehub.com/fa068a12/qZeFxPJWNB7UQdwUzjX3e/features-streamlined-team-communication-real-time-messaging-(light-mode)3x.jpg?w=201&h=100&format=webp&fit=cover", + ); + }); +}); diff --git a/src/transformers/basehub.ts b/src/transformers/basehub.ts new file mode 100644 index 0000000..54c8666 --- /dev/null +++ b/src/transformers/basehub.ts @@ -0,0 +1,42 @@ +import { UrlParser, UrlTransformer } from "../types.ts"; +import { + getNumericParam, + setParamIfDefined, + setParamIfUndefined, + toUrl, +} from "../utils.ts"; + +export const parse: UrlParser<{ fit?: string }> = (url) => { + const parsedUrl = toUrl(url); + + const fit = parsedUrl.searchParams.get("fit") || "cover"; + const width = getNumericParam(parsedUrl, "w"); + const height = getNumericParam(parsedUrl, "h"); + const quality = getNumericParam(parsedUrl, "q"); + const format = parsedUrl.searchParams.get("format") || undefined; + parsedUrl.search = ""; + return { + width, + height, + format, + base: parsedUrl.toString(), + params: { fit, quality }, + cdn: "basehub", + }; +}; + +export const transform: UrlTransformer = ( + { url: originalUrl, width, height, format }, +) => { + const url = toUrl(originalUrl); + + setParamIfDefined(url, "w", width, true, true); + setParamIfDefined(url, "h", height, true, true); + setParamIfDefined(url, "format", format === "jpg" ? "jpeg" : format); + + if (width && height) { + setParamIfUndefined(url, "fit", "cover"); + } + + return url; +}; diff --git a/src/types.ts b/src/types.ts index 8fc70bc..cd8fd15 100644 --- a/src/types.ts +++ b/src/types.ts @@ -101,6 +101,7 @@ export type ImageCdn = | "imagekit" | "uploadcare" | "supabase" - | "hygraph"; + | "hygraph" + | "basehub"; export type SupportedImageCdn = ImageCdn;