From 8a4fd2ab7b26fc84df060d34f672cdb879c6fc26 Mon Sep 17 00:00:00 2001 From: webdevcom01-cell Date: Sat, 16 May 2026 12:59:48 +0200 Subject: [PATCH 1/2] feat(slugify-url-safe-string): SDLC [{{pipelineResult.runId}}] --- src/lib/slugify.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/lib/slugify.ts diff --git a/src/lib/slugify.ts b/src/lib/slugify.ts new file mode 100644 index 0000000..2435e05 --- /dev/null +++ b/src/lib/slugify.ts @@ -0,0 +1,15 @@ +export function slugify(text: string): string { + // Normalize to NFD form to split accented letters + const normalized = text.normalize('NFD'); + // Remove diacritics (accents) + const withoutAccents = normalized.replace(/\p{Diacritic}+/gu, ''); + // Replace non-alphanumeric chars (including underscores and spaces) with hyphens + const replaced = withoutAccents.replace(/[^a-zA-Z0-9]+/g, '-'); + // Lowercase + const lower = replaced.toLowerCase(); + // Collapse multiple hyphens + const collapsed = lower.replace(/-+/g, '-'); + // Trim leading/trailing hyphens + const trimmed = collapsed.replace(/^-+|-+$/g, ''); + return trimmed; +} From b1d7b3a6ae681e619421145943b6db28aefcb2bb Mon Sep 17 00:00:00 2001 From: webdevcom01-cell Date: Sat, 16 May 2026 12:59:48 +0200 Subject: [PATCH 2/2] test(slugify-url-safe-string): SDLC [{{pipelineResult.runId}}] --- src/lib/slugify.test.ts | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/lib/slugify.test.ts diff --git a/src/lib/slugify.test.ts b/src/lib/slugify.test.ts new file mode 100644 index 0000000..db20ae4 --- /dev/null +++ b/src/lib/slugify.test.ts @@ -0,0 +1,36 @@ +import { describe, it, expect } from 'vitest'; +import { slugify } from './slugify'; + +describe('slugify', () => { + it('converts basic string with spaces', () => { + expect(slugify('Hello World')).toBe('hello-world'); + }); + + it('strips accented characters', () => { + expect(slugify('Café über')).toBe('cafe-uber'); + }); + + it('handles multiple spaces', () => { + expect(slugify('multiple spaces here')).toBe('multiple-spaces-here'); + }); + + it('replaces special characters with hyphens', () => { + expect(slugify('hello@world! How_are you?')).toBe('hello-world-how-are-you'); + }); + + it('returns already-clean slug unchanged (except lowercased)', () => { + expect(slugify('already-clean-slug')).toBe('already-clean-slug'); + }); + + it('returns empty string for empty input', () => { + expect(slugify('')).toBe(''); + }); + + it('returns empty string for all special chars', () => { + expect(slugify('!@#$%^&*()_+=[]{}|;:",.<>?/\\')).toBe(''); + }); + + it('handles numbers mixed with text', () => { + expect(slugify('Product 123 name!')).toBe('product-123-name'); + }); +});