From c8eb5b761810b8182075f9d10e92542bb72e9639 Mon Sep 17 00:00:00 2001 From: Ivan Buryak Date: Fri, 21 Aug 2026 11:37:19 +0500 Subject: [PATCH] Fix gradient dropping optional arguments set to 0 `color`, `direction`, `start` and `stop` were validated and rendered based on truthiness, so an explicit `0` was silently dropped and imgproxy applied the default instead. For `stop: 0` this changed the resulting image: `gr:0.5` means `stop` is `1.0`, not `0`. Check for `undefined` instead, matching the `progressive_blur` option. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01G8Aa3xeVUCaxKtQJDzZhMo --- .changeset/gradient-explicit-optional-args.md | 5 ++ src/options/gradient.ts | 16 +++---- tests/optionsBasic/gradient.test.ts | 46 +++++++++++++++++++ 3 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 .changeset/gradient-explicit-optional-args.md diff --git a/.changeset/gradient-explicit-optional-args.md b/.changeset/gradient-explicit-optional-args.md new file mode 100644 index 00000000..a20a3038 --- /dev/null +++ b/.changeset/gradient-explicit-optional-args.md @@ -0,0 +1,5 @@ +--- +"@imgproxy/imgproxy-js-core": patch +--- + +Fix the `gradient` option dropping optional arguments explicitly set to `0`. `color`, `direction`, `start` and `stop` were checked for truthiness, so `{ gradient: { opacity: 0.5, stop: 0 } }` produced `gr:0.5` and imgproxy fell back to the default `stop` of `1.0` instead of the requested `0`. The same applied to `start: 0` and to a `direction` angle of `0`. These values are now rendered explicitly, and invalid falsy values (such as `null` or an empty `color`) are reported instead of being silently ignored. diff --git a/src/options/gradient.ts b/src/options/gradient.ts index 62428728..e0ab4eda 100644 --- a/src/options/gradient.ts +++ b/src/options/gradient.ts @@ -30,8 +30,8 @@ const build = (options: GradientOptionsPartial): string => { addParam: { min: 0, max: 1 }, }); - if (color) guardIsNotStr(color, "gradient.color", true); - if (direction) { + if (color !== undefined) guardIsNotStr(color, "gradient.color", true); + if (direction !== undefined) { if (typeof direction === "number") { guardIsNotNum(direction, "gradient.direction"); } else { @@ -39,16 +39,16 @@ const build = (options: GradientOptionsPartial): string => { guardIsValidVal(currentDirection, direction, "gradient.direction"); } } - if (start) + if (start !== undefined) guardIsNotNum(start, "gradient.start", { addParam: { min: 0, max: 1 } }); - if (stop) + if (stop !== undefined) guardIsNotNum(stop, "gradient.stop", { addParam: { min: 0, max: 1 } }); const op = opacity; - const c = color || ""; - const dir = direction || ""; - const or = start || ""; - const end = stop || ""; + const c = color ?? ""; + const dir = direction ?? ""; + const or = start ?? ""; + const end = stop ?? ""; return `gr:${op}:${c}:${dir}:${or}:${end}`.replace(/:+$/, ""); }; diff --git a/tests/optionsBasic/gradient.test.ts b/tests/optionsBasic/gradient.test.ts index ca16257d..a4eb9e6e 100644 --- a/tests/optionsBasic/gradient.test.ts +++ b/tests/optionsBasic/gradient.test.ts @@ -190,5 +190,51 @@ describe("gradient", () => { }) ).toEqual("gr:0::::0.85"); }); + + it("should correctly handle 0 stop", () => { + expect( + build({ + gradient: { + opacity: 0.5, + stop: 0, + }, + }) + ).toEqual("gr:0.5::::0"); + }); + + it("should correctly handle 0 start", () => { + expect( + build({ + gradient: { + opacity: 0.5, + start: 0, + }, + }) + ).toEqual("gr:0.5:::0"); + }); + + it("should correctly handle 0 direction angle", () => { + expect( + build({ + gradient: { + opacity: 0.5, + direction: 0, + }, + }) + ).toEqual("gr:0.5::0"); + }); + + it("should throw an error if start is null", () => { + expect(() => + // @ts-expect-error: Let's ignore an error (check for users with vanilla js). + build({ gradient: { opacity: 0.5, start: null } }) + ).toThrow("gradient.start is not a number"); + }); + + it("should throw an error if color is an empty string", () => { + expect(() => build({ gradient: { opacity: 0.5, color: "" } })).toThrow( + "gradient.color must be 3, 6 or 8 characters long (with alpha)" + ); + }); }); });