UNPKG

@sehirapp/core-microservice

Version:

Modern mikroservis core paketi - MongoDB 6.7, Express API, Mongoose, PM2 cluster desteği

289 lines (242 loc) 8.62 kB
/** * String Utilities - Core mikroservisler için metin işleme fonksiyonları * Türkçe karakter desteği, SEO slug üretimi, temizlik işlemleri */ /** * Türkçe karakterleri İngilizce karşılıklarına çevir * @param {string} text - Çevrilecek metin * @returns {string} İngilizce karakterli metin */ export const turkishToEnglish = (text) => { if (!text || typeof text !== 'string') return ''; const turkishMap = { 'ç': 'c', 'ğ': 'g', 'ı': 'i', 'ö': 'o', 'ş': 's', 'ü': 'u', 'Ç': 'C', 'Ğ': 'G', 'İ': 'I', 'Ö': 'O', 'Ş': 'S', 'Ü': 'U' }; return text.replace(/[çğıöşüÇĞİÖŞÜ]/g, (char) => turkishMap[char] || char); }; /** * SEO dostu slug oluştur * @param {string} text - Slug'a çevrilecek metin * @param {Object} options - Seçenekler * @returns {string} SEO dostu slug */ export const createSlug = (text, options = {}) => { const { addTimestamp = true, maxLength = 100, separator = '-', lowercase = true, removeStopWords = true } = options; if (!text || typeof text !== 'string') return ''; // Türkçe karakterleri çevir let slug = turkishToEnglish(text); // Küçük harfe çevir if (lowercase) { slug = slug.toLowerCase(); } // Stop words'leri kaldır (Türkçe + İngilizce) if (removeStopWords) { const stopWords = [ 'bir', 'bu', 've', 'ile', 'için', 'olan', 'olarak', 'da', 'de', 'ki', 'mi', 'mu', 'mı', 'mü', 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'as', 'is', 'are', 'was', 'were' ]; const words = slug.split(/\s+/); slug = words.filter(word => !stopWords.includes(word)).join(' '); } // Özel karakterleri temizle ve boşlukları ayırıcı ile değiştir slug = slug .replace(/[^a-zA-Z0-9\s]/g, '') // Özel karakterleri kaldır .replace(/\s+/g, separator) // Boşlukları ayırıcı ile değiştir .replace(new RegExp(`\\${separator}+`, 'g'), separator) // Çoklu ayırıcıları tek yap .replace(new RegExp(`^\\${separator}|\\${separator}$`, 'g'), ''); // Baştan ve sondan ayırıcıları kaldır // Maksimum uzunluk kontrolü if (maxLength && slug.length > maxLength) { slug = slug.substring(0, maxLength); // Son kelimenin yarım kalmasını engelle const lastSeparator = slug.lastIndexOf(separator); if (lastSeparator > maxLength * 0.7) { slug = slug.substring(0, lastSeparator); } } // Timestamp ekle if (addTimestamp && slug) { const timestamp = Date.now().toString(36); // Base36 format slug += separator + timestamp; } return slug || 'untitled'; }; /** * Metin temizleme - HTML, script, SQL injection koruması * @param {string} text - Temizlenecek metin * @param {Object} options - Temizlik seçenekleri * @returns {string} Temizlenmiş metin */ export const sanitizeText = (text, options = {}) => { const { removeHtml = true, removeScript = true, removeSqlPatterns = true, maxLength = null, preserveNewlines = false } = options; if (!text || typeof text !== 'string') return ''; let cleaned = text; // Script taglarını kaldır (güvenlik) if (removeScript) { cleaned = cleaned.replace(/<script[\s\S]*?<\/script>/gi, ''); cleaned = cleaned.replace(/javascript:/gi, ''); cleaned = cleaned.replace(/on\w+\s*=/gi, ''); } // HTML taglarını kaldır if (removeHtml) { cleaned = cleaned.replace(/<[^>]*>/g, ''); cleaned = cleaned.replace(/&[#\w]+;/g, ''); // HTML entities } // SQL injection kalıplarını temizle if (removeSqlPatterns) { const sqlPatterns = [ /(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|UNION|SCRIPT)\b)/gi, /(--|\|\|)/g, /[';]/g ]; sqlPatterns.forEach(pattern => { cleaned = cleaned.replace(pattern, ''); }); } // Newline'ları koru veya kaldır if (!preserveNewlines) { cleaned = cleaned.replace(/\n\r?/g, ' '); } // Çoklu boşlukları tek yap cleaned = cleaned.replace(/\s+/g, ' ').trim(); // Maksimum uzunluk if (maxLength && cleaned.length > maxLength) { cleaned = cleaned.substring(0, maxLength).trim(); // Kelime ortasında kesilmesini engelle if (cleaned.lastIndexOf(' ') > maxLength * 0.7) { cleaned = cleaned.substring(0, cleaned.lastIndexOf(' ')); } cleaned += '...'; } return cleaned; }; /** * Güçlü parola oluşturucu * @param {Object} options - Parola seçenekleri * @returns {string} Oluşturulan parola */ export const generatePassword = (options = {}) => { const { length = 12, includeUppercase = true, includeLowercase = true, includeNumbers = true, includeSymbols = true, excludeSimilar = true, readable = false } = options; let chars = ''; if (includeLowercase) chars += 'abcdefghijklmnopqrstuvwxyz'; if (includeUppercase) chars += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; if (includeNumbers) chars += '0123456789'; if (includeSymbols) chars += '!@#$%^&*()_+-=[]{}|;:,.<>?'; // Benzer karakterleri çıkar (0, O, l, I, 1) if (excludeSimilar) { chars = chars.replace(/[0OlI1]/g, ''); } // Okunabilir parola (sadece harf ve rakam) if (readable) { chars = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'; } if (!chars) { throw new Error('No character set selected for password generation'); } let password = ''; for (let i = 0; i < length; i++) { password += chars.charAt(Math.floor(Math.random() * chars.length)); } return password; }; /** * Metin benzerlik oranı hesapla (Levenshtein mesafesi) * @param {string} str1 - Birinci metin * @param {string} str2 - İkinci metin * @returns {number} Benzerlik oranı (0-1 arası) */ export const calculateSimilarity = (str1, str2) => { if (!str1 || !str2 || typeof str1 !== 'string' || typeof str2 !== 'string') { return 0; } if (str1 === str2) return 1; const len1 = str1.length; const len2 = str2.length; if (len1 === 0) return len2 === 0 ? 1 : 0; if (len2 === 0) return 0; const matrix = []; for (let i = 0; i <= len2; i++) { matrix[i] = [i]; } for (let j = 0; j <= len1; j++) { matrix[0][j] = j; } for (let i = 1; i <= len2; i++) { for (let j = 1; j <= len1; j++) { if (str2.charAt(i - 1) === str1.charAt(j - 1)) { matrix[i][j] = matrix[i - 1][j - 1]; } else { matrix[i][j] = Math.min( matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1 ); } } } const distance = matrix[len2][len1]; const maxLength = Math.max(len1, len2); return (maxLength - distance) / maxLength; }; /** * Metin formatları - kelime sayısı, karakter sayısı vs. * @param {string} text - Analiz edilecek metin * @returns {Object} Metin istatistikleri */ export const analyzeText = (text) => { if (!text || typeof text !== 'string') { return { characters: 0, charactersNoSpace: 0, words: 0, sentences: 0, paragraphs: 0, readingTime: 0 }; } const characters = text.length; const charactersNoSpace = text.replace(/\s/g, '').length; const words = text.trim() ? text.trim().split(/\s+/).length : 0; const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 0).length; const paragraphs = text.split(/\n\s*\n/).filter(p => p.trim().length > 0).length; // Okuma süresi (dakika) - ortalama 200 kelime/dakika const readingTime = Math.ceil(words / 200); return { characters, charactersNoSpace, words, sentences, paragraphs, readingTime }; }; // Tüm string utility fonksiyonları dışa aktar export const stringUtils = { turkishToEnglish, createSlug, sanitizeText, generatePassword, calculateSimilarity, analyzeText }; export default stringUtils;