| 123456789101112131415161718192021222324252627282930313233343536373839404142434445 |
- const SLUG_PATTERN = /^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$|^[a-z0-9]{3}$/
- function simpleHash(str) {
- let h = 0
- for (let i = 0; i < str.length; i++) {
- h = ((h << 5) - h) + str.charCodeAt(i)
- h |= 0
- }
- return Math.abs(h).toString(36)
- }
- function slugify(title) {
- let base = String(title || '').trim().toLowerCase()
- .replace(/\s+/g, '-')
- .replace(/[^a-z0-9-]/g, '')
- .replace(/-+/g, '-')
- .replace(/^-|-$/g, '')
- if (base.length < 3) {
- base = 'article-' + simpleHash(String(title || Date.now()))
- }
- return base.slice(0, 58)
- }
- function isValidSlug(slug) {
- return SLUG_PATTERN.test(String(slug || ''))
- }
- async function ensureUniqueSlug(db, slug, excludeId = null) {
- let candidate = slug
- let n = 2
- while (true) {
- const sql = excludeId
- ? 'SELECT id FROM article WHERE slug = ? AND id != ? LIMIT 1'
- : 'SELECT id FROM article WHERE slug = ? LIMIT 1'
- const params = excludeId ? [candidate, excludeId] : [candidate]
- const rows = await db.query(sql, params)
- if (!rows || rows.length === 0) return candidate
- const suffix = `-${n}`
- candidate = `${slug.slice(0, 64 - suffix.length)}${suffix}`
- n++
- }
- }
- module.exports = { slugify, isValidSlug, ensureUniqueSlug, SLUG_PATTERN }
|