Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/lib/slugify.test.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});
15 changes: 15 additions & 0 deletions src/lib/slugify.ts
Original file line number Diff line number Diff line change
@@ -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;
}