@uxf/resizer 11.126.0 → 11.129.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.resizer-config.json +4 -4
  2. package/README.md +22 -12
  3. package/bin/uxf-resizer.js +20 -20
  4. package/bin/uxf-resizer.ts +19 -17
  5. package/package.json +4 -9
  6. package/src/handler.d.ts +10 -0
  7. package/src/handler.js +90 -0
  8. package/src/handler.test.js +65 -0
  9. package/src/handler.test.ts +79 -0
  10. package/src/handler.ts +121 -0
  11. package/src/utils/get-source-filename.d.ts +1 -1
  12. package/src/utils/get-source-filename.js +14 -15
  13. package/src/utils/get-source-filename.test.js +21 -0
  14. package/src/utils/get-source-filename.test.ts +33 -0
  15. package/src/utils/get-source-filename.ts +16 -16
  16. package/src/utils/match-route.d.ts +13 -0
  17. package/src/utils/match-route.js +38 -0
  18. package/src/utils/match-route.test.d.ts +1 -0
  19. package/src/utils/match-route.test.js +79 -0
  20. package/src/utils/match-route.test.ts +94 -0
  21. package/src/utils/match-route.ts +41 -0
  22. package/src/utils/tools.d.ts +10 -10
  23. package/src/utils/tools.js +2 -2
  24. package/src/utils/tools.test.d.ts +1 -0
  25. package/src/utils/tools.test.js +46 -0
  26. package/src/utils/tools.test.ts +48 -0
  27. package/src/utils/tools.ts +12 -11
  28. package/src/middleware.d.ts +0 -5
  29. package/src/middleware.js +0 -92
  30. package/src/middleware.ts +0 -73
  31. package/src/utils/parse-http-source.d.ts +0 -7
  32. package/src/utils/parse-http-source.js +0 -7
  33. package/src/utils/parse-http-source.test.js +0 -26
  34. package/src/utils/parse-http-source.test.ts +0 -25
  35. package/src/utils/parse-http-source.ts +0 -9
  36. package/src/utils/repair-params.d.ts +0 -8
  37. package/src/utils/repair-params.js +0 -19
  38. package/src/utils/repair-params.ts +0 -15
  39. /package/src/{utils/parse-http-source.test.d.ts → handler.test.d.ts} +0 -0
@@ -1,21 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getSourceFilename = getSourceFilename;
4
- const path_to_regexp_1 = require("path-to-regexp");
5
4
  const log_1 = require("./log");
6
- const parse_http_source_1 = require("./parse-http-source");
7
- const repair_params_1 = require("./repair-params");
5
+ /**
6
+ * `:name`, optionally followed by a path-to-regexp v6 modifier (`+`, `*`, `?`) that is ignored here –
7
+ * the matched value already contains any slashes. A name must start with a letter, so the port in
8
+ * `http://localhost:3000/...` is never mistaken for a parameter.
9
+ */
10
+ const PARAM_PATTERN = /:([A-Za-z_]\w*)[+*?]?/g;
8
11
  function getSourceFilename(source, params) {
9
- const parsedHttpSource = (0, parse_http_source_1.parseHttpSource)(source);
10
- const repairedParams = (0, repair_params_1.repairParams)(params);
11
- (0, log_1.log)(repairedParams);
12
- if (parsedHttpSource) {
13
- // escape port
14
- const domain = parsedHttpSource.domain.startsWith(":")
15
- ? parsedHttpSource.domain
16
- : parsedHttpSource.domain.replace(":", "\\:");
17
- const compiled = (0, path_to_regexp_1.compile)(`/${domain}/${parsedHttpSource.path}`, {})(repairedParams);
18
- return `${parsedHttpSource.protocol}:/${compiled}`;
19
- }
20
- return (0, path_to_regexp_1.compile)(source, {})(repairedParams);
12
+ (0, log_1.log)(params);
13
+ return source.replace(PARAM_PATTERN, (_match, key) => {
14
+ const value = params[key];
15
+ if (value === undefined) {
16
+ throw new Error(`Missing parameter "${key}" for source "${source}"`);
17
+ }
18
+ return Array.isArray(value) ? value.join("/") : value;
19
+ });
21
20
  }
