All files / src/core/utils Utils.ts

96.72% Statements 59/61
96.42% Branches 27/28
100% Functions 7/7
96.72% Lines 59/61

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150              1x                     1x 784x     784x   82x 782x 702x   702x 702x   702x 702x 702x   784x 784x                       1x 450x   450x 450x 450x 450x   450x 450x                       1x 364x 364x                   1x 89x 89x 89x 89x 89x 89x 1x 1x 89x                   1x 174x 174x 174x 174x 174x 174x 1x 1x 174x                   1x 88x 88x 88x     88x                         1x 31x 31x   31x 20x   3x 3x 31x 1x  
import type { KeyPath, TTL } from "../types";
 
/**
 * Class Helper
 * @internal
 * @ignore
 */
export const Utils = {
	/**
	 * Extracts the primary key from a given KeyPath.
	 *
	 * If the KeyPath is an array, the method returns the first element as a string.
	 * If the KeyPath is a string with indexing format (e.g., "keyName[0].name"),
	 * the method returns the first part before a "." or "[".
	 *
	 * @param keyPath - The KeyPath from which to extract the primary key.
	 * @returns The extracted primary key as a string.
	 */
	getKey(keyPath: KeyPath): string {
		let key = "";
 
		// Verificar se keyPath é um array
		if (Array.isArray(keyPath)) {
			// Retorna a primeira chave do array (ex: ["keyName", "subKey"] -> "keyName")
			key = keyPath.length > 0 ? String(keyPath[0]) : "";
		} else {
			key = keyPath.toString();
			// Verificar se é uma string com formato de indexação (ex: "keyName[0].name")
			const match = keyPath.match(/^[^.[\]]+/);
			if (match) {
				// Retorna a primeira parte antes de "." ou "["
				key = match[0];
			}
		}
 
		return key;
	},
 
	/**
	 * Converts a TTL to milliseconds.
	 *
	 * If the TTL is a number, it is returned as is.
	 * If the TTL is an object, the method sums up the milliseconds from the
	 * following properties: seconds, minutes, hours, and days.
	 *
	 * @param ttl - The TTL to convert.
	 * @returns The TTL converted to milliseconds.
	 */
	convertTTLToMilliseconds(ttl: TTL): number {
		if (typeof ttl === "number") return ttl;
 
		const s = (ttl.seconds || 0) * 1000;
		const m = (ttl.minutes || 0) * 60 * 1000;
		const h = (ttl.hours || 0) * 60 * 60 * 1000;
		const d = (ttl.days || 0) * 24 * 60 * 60 * 1000;
 
		return s + m + h + d;
	},
 
	/**
	 * Checks if a given expiresAt timestamp has expired.
	 *
	 * If the expiresAt timestamp is greater than 0, the method checks if the
	 * current time is greater than or equal to the expiresAt timestamp. If the
	 * expiresAt timestamp is 0 or less, the method returns false.
	 *
	 * @param expiresAt - The timestamp to check.
	 * @returns True if the timestamp has expired, false otherwise.
	 */
	isExpired(expiresAt: number): boolean {
		return expiresAt > 0 ? expiresAt <= Date.now() : false;
	},
 
	/**
	 * Checks if the sessionStorage is available.
	 *
	 * This method tries to set and remove an item from the sessionStorage.
	 * If the operation is successful, it returns true. Otherwise, it returns false.
	 *
	 * @returns true if the sessionStorage is available, false otherwise.
	 */
	isSessionStorageAvailable(): boolean {
		try {
			const testKey = "__test__";
			sessionStorage.setItem(testKey, testKey);
			sessionStorage.removeItem(testKey);
			return true;
		} catch (_ex) {
			return false;
		}
	},
 
	/**
	 * Checks if the localStorage is available.
	 *
	 * This method tries to set and remove an item from the localStorage.
	 * If the operation is successful, it returns true. Otherwise, it returns false.
	 *
	 * @returns true if the localStorage is available, false otherwise.
	 */
	isLocalStorageAvailable(): boolean {
		try {
			const testKey = "__test__";
			localStorage.setItem(testKey, testKey);
			localStorage.removeItem(testKey);
			return true;
		} catch (_ex) {
			return false;
		}
	},
 
	/**
	 * Checks if the IndexedDB is available.
	 *
	 * This method simply checks if the IndexedDB is available in the window object.
	 * If the IndexedDB is available, it returns true. Otherwise, it returns false.
	 *
	 * @returns true if the IndexedDB is available, false otherwise.
	 */
	isIndexedDBAvailable(): boolean {
		try {
			return "indexedDB" in window;
		} catch {
			return false;
		}
	},
 
	/**
	 * Calculates the size of the given bytes as a human-readable string.
	 *
	 * If the bytes is 0 or less, the method returns "0b".
	 * If the bytes is less than 1024, the method returns the size in bytes.
	 * Otherwise, the method calculates the size in kilobytes, megabytes, or gigabytes
	 * and returns the result as a string with the corresponding unit.
	 *
	 * @param bytes - The number of bytes to calculate the size for.
	 * @returns The calculated size as a human-readable string.
	 */
	calculateStorageSize(bytes: number): string {
		const BYTES_PER_KB = 1024;
		const UNITS = ["b", "kb", "mb", "gb"];
 
		if (bytes <= 0) return "0b";
		if (bytes < BYTES_PER_KB) return `${bytes}b`;
 
		const i = Math.floor(Math.log(bytes) / Math.log(1024));
		return Number.parseFloat((bytes / 1024 ** i).toFixed(2)) + UNITS[i];
	},
};