Skip to content

Commit e9656f8

Browse files
authored
feat: add wsrv.nl provider (#176)
* Add wsrv.nl provider * Re-work * Fix keyMap and test issue, add to async provider map
1 parent 5989f63 commit e9656f8

File tree

10 files changed

+343
-3
lines changed

10 files changed

+343
-3
lines changed

data/domains.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@
1111
"assets.caisy.io": "bunny",
1212
"images.contentstack.io": "contentstack",
1313
"ucarecdn.com": "uploadcare",
14-
"imagedelivery.net": "cloudflare_images"
14+
"imagedelivery.net": "cloudflare_images",
15+
"wsrv.nl": "wsrv"
1516
}

demo/src/examples.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,5 +95,9 @@
9595
"appwrite": [
9696
"Appwrite",
9797
"https://cloud.appwrite.io/v1/storage/buckets/unpic/files/679d127100131f67b6d8/view?project=unpic-test"
98+
],
99+
"wsrv": [
100+
"wsrv.nl",
101+
"https://wsrv.nl/?url=images.unsplash.com/photo-1560807707-8cc77767d783"
98102
]
99103
}

deno.jsonc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"./providers/supabase": "./src/providers/supabase.ts",
3030
"./providers/uploadcare": "./src/providers/uploadcare.ts",
3131
"./providers/vercel": "./src/providers/vercel.ts",
32-
"./providers/wordpress": "./src/providers/wordpress.ts"
32+
"./providers/wordpress": "./src/providers/wordpress.ts",
33+
"./providers/wsrv": "./src/providers/wsrv.ts"
3334
},
3435
"tasks": {
3536
"build:npm": "deno run --allow-all scripts/build_npm.ts"

src/async.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const asyncProviderMap: AsyncProviderMap = {
4040
uploadcare: () => import("./providers/uploadcare.ts"),
4141
vercel: () => import("./providers/vercel.ts"),
4242
wordpress: () => import("./providers/wordpress.ts"),
43+
wsrv: () => import("./providers/wsrv.ts"),
4344
};
4445

4546
/**

src/extract.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { extract as supabase } from "./providers/supabase.ts";
3333
import { extract as uploadcare } from "./providers/uploadcare.ts";
3434
import { extract as vercel } from "./providers/vercel.ts";
3535
import { extract as wordpress } from "./providers/wordpress.ts";
36+
import { extract as wsrv } from "./providers/wsrv.ts";
3637

3738
export const parsers: URLExtractorMap = {
3839
appwrite,
@@ -62,6 +63,7 @@ export const parsers: URLExtractorMap = {
6263
uploadcare,
6364
vercel,
6465
wordpress,
66+
wsrv,
6567
} as const;
6668

6769
/**

src/providers/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import type { SupabaseOperations } from "./supabase.ts";
3737
import type { UploadcareOperations, UploadcareOptions } from "./uploadcare.ts";
3838
import type { VercelOperations, VercelOptions } from "./vercel.ts";
3939
import type { WordPressOperations } from "./wordpress.ts";
40+
import type { WsrvOperations } from "./wsrv.ts";
4041

4142
export interface ProviderOperations {
4243
appwrite: AppwriteOperations;
@@ -66,6 +67,7 @@ export interface ProviderOperations {
6667
uploadcare: UploadcareOperations;
6768
vercel: VercelOperations;
6869
wordpress: WordPressOperations;
70+
wsrv: WsrvOperations;
6971
}
7072

7173
export interface ProviderOptions {
@@ -96,6 +98,7 @@ export interface ProviderOptions {
9698
uploadcare: UploadcareOptions;
9799
vercel: VercelOptions;
98100
wordpress: undefined;
101+
wsrv: undefined;
99102
}
100103

101104
export type URLExtractorMap = {

src/providers/wsrv.test.ts

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import { extract, generate, transform } from "./wsrv.ts";
2+
import { assertEqualIgnoringQueryOrder } from "../test-utils.ts";
3+
import { assertEquals } from "jsr:@std/assert";
4+
5+
const img = "https://example.com/image.jpg";
6+
7+
Deno.test("wsrv extract", async (t) => {
8+
await t.step("should parse a basic wsrv URL", () => {
9+
const { operations, src } = extract(
10+
"https://wsrv.nl/?url=example.com/image.jpg",
11+
) ?? {};
12+
assertEquals(src, "https://example.com/image.jpg");
13+
assertEquals(operations, {});
14+
});
15+
16+
await t.step("should parse operations from URL", () => {
17+
const { operations, src } = extract(
18+
"https://wsrv.nl/?url=example.com/image.jpg&w=300&h=200&q=85&output=webp&fit=cover",
19+
) ?? {};
20+
assertEquals(src, "https://example.com/image.jpg");
21+
assertEquals(operations?.width, 300);
22+
assertEquals(operations?.height, 200);
23+
assertEquals(operations?.quality, 85);
24+
assertEquals(operations?.format, "webp");
25+
assertEquals(operations?.fit, "cover");
26+
});
27+
28+
await t.step("should return null for non-wsrv URLs", () => {
29+
const result = extract("https://example.com/image.jpg");
30+
assertEquals(result, null);
31+
});
32+
});
33+
34+
Deno.test("wsrv generate", async (t) => {
35+
await t.step("should format a URL with width and height", () => {
36+
const result = generate(img, {
37+
width: 300,
38+
height: 200,
39+
});
40+
assertEqualIgnoringQueryOrder(
41+
result,
42+
"https://wsrv.nl/?url=example.com/image.jpg&w=300&h=200&fit=cover",
43+
);
44+
});
45+
46+
await t.step("should not set height if not provided", () => {
47+
const result = generate(img, { width: 300 });
48+
assertEqualIgnoringQueryOrder(
49+
result,
50+
"https://wsrv.nl/?url=example.com/image.jpg&w=300&fit=cover",
51+
);
52+
});
53+
54+
await t.step("should format a URL with quality", () => {
55+
const result = generate(img, { width: 600, quality: 80 });
56+
assertEqualIgnoringQueryOrder(
57+
result,
58+
"https://wsrv.nl/?url=example.com/image.jpg&w=600&q=80&fit=cover",
59+
);
60+
});
61+
62+
await t.step("should format a URL with format conversion", () => {
63+
const result = generate(img, { width: 400, format: "webp" });
64+
assertEqualIgnoringQueryOrder(
65+
result,
66+
"https://wsrv.nl/?url=example.com/image.jpg&w=400&output=webp&fit=cover",
67+
);
68+
});
69+
70+
await t.step("should apply default fit=cover", () => {
71+
const result = generate(img, { width: 300 });
72+
assertEqualIgnoringQueryOrder(
73+
result,
74+
"https://wsrv.nl/?url=example.com/image.jpg&w=300&fit=cover",
75+
);
76+
});
77+
78+
await t.step("should allow overriding fit parameter", () => {
79+
const result = generate(img, { width: 300, fit: "contain" });
80+
assertEqualIgnoringQueryOrder(
81+
result,
82+
"https://wsrv.nl/?url=example.com/image.jpg&w=300&fit=contain",
83+
);
84+
});
85+
86+
await t.step("should format a URL with provider-specific operations", () => {
87+
const result = generate(img, { width: 300, dpr: 2, blur: 5 });
88+
assertEqualIgnoringQueryOrder(
89+
result,
90+
"https://wsrv.nl/?url=example.com/image.jpg&w=300&dpr=2&blur=5&fit=cover",
91+
);
92+
});
93+
});
94+
95+
Deno.test("wsrv transform", async (t) => {
96+
await t.step("should format a URL with width and height", () => {
97+
const result = transform(img, {
98+
width: 200,
99+
height: 100,
100+
});
101+
assertEqualIgnoringQueryOrder(
102+
result,
103+
"https://wsrv.nl/?url=example.com/image.jpg&w=200&h=100&fit=cover",
104+
);
105+
});
106+
107+
await t.step("should not set height if not provided", () => {
108+
const result = transform(img, { width: 200 });
109+
assertEqualIgnoringQueryOrder(
110+
result,
111+
"https://wsrv.nl/?url=example.com/image.jpg&w=200&fit=cover",
112+
);
113+
});
114+
115+
await t.step("should apply defaults to URL", () => {
116+
const result = transform(
117+
"https://wsrv.nl/?url=example.com/image.jpg&w=300",
118+
{},
119+
);
120+
assertEqualIgnoringQueryOrder(
121+
result,
122+
"https://wsrv.nl/?url=example.com/image.jpg&w=300&fit=cover",
123+
);
124+
});
125+
126+
await t.step("should override existing parameters", () => {
127+
const result = transform(
128+
"https://wsrv.nl/?url=example.com/image.jpg&w=300&fit=inside",
129+
{ fit: "contain" },
130+
);
131+
assertEqualIgnoringQueryOrder(
132+
result,
133+
"https://wsrv.nl/?url=example.com/image.jpg&w=300&fit=contain",
134+
);
135+
});
136+
});

0 commit comments

Comments
 (0)