UNPKG

anitimejs

Version:

Thư viện xử lý chuỗi số và thời gian trong JavaScript/Typescript

386 lines (385 loc) 16.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.random = void 0; const random = (options = {}) => { const { // Các tùy chọn cơ bản includeUppercase = false, includeLowercase = false, includeNumbers = false, includeSpecials = false, customCharset = "", min, max, step = 1, exclude = [], excludeRegex, filter, probability = {}, distribution = "uniform", distributionParams = {}, length = 1, data = [], unique = false, sort = false, format = "auto", formatTemplate = "", prefix = "", suffix = "", seed, groupBy, mapFunction, // Các tùy chọn loại đặc biệt type = "default", uuidOptions = { dashes: true, version: 4 }, colorOptions = { alpha: false, format: "hex", minBrightness: 0, maxBrightness: 1, }, filenameOptions = { extension: "", includeTimestamp: false, nameLength: 8 }, } = options; // Các bộ ký tự cơ bản const uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const lowercaseChars = "abcdefghijklmnopqrstuvwxyz"; const numberChars = "0123456789"; const specialChars = "!@#$%^&*()-_=+[]{}|;:'\",.<>?/`~"; // Khởi tạo bộ sinh số ngẫu nhiên với hạt giống (nếu có) let randomFunction = Math.random; if (seed !== undefined) { // Bộ sinh số ngẫu nhiên có thể tái tạo sử dụng hạt giống const seededRandom = createSeededRandom(seed); randomFunction = seededRandom.next; } // Xây dựng tập hợp ký tự let pool = ""; if (includeUppercase) pool += uppercaseChars; if (includeLowercase) pool += lowercaseChars; if (includeNumbers) pool += numberChars; if (includeSpecials) pool += specialChars; if (customCharset) pool += customCharset; // Xử lý các loại random đặc biệt if (type === "uuid") { return generateUUID(uuidOptions); } else if (type === "color") { return generateColor(colorOptions); } else if (type === "filename") { return generateFilename(filenameOptions, prefix); } // Lọc các ký tự bị loại trừ const exclusionFilter = (item) => { // Kiểm tra loại trừ bằng giá trị if (exclude.some((excluded) => { if (typeof excluded === "object" && typeof item === "object") return JSON.stringify(excluded) === JSON.stringify(item); return excluded === item; })) return false; // Kiểm tra loại trừ bằng regex if (excludeRegex && typeof item === "string") { const regexes = Array.isArray(excludeRegex) ? excludeRegex : [excludeRegex]; if (regexes.some((regex) => regex.test(item))) return false; } // Áp dụng hàm lọc tùy chỉnh if (filter && !filter(item)) return false; return true; }; // Xử lý random số trong phạm vi if (min !== undefined && max !== undefined) { if (min > max) throw new Error("`min` phải nhỏ hơn hoặc bằng `max`."); // Tạo mảng phạm vi với bước nhảy const range = []; for (let i = min; i <= max; i += step) { range.push(i); } const filteredRange = range.filter(exclusionFilter); if (filteredRange.length === 0) { throw new Error("Không có giá trị nào trong phạm vi sau khi áp dụng các điều kiện loại trừ"); } // Random từ phạm vi số return generateRandomResult(filteredRange); } // Xử lý random từ pool ký tự if (pool.length > 0) { const filteredPool = pool.split("").filter(exclusionFilter); if (filteredPool.length === 0) { throw new Error("Không có ký tự nào hợp lệ để random sau khi áp dụng các điều kiện loại trừ"); } // Xử lý mẫu định dạng nếu có if (formatTemplate) { return applyFormatTemplate(formatTemplate, filteredPool); } // Random từ tập ký tự return generateRandomResult(filteredPool); } // Xử lý random từ mảng dữ liệu if (data.length > 0) { const filteredData = data.filter(exclusionFilter); if (filteredData.length === 0) { throw new Error("Không có phần tử nào trong data sau khi áp dụng các điều kiện loại trừ"); } // Random từ mảng dữ liệu return generateRandomResult(filteredData); } throw new Error("Không có dữ liệu hợp lệ để random. Vui lòng cung cấp tập ký tự, phạm vi số hoặc mảng dữ liệu."); // Hàm tạo kết quả ngẫu nhiên từ tập dữ liệu đầu vào function generateRandomResult(items) { let result; // Áp dụng phân phối xác suất if (unique) { // Trường hợp unique: trộn và lấy các phần tử đầu tiên result = shuffleArray(items).slice(0, Math.min(items.length, length)); } else { // Trường hợp không unique: random với phân phối đã chọn result = Array.from({ length }, () => { return getRandomItemWithDistribution(items); }); } // Áp dụng hàm biến đổi nếu có if (mapFunction) { result = result.map(mapFunction); } // Sắp xếp kết quả nếu có yêu cầu if (sort) { if (typeof sort === "function") { result.sort(sort); } else { result.sort((a, b) => { if (typeof a === "number" && typeof b === "number") return a - b; return String(a).localeCompare(String(b)); }); } } // Nhóm kết quả nếu có yêu cầu if (groupBy && groupBy > 0) { const groups = []; for (let i = 0; i < result.length; i += groupBy) { groups.push(result.slice(i, i + groupBy)); } return groups; } // Định dạng kết quả cuối cùng if (typeof items[0] === "string" && format !== "array") { // Ghép chuỗi nếu các phần tử là chuỗi và không yêu cầu định dạng mảng const stringResult = result.join(""); return prefix + stringResult + suffix; } // Trả về kết quả: số duy nhất, phần tử duy nhất hoặc mảng if (length === 1 && format !== "array") { return prefix ? prefix + String(result[0]) + suffix : result[0]; } // Thêm prefix và suffix cho từng phần tử nếu có if ((prefix || suffix) && typeof result[0] === "string") { return result.map((item) => prefix + String(item) + suffix); } return result; } // Hàm lấy phần tử ngẫu nhiên theo phân phối function getRandomItemWithDistribution(items) { var _a, _b, _c; switch (distribution) { case "normal": { // Phân phối chuẩn (Gaussian) const mean = (_a = distributionParams.mean) !== null && _a !== void 0 ? _a : items.length / 2; const stdDev = (_b = distributionParams.stdDev) !== null && _b !== void 0 ? _b : items.length / 6; let index = Math.floor(normalRandom(mean, stdDev)); // Đảm bảo index nằm trong phạm vi hợp lệ index = Math.max(0, Math.min(items.length - 1, index)); return items[index]; } case "exponential": { // Phân phối hàm mũ const lambda = (_c = distributionParams.lambda) !== null && _c !== void 0 ? _c : 1; const value = -Math.log(1 - randomFunction()) / lambda; const index = Math.floor(value * items.length) % items.length; return items[index]; } case "custom": { // Phân phối tùy chỉnh if (!distributionParams.custom) { throw new Error("Hàm phân phối tùy chỉnh không được cung cấp"); } let total = 0; const weights = []; for (let i = 0; i < items.length; i++) { const weight = distributionParams.custom(i / items.length); weights.push(weight); total += weight; } const r = randomFunction() * total; let acc = 0; for (let i = 0; i < items.length; i++) { acc += weights[i]; if (r <= acc) return items[i]; } return items[items.length - 1]; } case "uniform": default: { // Phân phối đều hoặc phân phối theo trọng số return weightedRandom(items, probability); } } } // Hàm random theo trọng số (xác suất) function weightedRandom(items, probabilities) { const totalWeight = items.reduce((sum, item) => { const key = typeof item === "object" ? JSON.stringify(item) : String(item); return sum + (probabilities[key] || 1); }, 0); let r = randomFunction() * totalWeight; for (const item of items) { const key = typeof item === "object" ? JSON.stringify(item) : String(item); const weight = probabilities[key] || 1; if (r < weight) return item; r -= weight; } return items[items.length - 1]; // Fallback } // Hàm trộn ngẫu nhiên mảng function shuffleArray(arr) { const array = [...arr]; for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(randomFunction() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; } // Hàm áp dụng mẫu định dạng function applyFormatTemplate(template, charPool) { return (prefix + template.replace(/[#?*]/g, (symbol) => { const randomIndex = Math.floor(randomFunction() * charPool.length); return charPool[randomIndex]; }) + suffix); } // Hàm tạo số ngẫu nhiên theo phân phối chuẩn function normalRandom(mean, stdDev) { // Thuật toán Box-Muller để tạo số ngẫu nhiên theo phân phối chuẩn const u1 = randomFunction(); const u2 = randomFunction(); const z0 = Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(2.0 * Math.PI * u2); return mean + z0 * stdDev; } // Tạo bộ sinh số ngẫu nhiên có thể tái tạo từ hạt giống function createSeededRandom(seed) { let state = seed; // Thuật toán Xorshift để tạo số ngẫu nhiên function next() { state ^= state << 13; state ^= state >> 17; state ^= state << 5; // Chuẩn hóa về phạm vi [0, 1) return (state >>> 0) / 4294967296; } return { next }; } // Hàm tạo UUID ngẫu nhiên function generateUUID(options = {}) { const { dashes = true, version = 4 } = options; const hexChars = "0123456789abcdef"; let uuid = ""; for (let i = 0; i < 36; i++) { if (dashes && (i === 8 || i === 13 || i === 18 || i === 23)) { uuid += "-"; } else if (i === 14) { uuid += version.toString(); // Phiên bản UUID } else if (i === 19) { // Byte xác định variant (8, 9, A hoặc B) uuid += hexChars.charAt(8 + Math.floor(randomFunction() * 4)); } else { uuid += hexChars.charAt(Math.floor(randomFunction() * 16)); } } return uuid; } // Hàm tạo mã màu ngẫu nhiên function generateColor(options = {}) { const { alpha = false, format = "hex", minBrightness = 0, maxBrightness = 1, } = options; // Tạo các giá trị RGB với độ sáng trong khoảng cho phép let r, g, b, a; do { r = Math.floor(randomFunction() * 256); g = Math.floor(randomFunction() * 256); b = Math.floor(randomFunction() * 256); // Tính độ sáng (0-1) theo công thức sRGB luminance const brightness = (0.299 * r + 0.587 * g + 0.114 * b) / 255; // Tiếp tục nếu độ sáng không nằm trong khoảng yêu cầu if (brightness >= minBrightness && brightness <= maxBrightness) { break; } } while (true); // Tạo giá trị alpha nếu cần if (alpha) { a = randomFunction().toFixed(2); } // Trả về theo định dạng yêu cầu switch (format) { case "rgb": return alpha ? `rgba(${r}, ${g}, ${b}, ${a})` : `rgb(${r}, ${g}, ${b})`; case "hsl": { // Chuyển RGB sang HSL const rNorm = r / 255; const gNorm = g / 255; const bNorm = b / 255; const max = Math.max(rNorm, gNorm, bNorm); const min = Math.min(rNorm, gNorm, bNorm); let h = 0; let s = 0; const l = (max + min) / 2; if (max !== min) { const d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case rNorm: h = (gNorm - bNorm) / d + (gNorm < bNorm ? 6 : 0); break; case gNorm: h = (bNorm - rNorm) / d + 2; break; case bNorm: h = (rNorm - gNorm) / d + 4; break; } h /= 6; } const hDeg = Math.round(h * 360); const sPercent = Math.round(s * 100); const lPercent = Math.round(l * 100); return alpha ? `hsla(${hDeg}, ${sPercent}%, ${lPercent}%, ${a})` : `hsl(${hDeg}, ${sPercent}%, ${lPercent}%)`; } case "hex": default: let hexColor = "#" + r.toString(16).padStart(2, "0") + g.toString(16).padStart(2, "0") + b.toString(16).padStart(2, "0"); if (alpha) { const alphaHex = Math.floor(parseFloat(a) * 255) .toString(16) .padStart(2, "0"); hexColor += alphaHex; } return hexColor; } } // Hàm tạo tên tệp ngẫu nhiên function generateFilename(options = {}, prefix = "") { const { extension = "", includeTimestamp = false, nameLength = 8, } = options; const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; let filename = prefix; // Thêm timestamp nếu cần if (includeTimestamp) { filename += Date.now() + "-"; } // Tạo phần ngẫu nhiên for (let i = 0; i < nameLength; i++) { filename += chars.charAt(Math.floor(randomFunction() * chars.length)); } // Thêm phần mở rộng nếu có if (extension) { if (!extension.startsWith(".")) { filename += "."; } filename += extension; } return filename; } }; exports.random = random;