@@ -20,3 +20,24 @@ test("get source filename", () => {
20
20
  extension: "jpg",
21
21
  })).toStrictEqual("/var/www/path/to/file.jpg");
22
22
  });
23
+ test("accepts a string value containing slashes (what URLPattern yields for :filename(.*))", () => {
24
+ expect((0, get_source_filename_1.getSourceFilename)("https://static.example.dev/:filename+.:extension", {
25
+ filename: "_next/static/media/logo.941ec59a",
26
+ extension: "png",
27
+ })).toStrictEqual("https://static.example.dev/_next/static/media/logo.941ec59a.png");
28
+ });
29
+ test("ignores the * and ? modifiers", () => {
30
+ expect((0, get_source_filename_1.getSourceFilename)("/var/www/:dir*/:file?.:ext", { dir: "a/b", file: "c", ext: "png" })).toStrictEqual("/var/www/a/b/c.png");
31
+ });
32
+ test("keeps the uploaded-image source intact", () => {
33
+ expect((0, get_source_filename_1.getSourceFilename)("https://s3.example.dev/:namespace/:p1/:p2/:filename.:extension", {
34
+ namespace: "product",
35
+ p1: "0",
36
+ p2: "f",
37
+ filename: "0f1e2d3c-1111-2222-3333-444455556666",
38
+ extension: "jpg",
39
+ })).toStrictEqual("https://s3.example.dev/product/0/f/0f1e2d3c-1111-2222-3333-444455556666.jpg");
40
+ });
41
+ test("throws when a parameter is missing", () => {
42
+ expect(() => (0, get_source_filename_1.getSourceFilename)("/var/www/:filename.:extension", { filename: "x" })).toThrow('Missing parameter "extension"');
43
+ });
@@ -30,3 +30,36 @@ test("get source filename", () => {
30
30
  }),
31
31
  ).toStrictEqual("/var/www/path/to/file.jpg");
32
32
  });
33
+
34
+ test("accepts a string value containing slashes (what URLPattern yields for :filename(.*))", () => {
35
+ expect(
36
+ getSourceFilename("https://static.example.dev/:filename+.:extension", {
37
+ filename: "_next/static/media/logo.941ec59a",
38
+ extension: "png",
39
+ }),
40
+ ).toStrictEqual("https://static.example.dev/_next/static/media/logo.941ec59a.png");
41
+ });
42
+
43
+ test("ignores the * and ? modifiers", () => {
44
+ expect(getSourceFilename("/var/www/:dir*/:file?.:ext", { dir: "a/b", file: "c", ext: "png" })).toStrictEqual(
45
+ "/var/www/a/b/c.png",
46
+ );
47
+ });
48
+
49
+ test("keeps the uploaded-image source intact", () => {
50
+ expect(
51
+ getSourceFilename("https://s3.example.dev/:namespace/:p1/:p2/:filename.:extension", {
52
+ namespace: "product",
53
+ p1: "0",
54
+ p2: "f",
55
+ filename: "0f1e2d3c-1111-2222-3333-444455556666",
56
+ extension: "jpg",
57
+ }),
58
+ ).toStrictEqual("https://s3.example.dev/product/0/f/0f1e2d3c-1111-2222-3333-444455556666.jpg");
59
+ });
60
+
61
+ test("throws when a parameter is missing", () => {
62
+ expect(() => getSourceFilename("/var/www/:filename.:extension", { filename: "x" })).toThrow(
63
+ 'Missing parameter "extension"',
64
+ );
65
+ });
@@ -1,21 +1,21 @@
1
- import { compile } from "path-to-regexp";
2
1
  import { log } from "./log";
3
- import { parseHttpSource } from "./parse-http-source";
4
- import { repairParams } from "./repair-params";
5
2
 
