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)" + ); + }); }); });