@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
JavaScript
/**
* 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;