6
- export function getSourceFilename(source: string, params: Record<string, any>): string {
7
- const parsedHttpSource = parseHttpSource(source);
8
- const repairedParams = repairParams(params);
9
- log(repairedParams);
3
+ /**
4
+ * `:name`, optionally followed by a path-to-regexp v6 modifier (`+`, `*`, `?`) that is ignored here –
5
+ * the matched value already contains any slashes. A name must start with a letter, so the port in
6
+ * `http://localhost:3000/...` is never mistaken for a parameter.
7
+ */
8
+ const PARAM_PATTERN = /:([A-Za-z_]\w*)[+*?]?/g;
10
9
 
11
- if (parsedHttpSource) {
12
- // escape port
13
- const domain = parsedHttpSource.domain.startsWith(":")
14
- ? parsedHttpSource.domain
15
- : parsedHttpSource.domain.replace(":", "\\:");
16
- const compiled = compile(`/${domain}/${parsedHttpSource.path}`, {})(repairedParams);
17
- return `${parsedHttpSource.protocol}:/${compiled}`;
18
- }
10
+ export function getSourceFilename(source: string, params: Partial<Record<string, string | string[]>>): string {
11
+ log(params);
19
12
 
20
- return compile(source, {})(repairedParams);
13
+ return source.replace(PARAM_PATTERN, (_match, key: string) => {
14
+ const value = params[key];
15
+ if (value === undefined) {
16
+ throw new Error(`Missing parameter "${key}" for source "${source}"`);
17
+ }
18
+
19
+ return Array.isArray(value) ? value.join("/") : value;
20
+ });
21
21
  }
@@ -0,0 +1,13 @@
1
+ import { Params } from "./tools";
2
+ /**
3
+ * Express 4 accepted `:name(*)` as "match anything, slashes included". URLPattern rejects a bare `*`
4
+ * inside a regexp group, so the legacy form is rewritten to the equivalent `(.*)`.
5
+ */
6
+ export declare function normalizeRoute(route: string): string;
7
+ /**
8
+ * Compiles a `route` from the resizer config into a matcher. The syntax is the one built into Node's
9
+ * `URLPattern` (path-to-regexp v6 compatible): `:name`, `:name(regexp)`, `:name+`, several parameters
10
+ * per segment. Matching is case-insensitive and the captured values are percent-decoded, mirroring the
11
+ * Express 4 router this replaced.
12
+ */
13
+ export declare function createRouteMatcher(route: string): (pathname: string) => Params | undefined;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeRoute = normalizeRoute;
4
+ exports.createRouteMatcher = createRouteMatcher;
5
+ const log_1 = require("./log");
6
+ const LEGACY_WILDCARD = "(*)";
7
+ /**
8
+ * Express 4 accepted `:name(*)` as "match anything, slashes included". URLPattern rejects a bare `*`
9
+ * inside a regexp group, so the legacy form is rewritten to the equivalent `(.*)`.
10
+ */
11
+ function normalizeRoute(route) {
12
+ if (!route.includes(LEGACY_WILDCARD)) {
13
+ return route;
14
+ }
15
+ (0, log_1.log)(`Route "${route}" uses the deprecated "(*)" group – use "(.*)" instead.`, "warn");
16
+ return route.replaceAll(LEGACY_WILDCARD, "(.*)");
17
+ }
18
+ /**
19
+ * Compiles a `route` from the resizer config into a matcher. The syntax is the one built into Node's
20
+ * `URLPattern` (path-to-regexp v6 compatible): `:name`, `:name(regexp)`, `:name+`, several parameters
21
+ * per segment. Matching is case-insensitive and the captured values are percent-decoded, mirroring the
22
+ * Express 4 router this replaced.
23
+ */
24
+ function createRouteMatcher(route) {
25
+ const pattern = new URLPattern({ pathname: normalizeRoute(route) }, { ignoreCase: true });
26
+ return (pathname) => {
27
+ var _a;
28
+ const groups = (_a = pattern.exec({ pathname })) === null || _a === void 0 ? void 0 : _a.pathname.groups;
29
+ if (groups === undefined) {
30
+ return undefined;
31
+ }
32
+ const params = {};
33
+ Object.entries(groups).forEach(([key, value]) => {
34
+ params[key] = value === undefined ? undefined : decodeURIComponent(value);
35
+ });
36
+ return params;
37
+ };
38
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * @jest-environment node
5
+ */
6
+ const match_route_1 = require("./match-route");
7
+ // the two shapes `resizerGetDefaultConfig` (@uxf/core) emits
8
+ const STATIC_ROUTE = "/generated/static/:width(\\d+|x)_:height(\\d+|x)_:fit([a-z]+)_:position([a-z]+)_:background([a-z]+)_:trim([a-z]+)_:quality(\\d+|x)/:version/:filename(.*).:extension.:toFormat";
9
+ const UPLOAD_ROUTE = "/generated/:namespace/:p1/:p2/:filename([a-f0-9\\-]+)_:width(\\d+|x)_:height(\\d+|x)_:fit([a-z]+)_:position([a-z]+)_:background([a-z]+)_:trim([a-z]+)_:quality(\\d+|x)_:extension.:toFormat";
10
+ test("matches the uploaded-image route produced by resizerImageUrl", () => {
11
+ const match = (0, match_route_1.createRouteMatcher)(UPLOAD_ROUTE);
12
+ expect(match("/generated/product/0/f/0f1e2d3c-1111-2222-3333-444455556666_300_x_cv_c_FFF_nt_80_jpg.webp")).toEqual({
13
+ namespace: "product",
14
+ p1: "0",
15
+ p2: "f",
16
+ filename: "0f1e2d3c-1111-2222-3333-444455556666",
17
+ width: "300",
18
+ height: "x",
19
+ fit: "cv",
20
+ position: "c",
21
+ background: "FFF",
22
+ trim: "nt",
23
+ quality: "80",
24
+ extension: "jpg",
25
+ toFormat: "webp",
26
+ });
27
+ });
28
+ test("matches the static route with a nested, dotted filename", () => {
29
+ const match = (0, match_route_1.createRouteMatcher)(STATIC_ROUTE);
30
+ expect(match("/generated/static/300_200_cv_c_t_nt_x/1/_next/static/media/logo.941ec59a.png.avif")).toEqual({
31
+ width: "300",
32
+ height: "200",
33
+ fit: "cv",
34
+ position: "c",
35
+ background: "t",
36
+ trim: "nt",
37
+ quality: "x",
38
+ version: "1",
39
+ filename: "_next/static/media/logo.941ec59a",
40
+ extension: "png",
41
+ toFormat: "avif",
42
+ });
43
+ });
44
+ test("legacy (*) group matches exactly like (.*)", () => {
45
+ const warnSpy = jest.spyOn(console, "warn").mockImplementation(() => undefined);
46
+ const legacy = (0, match_route_1.createRouteMatcher)(STATIC_ROUTE.replace("(.*)", "(*)"));
47
+ const current = (0, match_route_1.createRouteMatcher)(STATIC_ROUTE);
48
+ const pathname = "/generated/static/x_x_cn_lt_FFF_nt_75/3/images/deep/dir/file.name.jpg.webp";
49
+ expect(warnSpy).toHaveBeenCalledTimes(1);
50
+ warnSpy.mockRestore();
51
+ expect(legacy(pathname)).toEqual(current(pathname));
52
+ expect(current(pathname)).toMatchObject({
53
+ filename: "images/deep/dir/file.name",
54
+ extension: "jpg",
55
+ toFormat: "webp",
56
+ });
57
+ });
58
+ test("normalizeRoute rewrites every (*) and leaves other routes alone", () => {
59
+ expect((0, match_route_1.normalizeRoute)("/a/:x(*)/:y(*)")).toBe("/a/:x(.*)/:y(.*)");
60
+ expect((0, match_route_1.normalizeRoute)(STATIC_ROUTE)).toBe(STATIC_ROUTE);
61
+ });
62
+ test("matching is case-insensitive (background FFF against [a-z]+)", () => {
63
+ const match = (0, match_route_1.createRouteMatcher)("/x/:background([a-z]+)");
64
+ expect(match("/x/FFF")).toEqual({ background: "FFF" });
65
+ expect(match("/X/fff")).toEqual({ background: "fff" });
66
+ });
67
+ test("percent-decodes captured values", () => {
68
+ const match = (0, match_route_1.createRouteMatcher)("/files/:filename(.*).:extension");
69
+ expect(match("/files/My%20Photo.jpg")).toEqual({ filename: "My Photo", extension: "jpg" });
70
+ });
71
+ test("returns undefined when the path does not match", () => {
72
+ const match = (0, match_route_1.createRouteMatcher)(UPLOAD_ROUTE);
73
+ expect(match("/generated/static/300_200/x.png.webp")).toBeUndefined();
74
+ expect(match("/generated/product/0/f/not-a-uuid_300_x_cv_c_FFF_nt_80_jpg.webp")).toBeUndefined();
75
+ expect(match("/generated/product/0/f/0f1e2d3c_abc_x_cv_c_FFF_nt_80_jpg.webp")).toBeUndefined();
76
+ });
77
+ test("throws on an invalid route at construction time", () => {
78
+ expect(() => (0, match_route_1.createRouteMatcher)("/x/:a([")).toThrow();
79
+ });
@@ -0,0 +1,94 @@
1
+ /**
2
+ * @jest-environment node
3
+ */
4
+ import { createRouteMatcher, normalizeRoute } from "./match-route";
5
+
6
+ // the two shapes `resizerGetDefaultConfig` (@uxf/core) emits
7
+ const STATIC_ROUTE =
8
+ "/generated/static/:width(\\d+|x)_:height(\\d+|x)_:fit([a-z]+)_:position([a-z]+)_:background([a-z]+)_:trim([a-z]+)_:quality(\\d+|x)/:version/:filename(.*).:extension.:toFormat";
9
+ const UPLOAD_ROUTE =
10
+ "/generated/:namespace/:p1/:p2/:filename([a-f0-9\\-]+)_:width(\\d+|x)_:height(\\d+|x)_:fit([a-z]+)_:position([a-z]+)_:background([a-z]+)_:trim([a-z]+)_:quality(\\d+|x)_:extension.:toFormat";
11
+
12
+ test("matches the uploaded-image route produced by resizerImageUrl", () => {
13
+ const match = createRouteMatcher(UPLOAD_ROUTE);
14
+
15
+ expect(match("/generated/product/0/f/0f1e2d3c-1111-2222-3333-444455556666_300_x_cv_c_FFF_nt_80_jpg.webp")).toEqual({
16
+ namespace: "product",
17
+ p1: "0",
18
+ p2: "f",
19
+ filename: "0f1e2d3c-1111-2222-3333-444455556666",
20
+ width: "300",
21
+ height: "x",
22
+ fit: "cv",
23
+ position: "c",
24
+ background: "FFF",
25
+ trim: "nt",
26
+ quality: "80",
27
+ extension: "jpg",
28
+ toFormat: "webp",
29
+ });
30
+ });
31
+
32
+ test("matches the static route with a nested, dotted filename", () => {
33
+ const match = createRouteMatcher(STATIC_ROUTE);
34
+
35
+ expect(match("/generated/static/300_200_cv_c_t_nt_x/1/_next/static/media/logo.941ec59a.png.avif")).toEqual({
36
+ width: "300",
37
+ height: "200",
38
+ fit: "cv",
39
+ position: "c",
40
+ background: "t",
41
+ trim: "nt",
42
+ quality: "x",
43
+ version: "1",
44
+ filename: "_next/static/media/logo.941ec59a",
45
+ extension: "png",
46
+ toFormat: "avif",
47
+ });
48
+ });
49
+
50
+ test("legacy (*) group matches exactly like (.*)", () => {
51
+ const warnSpy = jest.spyOn(console, "warn").mockImplementation(() => undefined);
52
+ const legacy = createRouteMatcher(STATIC_ROUTE.replace("(.*)", "(*)"));
53
+ const current = createRouteMatcher(STATIC_ROUTE);
54
+ const pathname = "/generated/static/x_x_cn_lt_FFF_nt_75/3/images/deep/dir/file.name.jpg.webp";
55
+
56
+ expect(warnSpy).toHaveBeenCalledTimes(1);
57
+ warnSpy.mockRestore();
58
+ expect(legacy(pathname)).toEqual(current(pathname));
59
+ expect(current(pathname)).toMatchObject({
60
+ filename: "images/deep/dir/file.name",
61
+ extension: "jpg",
62
+ toFormat: "webp",
63
+ });
64
+ });
65
+
66
+ test("normalizeRoute rewrites every (*) and leaves other routes alone", () => {
67
+ expect(normalizeRoute("/a/:x(*)/:y(*)")).toBe("/a/:x(.*)/:y(.*)");
68
+ expect(normalizeRoute(STATIC_ROUTE)).toBe(STATIC_ROUTE);
69
+ });
70
+
71
+ test("matching is case-insensitive (background FFF against [a-z]+)", () => {
72
+ const match = createRouteMatcher("/x/:background([a-z]+)");
73
+
74
+ expect(match("/x/FFF")).toEqual({ background: "FFF" });
75
+ expect(match("/X/fff")).toEqual({ background: "fff" });
76
+ });
77
+
78
+ test("percent-decodes captured values", () => {
79
+ const match = createRouteMatcher("/files/:filename(.*).:extension");
80
+
81
+ expect(match("/files/My%20Photo.jpg")).toEqual({ filename: "My Photo", extension: "jpg" });
82
+ });
83
+
84
+ test("returns undefined when the path does not match", () => {
85
+ const match = createRouteMatcher(UPLOAD_ROUTE);
86
+
87
+ expect(match("/generated/static/300_200/x.png.webp")).toBeUndefined();
88
+ expect(match("/generated/product/0/f/not-a-uuid_300_x_cv_c_FFF_nt_80_jpg.webp")).toBeUndefined();
89
+ expect(match("/generated/product/0/f/0f1e2d3c_abc_x_cv_c_FFF_nt_80_jpg.webp")).toBeUndefined();
90
+ });
91
+
92
+ test("throws on an invalid route at construction time", () => {
93
+ expect(() => createRouteMatcher("/x/:a([")).toThrow();
94
+ });
@@ -0,0 +1,41 @@
1
+ import { log } from "./log";
2
+ import { Params } from "./tools";
3
+
4
+ const LEGACY_WILDCARD = "(*)";
5
+
6
+ /**
7
+ * Express 4 accepted `:name(*)` as "match anything, slashes included". URLPattern rejects a bare `*`
8
+ * inside a regexp group, so the legacy form is rewritten to the equivalent `(.*)`.
9
+ */
10
+ export function normalizeRoute(route: string): string {
11
+ if (!route.includes(LEGACY_WILDCARD)) {
12
+ return route;
13
+ }
14
+
15
+ log(`Route "${route}" uses the deprecated "(*)" group – use "(.*)" instead.`, "warn");
16
+ return route.replaceAll(LEGACY_WILDCARD, "(.*)");
17
+ }
18
+
19
+ /**
20
+ * Compiles a `route` from the resizer config into a matcher. The syntax is the one built into Node's
21
+ * `URLPattern` (path-to-regexp v6 compatible): `:name`, `:name(regexp)`, `:name+`, several parameters
22
+ * per segment. Matching is case-insensitive and the captured values are percent-decoded, mirroring the
23
+ * Express 4 router this replaced.
24
+ */
25
+ export function createRouteMatcher(route: string): (pathname: string) => Params | undefined {
26
+ const pattern = new URLPattern({ pathname: normalizeRoute(route) }, { ignoreCase: true });
27
+
28
+ return (pathname) => {
29
+ const groups = pattern.exec({ pathname })?.pathname.groups;
30
+ if (groups === undefined) {
31
+ return undefined;
32
+ }
33
+
34
+ const params: Partial<Record<string, string>> = {};
35
+ Object.entries(groups).forEach(([key, value]) => {
36
+ params[key] = value === undefined ? undefined : decodeURIComponent(value);
37
+ });
38
+
39
+ return params as unknown as Params;
40
+ };
41
+ }
@@ -1,24 +1,24 @@
1
1
  import type { FitEnum } from "sharp";
2
2
  export declare const CONTENT_TYPES: Record<string, string | undefined>;
3
- export interface Params {
4
- width: string;
5
- height: string;
6
- fit: string;
7
- position: string;
8
- background: string;
9
- trim: string;
10
- quality: string;
3
+ export type Params = {
4
+ width: string | undefined;
5
+ height: string | undefined;
6
+ fit: string | undefined;
7
+ position: string | undefined;
8
+ background: string | undefined;
9
+ trim: string | undefined;
10
+ quality: string | undefined;
11
11
  filename: string;
12
12
  extension: string;
13
13
  toFormat: string;
14
14
  p1: string | undefined;
15
15
  p2: string | undefined;
16
16
  namespace: string | undefined;
17
- }
17
+ };
18
18
  export declare const getQuality: ({ quality }: Params) => number | undefined;
19
19
  export declare const getWidth: ({ width }: Params) => number | undefined;
20
20
  export declare const getHeight: ({ height }: Params) => number | undefined;
21
- export declare const getBackground: ({ background }: Params) => string;
21
+ export declare const getBackground: ({ background: bg }: Params) => string;
22
22
  export declare const getFit: ({ fit }: Params) => keyof FitEnum;
23
23
  export declare const getPosition: ({ position }: Params) => string | number | undefined;
24
24
  export declare const getWithoutEnlargement: ({ extension }: Params) => boolean;
@@ -33,7 +33,7 @@ const getWidth = ({ width }) => (width && width !== "x" ? Number(width) : undefi
33
33
  exports.getWidth = getWidth;
34
34
  const getHeight = ({ height }) => (height && height !== "x" ? Number(height) : undefined);
35
35
  exports.getHeight = getHeight;
36
- const getBackground = ({ background }) => (background === "t" ? "transparent" : `#${background}`);
36
+ const getBackground = ({ background: bg }) => bg === undefined || bg === "t" ? "transparent" : `#${bg}`;
37
37
  exports.getBackground = getBackground;
38
38
  const getFit = ({ fit }) => { var _a; return (fit ? ((_a = FIT_OPTIONS[fit]) !== null && _a !== void 0 ? _a : "cover") : "cover"); };
39
39
  exports.getFit = getFit;
@@ -41,5 +41,5 @@ const getPosition = ({ position }) => { var _a; return (position ? ((_a = POSITI
41
41
  exports.getPosition = getPosition;
42
42
  const getWithoutEnlargement = ({ extension }) => extension !== "svg";
43
43
  exports.getWithoutEnlargement = getWithoutEnlargement;
44
- const getTrim = ({ trim }) => (trim === "nt" ? undefined : Number(trim));
44
+ const getTrim = ({ trim }) => (trim === undefined || trim === "nt" ? undefined : Number(trim));
45
45
  exports.getTrim = getTrim;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tools_1 = require("./tools");
4
+ const minimal = {
5
+ width: "146",
6
+ height: "100",
7
+ fit: undefined,
8
+ position: undefined,
9
+ background: undefined,
10
+ trim: undefined,
11
+ quality: undefined,
12
+ filename: "logo",
13
+ extension: "png",
14
+ toFormat: "avif",
15
+ p1: undefined,
16
+ p2: undefined,
17
+ namespace: undefined,
18
+ };
19
+ test("a route without the optional parameters falls back to defaults", () => {
20
+ expect((0, tools_1.getWidth)(minimal)).toBe(146);
21
+ expect((0, tools_1.getHeight)(minimal)).toBe(100);
22
+ expect((0, tools_1.getFit)(minimal)).toBe("cover");
23
+ expect((0, tools_1.getPosition)(minimal)).toBeUndefined();
24
+ expect((0, tools_1.getBackground)(minimal)).toBe("transparent");
25
+ expect((0, tools_1.getTrim)(minimal)).toBeUndefined();
26
+ expect((0, tools_1.getQuality)(minimal)).toBeUndefined();
27
+ });
28
+ test("explicit parameters are mapped", () => {
29
+ const params = {
30
+ ...minimal,
31
+ width: "x",
32
+ fit: "cn",
33
+ position: "lt",
34
+ background: "t",
35
+ trim: "10",
36
+ quality: "75",
37
+ };
38
+ expect((0, tools_1.getWidth)(params)).toBeUndefined();
39
+ expect((0, tools_1.getFit)(params)).toBe("contain");
40
+ expect((0, tools_1.getPosition)(params)).toBe("left top");
41
+ expect((0, tools_1.getBackground)(params)).toBe("transparent");
42
+ expect((0, tools_1.getTrim)(params)).toBe(10);
43
+ expect((0, tools_1.getQuality)(params)).toBe(75);
44
+ expect((0, tools_1.getBackground)({ ...minimal, background: "ff0000" })).toBe("#ff0000");
45
+ expect((0, tools_1.getTrim)({ ...minimal, trim: "nt" })).toBeUndefined();
46
+ });
@@ -0,0 +1,48 @@
1
+ import { getBackground, getFit, getHeight, getPosition, getQuality, getTrim, getWidth, Params } from "./tools";
2
+
3
+ const minimal: Params = {
4
+ width: "146",
5
+ height: "100",
6
+ fit: undefined,
7
+ position: undefined,
8
+ background: undefined,
9
+ trim: undefined,
10
+ quality: undefined,
11
+ filename: "logo",
12
+ extension: "png",
13
+ toFormat: "avif",
14
+ p1: undefined,
15
+ p2: undefined,
16
+ namespace: undefined,
17
+ };
18
+
19
+ test("a route without the optional parameters falls back to defaults", () => {
20
+ expect(getWidth(minimal)).toBe(146);
21
+ expect(getHeight(minimal)).toBe(100);
22
+ expect(getFit(minimal)).toBe("cover");
23
+ expect(getPosition(minimal)).toBeUndefined();
24
+ expect(getBackground(minimal)).toBe("transparent");
25
+ expect(getTrim(minimal)).toBeUndefined();
26
+ expect(getQuality(minimal)).toBeUndefined();
27
+ });
28
+
29
+ test("explicit parameters are mapped", () => {
30
+ const params: Params = {
31
+ ...minimal,
32
+ width: "x",
33
+ fit: "cn",
34
+ position: "lt",
35
+ background: "t",
36
+ trim: "10",
37
+ quality: "75",
38
+ };
39
+
40
+ expect(getWidth(params)).toBeUndefined();
41
+ expect(getFit(params)).toBe("contain");
42
+ expect(getPosition(params)).toBe("left top");
43
+ expect(getBackground(params)).toBe("transparent");
44
+ expect(getTrim(params)).toBe(10);
45
+ expect(getQuality(params)).toBe(75);
46
+ expect(getBackground({ ...minimal, background: "ff0000" })).toBe("#ff0000");
47
+ expect(getTrim({ ...minimal, trim: "nt" })).toBeUndefined();
48
+ });
@@ -29,14 +29,14 @@ export const CONTENT_TYPES: Record<string, string | undefined> = {
29
29
  jpeg: "image/jpeg",
30
30
  };
31
31
 
32
- export interface Params {
33
- width: string;
34
- height: string;
35
- fit: string;
36
- position: string;
37
- background: string;
38
- trim: string;
39
- quality: string;
32
+ export type Params = {
33
+ width: string | undefined;
34
+ height: string | undefined;
35
+ fit: string | undefined;
36
+ position: string | undefined;
37
+ background: string | undefined;
38
+ trim: string | undefined;
39
+ quality: string | undefined;
40
40
  filename: string;
41
41
  extension: string;
42
42
  toFormat: string;
@@ -44,13 +44,14 @@ export interface Params {
44
44
  p1: string | undefined;
45
45
  p2: string | undefined;
46
46
  namespace: string | undefined;
47
- }
47
+ };
48
48
 
49
49
  export const getQuality = ({ quality }: Params) => (quality && quality !== "x" ? Number(quality) : undefined);
50
50
  export const getWidth = ({ width }: Params) => (width && width !== "x" ? Number(width) : undefined);
51
51
  export const getHeight = ({ height }: Params) => (height && height !== "x" ? Number(height) : undefined);
52
- export const getBackground = ({ background }: Params) => (background === "t" ? "transparent" : `#${background}`);
52
+ export const getBackground = ({ background: bg }: Params) =>
53
+ bg === undefined || bg === "t" ? "transparent" : `#${bg}`;
53
54
  export const getFit = ({ fit }: Params): keyof FitEnum => (fit ? (FIT_OPTIONS[fit] ?? "cover") : "cover");
54
55
  export const getPosition = ({ position }: Params) => (position ? (POSITION_OPTIONS[position] ?? "centre") : undefined);
55
56
  export const getWithoutEnlargement = ({ extension }: Params) => extension !== "svg";
56
- export const getTrim = ({ trim }: Params) => (trim === "nt" ? undefined : Number(trim));
57
+ export const getTrim = ({ trim }: Params) => (trim === undefined || trim === "nt" ? undefined : Number(trim));
@@ -1,5 +0,0 @@
1
- export type Config = Array<{
2
- route: string;
3
- source: string;
4
- }>;
5
- export declare const resizerMiddleware: (config: Config) => import("express-serve-static-core").Router;