Make slug optional on create and auto-generate from title when omitted

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-24 15:58:56 +03:30
co-authored by Cursor
parent aa990c3204
commit 1522ff62f5
9 changed files with 118 additions and 23 deletions
+34 -2
View File
@@ -1,3 +1,5 @@
const SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
export function slugifyTitle(value: string): string {
return value
.trim()
@@ -8,13 +10,19 @@ export function slugifyTitle(value: string): string {
.replace(/^-|-$/g, '');
}
export async function uniqueBusinessSlug(
export function normalizeSlugInput(value?: string | null): string | undefined {
const trimmed = value?.trim();
return trimmed ? trimmed : undefined;
}
export async function uniqueSlugFromTitle(
title: string,
exists: (slug: string) => Promise<boolean>,
fallbackBase = 'item',
): Promise<string> {
let base = slugifyTitle(title);
if (!base) {
base = 'business';
base = fallbackBase;
}
let slug = base;
let suffix = 0;
@@ -24,3 +32,27 @@ export async function uniqueBusinessSlug(
}
return slug;
}
export async function resolveUniqueSlug(
title: string,
exists: (slug: string) => Promise<boolean>,
provided?: string | null,
fallbackBase = 'item',
): Promise<string> {
const normalized = normalizeSlugInput(provided);
if (normalized) {
if (!SLUG_PATTERN.test(normalized)) {
throw new Error('Invalid slug format');
}
return normalized;
}
return uniqueSlugFromTitle(title, exists, fallbackBase);
}
/** @deprecated Use uniqueSlugFromTitle */
export async function uniqueBusinessSlug(
title: string,
exists: (slug: string) => Promise<boolean>,
): Promise<string> {
return uniqueSlugFromTitle(title, exists, 'business');
}