houser-js-utils
Version:
A comprehensive collection of TypeScript utility functions for common development tasks including array manipulation, string processing, date handling, random number generation, validation, and much more.
1 lines • 10.4 kB
Source Map (JSON)
{"version":3,"file":"FileUtils.mjs","sources":["../src/FileUtils.ts"],"sourcesContent":["/**\n * @module FileUtils\n * @description A collection of utility functions for file operations, validation, and manipulation.\n * @example\n * ```typescript\n * import { FileUtils } from 'houser-js-utils';\n *\n * // Get file extension\n * const ext = FileUtils.getFileExtension('document.pdf'); // 'pdf'\n *\n * // Validate file type\n * const isImage = FileUtils.isImageFile(file);\n *\n * // Format file size\n * const size = FileUtils.formatFileSize(file.size);\n * ```\n */\n\n// Type declarations for IE-specific navigator methods\ndeclare global {\n interface Navigator {\n msSaveOrOpenBlob?: (blob: Blob, filename: string) => void;\n }\n}\n\n/**\n * Basic file types supported by the utility functions.\n */\ntype FileType = \"image\" | \"video\" | \"audio\" | \"document\";\n\n/**\n * Interface representing file data with optional media ID and metadata.\n */\nexport interface FileData {\n /** Optional media identifier */\n mediaId?: string;\n /** File name */\n name: string;\n /** File MIME type */\n type: string;\n /** Optional file metadata */\n data?: {\n /** Optional media identifier */\n mediaId?: string;\n /** File name */\n name: string;\n };\n}\n\n/**\n * Mappings of basic file types to their MIME type patterns.\n */\nconst fileTypeMappings: Record<string, string> = {\n image: \"image.*\",\n video: \"video.*\",\n audio: \"audio.*\",\n};\n\n/**\n * Utility object containing file handling functions.\n */\nexport const FileUtils = {\n /**\n * Converts bytes to a human-readable size string.\n *\n * @param bytes - Number of bytes to convert\n * @returns Formatted size string (e.g., \"1.5 MB\")\n *\n * @example\n * ```typescript\n * const size = FileUtils.bytesToSize(1500000); // \"1.5 MB\"\n * ```\n */\n bytesToSize(bytes: number): string {\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\", \"TB\"];\n if (bytes === 0) return \"0 Byte\";\n const i = Math.floor(Math.log(bytes) / Math.log(1024));\n return `${Math.round(bytes / 1024 ** i)} ${sizes[i]}`;\n },\n\n /**\n * Downloads a blob as a file.\n * Supports both modern browsers and IE.\n *\n * @param blob - Blob to download\n * @param filename - Name of the file to save as\n *\n * @example\n * ```typescript\n * const blob = new Blob(['Hello World'], { type: 'text/plain' });\n * FileUtils.downloadBlob(blob, 'hello.txt');\n * ```\n */\n downloadBlob(blob: Blob, filename: string): void {\n if (window.navigator.msSaveOrOpenBlob) {\n window.navigator.msSaveOrOpenBlob(blob, filename);\n } else {\n const objectUrl = window.URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = objectUrl;\n a.style.display = \"none\";\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n window.URL.revokeObjectURL(objectUrl);\n document.body.removeChild(a);\n }\n },\n\n /**\n * Extracts base64 data from a local URL.\n *\n * @param url - URL containing base64 data\n * @returns Base64 string or original URL if no base64 data found\n *\n * @example\n * ```typescript\n * const base64 = FileUtils.extractBase64FromLocalUrl('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...');\n * ```\n */\n extractBase64FromLocalUrl(url: string): string {\n if (!url?.length) return url;\n\n const urlDataIdx = url.indexOf(\"base64,\");\n if (urlDataIdx === -1) return url;\n\n return url.substring(urlDataIdx + 7);\n },\n\n /**\n * Checks if a file is already attached to a list of files.\n *\n * @param file - File to check\n * @param files - List of files to check against\n * @returns The matching file if found, undefined otherwise\n *\n * @example\n * ```typescript\n * const isDuplicate = FileUtils.fileIsAlreadyAttached(newFile, existingFiles);\n * ```\n */\n fileIsAlreadyAttached(\n file: FileData,\n files: FileData[]\n ): FileData | undefined {\n return files.find((f) => {\n const { mediaId, name } = f.data || {};\n const { mediaId: fileMediaId, name: fileName } = file.data || {};\n return fileMediaId ? mediaId === fileMediaId : name === fileName;\n });\n },\n\n /**\n * Gets the basic file type (image, video, audio, or document).\n *\n * @param file - File to check\n * @returns Basic file type\n *\n * @example\n * ```typescript\n * const type = FileUtils.getBasicFileType(imageFile); // \"image\"\n * ```\n */\n getBasicFileType(file: File): FileType {\n for (const type of Object.keys(fileTypeMappings)) {\n if (file.type.match(fileTypeMappings[type])) {\n return type as FileType;\n }\n }\n\n return \"document\";\n },\n\n /**\n * Gets a base64 preview of an image file.\n *\n * @param file - Image file to preview\n * @returns Promise resolving to base64 string of the image\n * @throws Error if file is not an image or fails to load\n *\n * @example\n * ```typescript\n * const preview = await FileUtils.getImagePreview(imageFile);\n * ```\n */\n async getImagePreview(file: File): Promise<string> {\n if (!file?.type.startsWith(\"image/\")) {\n return \"\";\n }\n\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n\n reader.onload = (e) => {\n const img = document.createElement(\"img\");\n img.onload = () => resolve(e.target?.result as string);\n img.onerror = () => reject(new Error(\"Failed to load image\"));\n img.src = e.target?.result as string;\n };\n\n reader.onerror = () => reject(new Error(\"Failed to read file\"));\n reader.readAsDataURL(file);\n });\n },\n\n /**\n * Gets a local URL for a file.\n *\n * @param file - File to get URL for\n * @param callback - Callback function to receive the URL\n *\n * @example\n * ```typescript\n * FileUtils.getLocalUrl(file, (url) => {\n * console.log('File URL:', url);\n * });\n * ```\n */\n getLocalUrl(file: File, callback: (url: string) => void): void {\n const reader = new FileReader();\n reader.onload = (e) => callback(e.target?.result as string);\n reader.onerror = (error) => console.error(error);\n reader.readAsDataURL(file);\n },\n\n /**\n * Checks if a value is a valid file extension.\n *\n * @param extension - File extension to validate\n * @returns True if valid, false otherwise\n *\n * @example\n * ```typescript\n * const isValid = FileUtils.isFileExtension('jpg'); // true\n * ```\n */\n isFileExtension(extension: string): boolean {\n const extensionRegex = /^[a-zA-Z0-9]+$/;\n return extensionRegex.test(extension);\n },\n\n /**\n * Converts a size with units to bytes.\n *\n * @param size - Size to convert\n * @param units - Units of the size (B, KB, MB, GB, TB)\n * @returns Size in bytes\n *\n * @example\n * ```typescript\n * const bytes = FileUtils.sizeToBytes(1.5, 'MB'); // 1572864\n * ```\n */\n sizeToBytes(size: string | number, units: string): number {\n if (!size) return 0;\n\n const sizeNum = parseFloat(String(size));\n if (Number.isNaN(sizeNum)) return 0;\n\n switch (units.toUpperCase()) {\n case \"KB\":\n return sizeNum * 1024;\n case \"MB\":\n return sizeNum * 1024 * 1024;\n case \"GB\":\n return sizeNum * 1024 * 1024 * 1024;\n case \"TB\":\n return sizeNum * 1024 * 1024 * 1024 * 1024;\n default:\n return sizeNum;\n }\n },\n};\n"],"names":[],"mappings":"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"}