Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Directus support #46

Merged
merged 6 commits into from
Apr 22, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: add directus assets transformer
danestves committed Apr 19, 2023
commit 1441b8755ee98f885ae11e7204959292afcdff20
3 changes: 2 additions & 1 deletion data/paths.json
Original file line number Diff line number Diff line change
@@ -3,5 +3,6 @@
"/_next/image": "nextjs",
"/_next/static": "nextjs",
"/_vercel/image": "vercel",
"/is/image": "scene7"
"/is/image": "scene7",
"/assets": "directus"
}
4 changes: 4 additions & 0 deletions demo/src/examples.json
Original file line number Diff line number Diff line change
@@ -50,5 +50,9 @@
[
"KeyCDN",
"https://ip.keycdn.com/example.jpg"
],
[
"Directus",
"https://marketing.directus.app/assets/852ad2fc-0d8c-4f12-9adb-edcf0b99cd00"
]
]
2 changes: 2 additions & 0 deletions src/transform.ts
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ import { transform as vercel } from "./transformers/vercel.ts";
import { transform as nextjs } from "./transformers/nextjs.ts";
import { transform as scene7 } from "./transformers/scene7.ts";
import { transform as keycdn } from "./transformers/keycdn.ts";
import { transform as directus } from "./transformers/directus.ts";
import { ImageCdn, UrlTransformer } from "./types.ts";

export const getTransformer = (cdn: ImageCdn) => ({
@@ -30,6 +31,7 @@ export const getTransformer = (cdn: ImageCdn) => ({
scene7,
"kontent.ai": kontentai,
keycdn,
directus,
}[cdn]);

/**
80 changes: 80 additions & 0 deletions src/transformers/directus.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { assertEquals } from "https://deno.land/std@0.172.0/testing/asserts.ts";

import { DirectusParams, parse, transform } from "./directus.ts";
import { ParsedUrl } from "../types.ts";
import { getImageCdnForUrl } from "../detect.ts";

const img =
"https://marketing.directus.app/assets/852ad2fc-0d8c-4f12-9adb-edcf0b99cd00";
const imgNoTransforms = img;
const imgWithQuality = `${img}?quality=30`;
const imgOverrideEnlargement = `${img}?withoutEnlargement=true`;

Deno.test("directus", async (t) => {
await t.step("should overwrite format", () => {
const result = transform({
url: img,
width: 200,
height: 200,
format: "png",
cdn: "directus",
});
assertEquals(
result?.toString(),
`${img}?width=200&height=200&format=png`,
);
});

await t.step("should return quality", () => {
const result = transform({
url: imgWithQuality,
width: 200,
height: 200,
format: "png",
cdn: "directus",
});
assertEquals(
result?.toString(),
`${img}?quality=30&width=200&height=200&format=png`,
);
});

await t.step(
"should not override and match any domain that continue with /assets subpath",
() => {
const result = transform({
url: imgOverrideEnlargement,
width: 400,
height: 600,
});
assertEquals(
result?.toString(),
`${img}?withoutEnlargement=true&width=400&height=600&format=auto`,
);
},
);

await t.step("parses image with base transforms", () => {
const parsed = parse(imgNoTransforms);
const expected: ParsedUrl<DirectusParams> = {
base: imgNoTransforms,
cdn: "directus",
format: "auto",
width: 0,
height: 0,
params: {
fit: undefined,
quality: undefined,
withoutEnlargement: undefined,
transforms: undefined,
},
};
assertEquals(parsed, expected);
});

await t.step("url detection example image", () => {
const detected = getImageCdnForUrl(img);
const expected = "directus";
assertEquals(detected, expected);
});
});
64 changes: 64 additions & 0 deletions src/transformers/directus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { UrlParser, UrlTransformer } from "../types.ts";
import { getNumericParam, setParamIfDefined } from "../utils.ts";

type Fit = "cover" | "contain" | "inside" | "outside";

export interface DirectusParams {
fit?: Fit;
quality?: number;
withoutEnlargement?: boolean;
/**
* For even more advanced control over the file generation, Directus exposes the [full `sharp` API](https://sharp.pixelplumbing.com/api-operation).
*
* @example
*
* ?transforms=[["blur",45],["resize",{"width":200,"height":200}]]
*/
transforms?: Array<
Array<string | number | boolean | Record<string, unknown>>
>;
}

export const parse: UrlParser<DirectusParams> = (imageUrl) => {
const parsedUrl = new URL(imageUrl);

const width = getNumericParam(parsedUrl, "width");
const height = getNumericParam(parsedUrl, "height");
const format = parsedUrl.searchParams.get("format") || "auto"; // We must set this to `auto` because Directus doesn't have a default value for this parameter.
const quality = getNumericParam(parsedUrl, "quality") || undefined;
let fit: Fit | undefined = parsedUrl.searchParams.get("fit") as Fit ||
undefined;
const withoutEnlargement =
parsedUrl.searchParams.get("withoutEnlargement") === "true" || undefined;
const transforms = parsedUrl.searchParams.get("transforms") || undefined;

// if fit doesn't satisfy the type, it will be undefined
if (fit && !["cover", "contain", "inside", "outside"].includes(fit)) {
fit = undefined;
}

return {
width,
height,
format,
base: parsedUrl.toString(),
params: {
fit,
quality,
withoutEnlargement,
transforms: transforms ? JSON.parse(transforms) : undefined,
},
cdn: "directus",
};
};

export const transform: UrlTransformer = (
{ url: originalUrl, width, height, format = "auto" },
) => {
const url = new URL(originalUrl);
setParamIfDefined(url, "width", width, true, true);
setParamIfDefined(url, "height", height, true, true);
setParamIfDefined(url, "format", format, true);
setParamIfDefined(url, "quality", getNumericParam(url, "quality"), true);
return url;
};
3 changes: 2 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -66,6 +66,7 @@ export type ImageCdn =
| "vercel"
| "nextjs"
| "scene7"
| "keycdn";
| "keycdn"
| "directus";

export type SupportedImageCdn = ImageCdn;