From 25a30296a8ee61d4313e6c26452d3cef7f001a41 Mon Sep 17 00:00:00 2001 From: Francis Pion Date: Mon, 28 Apr 2025 20:20:18 -0400 Subject: [PATCH] `email` and `url` now accept empty strings (but not white space). --- CHANGELOG.md | 9 ++++- package-lock.json | 4 +- package.json | 4 +- src/rules/__tests__/email.spec.ts | 8 ++-- src/rules/__tests__/url.spec.ts | 9 +---- src/rules/email.ts | 28 +++++++------- src/rules/url.ts | 64 +++++++++++++++---------------- 7 files changed, 65 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 157ec0b..71adce7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Nothing yet. +## [1.0.1] - 2025-04-28 + +### Fixed + +- `email` and `url` now accept empty strings (but not white space). + ## [1.0.0] - 2025-04-21 ### Added - Implemented Validator, message formatting and validation rules. -[unreleased]: https://github.com/Logitar/js/compare/v1.0.0...HEAD +[unreleased]: https://github.com/Logitar/js/compare/v1.0.1...HEAD +[1.0.1]: https://github.com/Logitar/js/compare/v1.0.0...v1.0.1 [1.0.0]: https://github.com/Logitar/js/releases/tag/v1.0.0 diff --git a/package-lock.json b/package-lock.json index 6741196..3d52bc5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "logitar-validation", - "version": "1.0.0", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "logitar-validation", - "version": "1.0.0", + "version": "1.0.1", "license": "MIT", "dependencies": { "logitar-js": "^1.0.1" diff --git a/package.json b/package.json index 4382bdb..d7591a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "logitar-validation", - "version": "1.0.0", + "version": "1.0.1", "description": "JavaScript validation library distributed by Logitar.", "keywords": [ "logitar", @@ -40,4 +40,4 @@ "dependencies": { "logitar-js": "^1.0.1" } -} +} \ No newline at end of file diff --git a/src/rules/__tests__/email.spec.ts b/src/rules/__tests__/email.spec.ts index d0f5663..4a07779 100644 --- a/src/rules/__tests__/email.spec.ts +++ b/src/rules/__tests__/email.spec.ts @@ -16,14 +16,14 @@ describe("email", () => { expect(outcome.message).toBe("The arguments must be undefined, or a valid email address validation regular expression."); }); - it.concurrent("should return invalid when the value is not a valid email address", () => { - const outcome = email("aa@@bb..cc") as RuleExecutionOutcome; + test.each([" ", "aa@@bb..cc"])("should return invalid when the value is not a valid email address", (value) => { + const outcome = email(value) as RuleExecutionOutcome; expect(outcome.severity).toBe("error"); expect(outcome.message).toBe("{{name}} must be a valid email address."); }); - it.concurrent("should return valid when the value is a valid email address", () => { - const outcome = email("test@example.com") as RuleExecutionOutcome; + test.each(["", "test@example.com"])("should return valid when the value is a valid email address", (value) => { + const outcome = email(value) as RuleExecutionOutcome; expect(outcome.severity).toBe("information"); expect(outcome.message).toBeUndefined(); }); diff --git a/src/rules/__tests__/url.spec.ts b/src/rules/__tests__/url.spec.ts index 7966918..60ca4c6 100644 --- a/src/rules/__tests__/url.spec.ts +++ b/src/rules/__tests__/url.spec.ts @@ -10,15 +10,9 @@ describe("url", () => { expect(outcome.message).toBe("{{name}} must be a string."); }); - test.each(["", " "])("should return invalid when the value is empty or white-space", (value) => { + test.each([" ", "invalid-url"])("should return invalid when the value is not a valid URL", (value) => { const outcome = url(value) as RuleExecutionOutcome; expect(outcome.severity).toBe("error"); - expect(outcome.message).toBe("{{name}} cannot be an empty string."); - }); - - it.concurrent("should return invalid when the value is not a valid URL", () => { - const outcome = url("invalid-url") as RuleExecutionOutcome; - expect(outcome.severity).toBe("error"); expect(outcome.message).toBe("{{name}} must be a valid URL."); }); @@ -37,6 +31,7 @@ describe("url", () => { }); test.each([ + ["", undefined], ["http://example.com", undefined], ["http://example.com", "http,https"], ["http://example.com", "http;https"], diff --git a/src/rules/email.ts b/src/rules/email.ts index bede65a..ea51032 100644 --- a/src/rules/email.ts +++ b/src/rules/email.ts @@ -14,21 +14,23 @@ const email: ValidationRule = (value: unknown, args: unknown): RuleExecutionOutc return { severity: "error", message: "{{name}} must be a string." }; } - let isArgsValid: boolean = true; - let regex: RegExp; - if (typeof args === "string" || args instanceof RegExp) { - regex = new RegExp(args); - } else { - regex = new RegExp(defaultRegex); - if (typeof args !== "undefined" && typeof args !== "boolean") { - isArgsValid = false; + if (value.length > 0) { + let isArgsValid: boolean = true; + let regex: RegExp; + if (typeof args === "string" || args instanceof RegExp) { + regex = new RegExp(args); + } else { + regex = new RegExp(defaultRegex); + if (typeof args !== "undefined" && typeof args !== "boolean") { + isArgsValid = false; + } } - } - if (!regex.test(value)) { - return { severity: "error", message: "{{name}} must be a valid email address." }; - } else if (!isArgsValid) { - return { severity: "warning", message: "The arguments must be undefined, or a valid email address validation regular expression." }; + if (!regex.test(value)) { + return { severity: "error", message: "{{name}} must be a valid email address." }; + } else if (!isArgsValid) { + return { severity: "warning", message: "The arguments must be undefined, or a valid email address validation regular expression." }; + } } return { severity: "information" }; diff --git a/src/rules/url.ts b/src/rules/url.ts index 9cf19ab..b2e983a 100644 --- a/src/rules/url.ts +++ b/src/rules/url.ts @@ -2,7 +2,7 @@ import { stringUtils } from "logitar-js"; import type { RuleExecutionOutcome, ValidationRule } from "../types"; -const { isNullOrWhiteSpace, trimEnd } = stringUtils; +const { trimEnd } = stringUtils; /** * Format a protocol string to be used in a set. @@ -22,43 +22,43 @@ function format(protocol: string): string { const url: ValidationRule = (value: unknown, args: unknown): RuleExecutionOutcome => { if (typeof value !== "string") { return { severity: "error", message: "{{name}} must be a string." }; - } else if (isNullOrWhiteSpace(value)) { - return { severity: "error", message: "{{name}} cannot be an empty string." }; } - let isArgsValid: boolean = true; - const protocols: Set = new Set(["http", "https"]); - if (typeof args !== "undefined") { - let values: string[] = []; - if (typeof args === "string") { - values = args.split(/[,;\|]/); - } else if (Array.isArray(args)) { - values = args; + if (value.length > 0) { + let isArgsValid: boolean = true; + const protocols: Set = new Set(["http", "https"]); + if (typeof args !== "undefined") { + let values: string[] = []; + if (typeof args === "string") { + values = args.split(/[,;\|]/); + } else if (Array.isArray(args)) { + values = args; + } + if (values.length === 0) { + isArgsValid = false; + } else { + values.forEach((value) => protocols.add(format(value))); + } } - if (values.length === 0) { - isArgsValid = false; - } else { - values.forEach((value) => protocols.add(format(value))); - } - } - let url: URL; - try { - url = new URL(value.trim()); - } catch (_) { - return { severity: "error", message: "{{name}} must be a valid URL." }; - } + let url: URL; + try { + url = new URL(value.trim()); + } catch (_) { + return { severity: "error", message: "{{name}} must be a valid URL." }; + } - if (!protocols.has(format(url.protocol))) { - return { severity: "error", message: `{{name}} must be an URL with one of the following protocols: ${[...protocols].join(", ")}.` }; - } + if (!protocols.has(format(url.protocol))) { + return { severity: "error", message: `{{name}} must be an URL with one of the following protocols: ${[...protocols].join(", ")}.` }; + } - if (!isArgsValid) { - return { - severity: "warning", - message: - "The arguments must be undefined, a string containing the allowed protocols separated by commas, semicolons or pipes, or an array of allowed protocols.", - }; + if (!isArgsValid) { + return { + severity: "warning", + message: + "The arguments must be undefined, a string containing the allowed protocols separated by commas, semicolons or pipes, or an array of allowed protocols.", + }; + } } return { severity: "information" };