From 2b20d0122d10a9834fd4d441571a862c7ee98c57 Mon Sep 17 00:00:00 2001 From: Hein Date: Tue, 4 Mar 2025 17:03:53 +0200 Subject: [PATCH] blankValue --- src/strings/blankValue.test.ts | 81 ++++++++++++++++++++++++++++++++++ src/strings/blankValue.ts | 47 ++++++++++++++++++++ src/strings/index.ts | 1 + 3 files changed, 129 insertions(+) create mode 100644 src/strings/blankValue.test.ts create mode 100644 src/strings/blankValue.ts diff --git a/src/strings/blankValue.test.ts b/src/strings/blankValue.test.ts new file mode 100644 index 0000000..407b838 --- /dev/null +++ b/src/strings/blankValue.test.ts @@ -0,0 +1,81 @@ +import { describe, it, expect } from "vitest"; +import { blankValue } from "./blankValue"; + +describe("blankValue function", () => { + it("should return undefined when no arguments are provided", () => { + expect(blankValue()).toBe(undefined); + }); + + it("should return the first non-blank value", () => { + expect(blankValue(undefined, null, "value")).toBe("value"); + expect(blankValue(null, 42, "string")).toBe(42); + expect(blankValue(undefined, null, 0, "", [], {}, "valid")).toBe("valid"); + }); + + it("should consider 0 as blank for numbers", () => { + expect(blankValue(0, 42)).toBe(42); + expect(blankValue(0, "string")).toBe("string"); + expect(blankValue(undefined, 0, null, 42)).toBe(42); + }); + + it("should consider empty string as blank for strings", () => { + expect(blankValue("", "value")).toBe("value"); + expect(blankValue(undefined, "", "text")).toBe("text"); + }); + + it("should consider empty arrays as blank", () => { + expect(blankValue([], [1, 2, 3])).toEqual([1, 2, 3]); + expect(blankValue(undefined, [], ["item"])).toEqual(["item"]); + }); + + it("should consider empty objects as blank", () => { + expect(blankValue({}, { key: "value" })).toEqual({ key: "value" }); + expect(blankValue(undefined, {}, { name: "John" })).toEqual({ + name: "John", + }); + }); + + it("should return the last argument if all values are blank", () => { + expect(blankValue(undefined, null)).toBe(null); + expect(blankValue(undefined, null, 0, "", [], {})).toEqual({}); + }); + + it("should work with various data types in the same call", () => { + expect(blankValue(0, "", [], {}, "mixed")).toBe("mixed"); + expect(blankValue(undefined, null, 0, 42, "", "text", [], [1, 2])).toBe(42); + }); + + it("should handle complex nested structures correctly", () => { + const complexObj = { nested: { data: "value" } }; + expect(blankValue({}, complexObj)).toEqual(complexObj); + + const nestedArray = [ + [1, 2], + [3, 4], + ]; + expect(blankValue([], nestedArray)).toEqual(nestedArray); + }); + + it("should maintain type correctness with generics", () => { + const stringResult: string = blankValue(undefined, "", "text"); + expect(stringResult).toBe("text"); + + const numResult: number = blankValue(null, 0, 42); + expect(numResult).toBe(42); + + const arrayResult: number[] = blankValue([], [1, 2, 3]); + expect(arrayResult).toEqual([1, 2, 3]); + + interface User { + name: string; + age?: number; + } + const objResult: User = blankValue({}, { name: "John" }); + expect(objResult).toEqual({ name: "John" }); + }); + + it("should handle falsy values that are not blank correctly", () => { + expect(blankValue(undefined, false)).toBe(false); + expect(blankValue(null, NaN)).toBeNaN(); + }); +}); diff --git a/src/strings/blankValue.ts b/src/strings/blankValue.ts new file mode 100644 index 0000000..f6802fb --- /dev/null +++ b/src/strings/blankValue.ts @@ -0,0 +1,47 @@ +/** + * Returns the first non-blank value from the provided arguments. + * A value is considered blank if it's: + * - undefined or null + * - number 0 + * - empty string + * - empty array + * - empty object + * If all values are blank, returns the last argument. + * + * @returns The first non-blank value or the last argument if all are blank + */ +export function blankValue(...args: any[]): T | undefined { + // Handle case where no arguments are provided + if (args.length === 0) return undefined; + + for (let i = 0; i < args.length; i++) { + const value = args[i]; + const valueType = typeof value; + + // Skip blank values based on type + if (value === undefined || value === null) continue; + + // Check numbers - consider 0 as blank + if (valueType === "number" && value === 0) continue; + + // Check strings - consider empty string as blank + if (valueType === "string" && value === "") continue; + + // Check arrays - consider empty arrays as blank + if (Array.isArray(value) && value.length === 0) continue; + + // Check objects - consider empty objects as blank + if ( + valueType === "object" && + !Array.isArray(value) && + Object.keys(value).length === 0 + ) + continue; + + // If we reach here, we've found a non-blank value + return value; + } + + // If all values are blank, return the last one + return args[args.length - 1]; +} diff --git a/src/strings/index.ts b/src/strings/index.ts index 915edf4..8cd54ee 100644 --- a/src/strings/index.ts +++ b/src/strings/index.ts @@ -6,3 +6,4 @@ export * from "./fileSize"; export * from "./legacy"; export * from "./uuid"; export * from "./time"; +export * from "./blankValue";