From 611bcc1ceadca343e4270da5f1223ed78405d3d0 Mon Sep 17 00:00:00 2001 From: jan-kubica Date: Sat, 13 Jun 2026 21:46:40 +0200 Subject: [PATCH] fix(clean): strip surrounding whitespace clean() normalized unicode and removed the given separator characters but left surrounding whitespace outside that set (newlines, tabs) intact, so validate() rejected otherwise-valid copy-pasted input. A few modules worked around this with a manual .trim(); most did not. Trim in clean() so every compact()/validate() handles surrounding whitespace uniformly. --- __test__/clean.test.ts | 23 +++++++++++++++++++++++ __test__/no.test.ts | 10 ++++++++++ src/_util/clean.ts | 9 +++++++-- 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 __test__/clean.test.ts diff --git a/__test__/clean.test.ts b/__test__/clean.test.ts new file mode 100644 index 0000000..7b4e8f7 --- /dev/null +++ b/__test__/clean.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, test } from "bun:test"; + +import { clean } from "../src/_util/clean"; + +describe("clean", () => { + test("removes surrounding whitespace", () => { + // Newlines and tabs are not in the separator set, so without the + // trailing trim they would survive and break length/format checks. + expect(clean("988077917\n", " -")).toBe("988077917"); + expect(clean("\t 988077917 ", " -")).toBe("988077917"); + expect(clean("\r\n12 34\r\n", " -")).toBe("1234"); + }); + + test("preserves internal characters and removes separators", () => { + expect(clean("123-456 789", " -")).toBe("123456789"); + expect(clean("a b", "")).toBe("a b"); + }); + + test("normalizes unicode separators before stripping", () => { + // en dash -> ascii hyphen, then removed by the strip set + expect(clean("123–456", " -")).toBe("123456"); + }); +}); diff --git a/__test__/no.test.ts b/__test__/no.test.ts index 111dee4..ceee166 100644 --- a/__test__/no.test.ts +++ b/__test__/no.test.ts @@ -15,6 +15,16 @@ describe("no.orgnr", () => { expect(r.valid).toBe(true); }); + test("valid with surrounding whitespace", () => { + // compact() trims newlines/tabs that the separator set misses. + expect(no.orgnr.validate("988077917\n").valid).toBe( + true, + ); + expect(no.orgnr.validate("\t 988077917 ").valid).toBe( + true, + ); + }); + test("invalid checksum", () => { const r = no.orgnr.validate("988077918"); expect(r.valid).toBe(false); diff --git a/src/_util/clean.ts b/src/_util/clean.ts index 194f4be..54a7e75 100644 --- a/src/_util/clean.ts +++ b/src/_util/clean.ts @@ -63,7 +63,12 @@ const CHAR_REGEX = new RegExp( /** * Normalize Unicode artifacts to ASCII - * equivalents and strip the given characters. + * equivalents, strip the given characters, and + * remove surrounding whitespace. + * + * The trailing trim removes whitespace outside the + * separator set (newlines, tabs) so validators + * accept copy-pasted input. * * @param value - The input string * @param strip - Characters to remove @@ -82,5 +87,5 @@ export const clean = ( result = result.replaceAll(ch, ""); } } - return result; + return result.trim(); };