From 2ed9291c4d0bdc9c4557a9ebedee6dadc795636a Mon Sep 17 00:00:00 2001 From: Pablo Baleztena Date: Thu, 17 Oct 2024 14:32:47 -0300 Subject: [PATCH] [fabric/core] Add utility functions for value checks and string sanitization --- packages/fabric/core/utils/index.ts | 3 ++ .../fabric/core/utils/is-not-a-number.test.ts | 40 +++++++++++++++++++ packages/fabric/core/utils/is-not-a-number.ts | 25 ++++++++++++ packages/fabric/core/utils/is-nullish.ts | 11 +++++ .../fabric/core/utils/sanitize-string.test.ts | 40 +++++++++++++++++++ packages/fabric/core/utils/sanitize-string.ts | 15 +++++++ 6 files changed, 134 insertions(+) create mode 100644 packages/fabric/core/utils/is-not-a-number.test.ts create mode 100644 packages/fabric/core/utils/is-not-a-number.ts create mode 100644 packages/fabric/core/utils/is-nullish.ts create mode 100644 packages/fabric/core/utils/sanitize-string.test.ts create mode 100644 packages/fabric/core/utils/sanitize-string.ts diff --git a/packages/fabric/core/utils/index.ts b/packages/fabric/core/utils/index.ts index 2f5dc32..edf865a 100644 --- a/packages/fabric/core/utils/index.ts +++ b/packages/fabric/core/utils/index.ts @@ -1 +1,4 @@ export * from "./ensure-value.ts"; +export * from "./is-not-a-number.ts"; +export * from "./is-nullish.ts"; +export * from "./sanitize-string.ts"; diff --git a/packages/fabric/core/utils/is-not-a-number.test.ts b/packages/fabric/core/utils/is-not-a-number.test.ts new file mode 100644 index 0000000..6f7f7d9 --- /dev/null +++ b/packages/fabric/core/utils/is-not-a-number.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, test } from "@fabric/testing"; +import { isNotANumber } from "./is-not-a-number.ts"; + +describe("Is not a number", () => { + test("Given a number it should return false", () => { + expect(isNotANumber(1)).toBe(false); + }); + + test("Given a string it should return true", () => { + expect(isNotANumber("a")).toBe(true); + }); + + test("Given a string number it should return false", () => { + expect(isNotANumber("5")).toBe(false); + }); + + test("Given an empty string it should return true", () => { + expect(isNotANumber("")).toBe(true); + }); + + test("Given a boolean it should return true", () => { + expect(isNotANumber(true)).toBe(true); + }); + + test("Given an object it should return true", () => { + expect(isNotANumber({})).toBe(true); + }); + + test("Given an array it should return true", () => { + expect(isNotANumber([])).toBe(true); + }); + + test("Given a null it should return true", () => { + expect(isNotANumber(null)).toBe(true); + }); + + test("Given an undefined it should return true", () => { + expect(isNotANumber(undefined)).toBe(true); + }); +}); diff --git a/packages/fabric/core/utils/is-not-a-number.ts b/packages/fabric/core/utils/is-not-a-number.ts new file mode 100644 index 0000000..486368f --- /dev/null +++ b/packages/fabric/core/utils/is-not-a-number.ts @@ -0,0 +1,25 @@ +import { isNullish } from "./is-nullish.ts"; +import { parseAndSanitizeString } from "./sanitize-string.ts"; + +export function isNotANumber(value: unknown): boolean { + if (isNullish(value)) { + return true; + } + + if (typeof value === "string") { + const sanitized = parseAndSanitizeString(value); + if (sanitized === "") { + return true; + } + } + + if ( + typeof value === "boolean" || + typeof value === "object" || + Array.isArray(value) + ) { + return true; + } + + return isNaN(Number(value)); +} diff --git a/packages/fabric/core/utils/is-nullish.ts b/packages/fabric/core/utils/is-nullish.ts new file mode 100644 index 0000000..dcdfc62 --- /dev/null +++ b/packages/fabric/core/utils/is-nullish.ts @@ -0,0 +1,11 @@ +export function isNullish(value: unknown): value is null | undefined { + return isNull(value) || isUndefined(value); +} + +export function isUndefined(value: unknown): value is undefined { + return value === undefined; +} + +export function isNull(value: unknown): value is null { + return value === null; +} diff --git a/packages/fabric/core/utils/sanitize-string.test.ts b/packages/fabric/core/utils/sanitize-string.test.ts new file mode 100644 index 0000000..1945871 --- /dev/null +++ b/packages/fabric/core/utils/sanitize-string.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, test } from "@fabric/testing"; +import { parseAndSanitizeString } from "./sanitize-string.ts"; + +describe("Sanitize String", () => { + test("Given a string with low characters it should sanitize it", () => { + const sanitized = parseAndSanitizeString("John\x00"); + + expect(sanitized).toBe("John"); + }); + + test("Given a string with leading and trailing spaces it should trim them", () => { + const sanitized = parseAndSanitizeString(" John "); + + expect(sanitized).toBe("John"); + }); + + test("Given a number value it should convert it to a string", () => { + const sanitized = parseAndSanitizeString(123); + + expect(sanitized).toBe("123"); + }); + + test("Given a boolean value it should convert it to a string", () => { + const sanitized = parseAndSanitizeString(true); + + expect(sanitized).toBe("true"); + }); + + test("Given a null value it should convert it to an empty string", () => { + const sanitized = parseAndSanitizeString(null); + + expect(sanitized).toBe("null"); + }); + + test("Given an undefined value it should convert it to an empty string", () => { + const sanitized = parseAndSanitizeString(undefined); + + expect(sanitized).toBe(undefined); + }); +}); diff --git a/packages/fabric/core/utils/sanitize-string.ts b/packages/fabric/core/utils/sanitize-string.ts new file mode 100644 index 0000000..9fbc445 --- /dev/null +++ b/packages/fabric/core/utils/sanitize-string.ts @@ -0,0 +1,15 @@ +import validator from "validator"; +import { isUndefined } from "./is-nullish.ts"; + +const { stripLow, trim } = validator; + +/** + * Parses and sanitizes an unknown value into a string + * The string is trimmed and all low characters are removed + */ +export function parseAndSanitizeString(value: unknown): string | undefined { + if (isUndefined(value)) { + return value; + } + return stripLow(trim(String(value))); +}