import _ from 'lodash'; export const isNotEmptyValue = (value: any) => { if (Array.isArray(value)) { return value.length > 0; } return !!value || value === 0 || value === false; }; export const isNotEmptyValueAllowNull = (value: any) => { if (Array.isArray(value)) { return value.length > 0; } return !!value || value === 0 || value === false || value === null; }; export const handleBatchRequest = async ( list: any[], fn: (args: any) => void ) => { return Promise.allSettled(list.map((item) => fn(item))); }; export const convertFileSize = ( sizeInBytes: number, prec = 1, allowEmpty = false ): string | number => { if (!sizeInBytes) return allowEmpty ? '' : 0; const fmt = 1024; const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB']; const precs = [0, 1, 1, 2, 2]; // precision for each unit let size = sizeInBytes; let unitIndex = 0; while (size >= fmt && unitIndex < units.length - 1) { size /= fmt; unitIndex++; } return `${_.round(size, precs[unitIndex])} ${units[unitIndex]}`; }; export const convertFileSizeByUnit = (params: { sizeInBytes: number; defaultUnit?: 'B' | 'KiB' | 'MiB' | 'GiB' | 'TiB'; allowEmpty?: boolean; }): string | number => { const { sizeInBytes, allowEmpty = false, defaultUnit = 'B' } = params; if (!sizeInBytes) return allowEmpty ? '' : 0; const fmt = 1024; const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB']; const precs = [0, 1, 1, 2, 2]; // precision for each unit let size = sizeInBytes; let unitIndex = units.indexOf(defaultUnit); while (size >= fmt && unitIndex < units.length - 1) { size /= fmt; unitIndex++; } return `${_.round(size, precs[unitIndex])} ${units[unitIndex]}`; }; export const platformCall = () => { const platform = navigator.userAgent; const isMac = () => { return platform.indexOf('Mac') !== -1; }; const isWin = () => { return platform.indexOf('Win') !== -1; }; return { isMac: isMac(), isWin: isWin() }; }; export const formatTime = (seconds: number) => { if (isNaN(seconds) || !seconds || seconds === Infinity) { return '00:00'; } const hrs = Math.floor(seconds / 3600); const mins = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); const formatted = [ hrs.toString().padStart(2, '0'), mins.toString().padStart(2, '0'), secs.toString().padStart(2, '0') ]; if (hrs > 0) { return `${formatted[0]}:${formatted[1]}:${formatted[2]}`; } return `${formatted[1]}:${formatted[2]}`; }; export const formatNumber = (num: number) => { if (!num) { return '0'; } if (num >= 1000000) { return (num / 1000000).toFixed(2) + 'M'; } else if (num >= 1000) { return (num / 1000).toFixed(2) + 'k'; } else { return num.toString(); } }; export const formatLargeNumber = (value: number) => { if (typeof value !== 'number' || isNaN(value)) { return value; } if (value >= 1e9) { return (value / 1e9).toFixed(1).replace(/\.0$/, '') + 'B'; } else if (value >= 1e6) { return (value / 1e6).toFixed(1).replace(/\.0$/, '') + 'M'; } else if (value >= 1e3) { return (value / 1e3).toFixed(1).replace(/\.0$/, '') + 'K'; } else { return value; } }; export function loadLanguageConfig(language: string) { // @ts-ignore const requireContext = require.context(`./${language}`, false, /\.ts$/); const languageConfig: Record = {}; requireContext.keys().forEach((fileName: any) => { const moduleConfig = requireContext(fileName).default; const moduleName = fileName.replace(/(\.\/|\.ts)/g, ''); languageConfig[moduleName] = moduleConfig; }); return languageConfig; } export function readBlob(blob: Blob): Promise { return new Promise((resolve) => { const reader = new FileReader(); reader.onload = function (e: any) { resolve(e.target.result); }; reader.readAsText(blob, 'utf-8'); }); } export const cosineSimilarity = (vec1: number[], vec2: number[]) => { if (vec1.length !== vec2.length) { throw new Error('both vectors must have the same length'); } const dotProduct = vec1.reduce( (sum, value, index) => sum + value * vec2[index], 0 ); const magnitudeA = Math.sqrt( vec1.reduce((sum, value) => sum + value * value, 0) ); const magnitudeB = Math.sqrt( vec2.reduce((sum, value) => sum + value * value, 0) ); if (magnitudeA === 0 || magnitudeB === 0) { throw new Error('both vectors must have a length greater than 0'); } return dotProduct / (magnitudeA * magnitudeB); }; const htmlSpecialTags = /^(.|\n|\r)*<\/html>$/i; export const isHTMLDocumentString = (str: string) => { return htmlSpecialTags.test(str?.trim()); }; // generate a random number between 0 and 64 bit export const generateRandomNumber = () => { // 16: 0x1000;32:0x100000000 return Math.floor(Math.random() * 0x100000000); }; function base64ToBlob(base64: string, contentType = '', sliceSize = 512) { try { const base64Content = base64.replace(/^data:image\/[^;]+;base64,/, ''); const byteCharacters = atob(base64Content); const byteArrays = []; for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) { const slice = byteCharacters.slice(offset, offset + sliceSize); const byteNumbers = new Array(slice.length); for (let i = 0; i < slice.length; i++) { byteNumbers[i] = slice.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); byteArrays.push(byteArray); } return new Blob(byteArrays, { type: contentType }); } catch (error) { return null; } } export const base64ToFile = (base64String: string, fileName: string) => { try { if (!base64String) { return null; } console.log('base64String:', base64String); const match = base64String.match(/data:(.*?);base64,/); if (!match) { throw new Error('Invalid base64 string'); } const contentType = match[1]; const blob = base64ToBlob(base64String, contentType); if (!blob) { throw new Error('Failed to convert base64 to blob'); } return new File([blob], fileName || contentType, { type: contentType }); } catch (error) { return null; } }; // check onlinestatus export const isOnline = () => { return window.navigator.onLine; }; /** * Parse a command-line parameter string into an array format. * @param paramsString - The parameter string to parse (supports multiline). * @returns An array of parameters, e.g. ['--param=value', '--flag'] * * @example * parseParamsString('--foo=bar --baz 123 --flag') * // Returns: ['--foo=bar', '--baz=123', '--flag'] * * parseParamsString(`--foo bar * --baz=123`) * // Returns: ['--foo=bar', '--baz=123'] */ export const parseParamsString = (paramsString: string): string[] => { if (!paramsString || !paramsString.trim()) { return []; } // Convert multiline to single line, replace newlines with spaces // Remove line-continuation backslashes (surrounded by spaces or at end of line) const normalizedString = paramsString .replace(/\n/g, ' ') .replace(/\s\\\s/g, ' ') .replace(/\s+/g, ' ') .trim(); const result: string[] = []; const tokens: string[] = []; let current = ''; let inQuote = false; let quoteChar = ''; let braceDepth = 0; // Curly brace depth // Tokenize, handle quotes and curly braces for (let i = 0; i < normalizedString.length; i++) { const char = normalizedString[i]; if ( (char === '"' || char === "'") && (i === 0 || normalizedString[i - 1] !== '\\') ) { if (!inQuote) { inQuote = true; quoteChar = char; current += char; } else if (char === quoteChar) { inQuote = false; quoteChar = ''; current += char; } else { current += char; } } else if (char === '{' && !inQuote) { braceDepth++; current += char; } else if (char === '}' && !inQuote) { braceDepth--; current += char; } else if (char === ' ' && !inQuote && braceDepth === 0) { if (current) { tokens.push(current); current = ''; } } else { current += char; } } if (current) { tokens.push(current); } // Parse tokens into parameter array for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; // Check if already contains '=' with value if (token.includes('=')) { result.push(token); } else if (token.startsWith('-')) { // Check if next token is a value (does not start with '-') const nextToken = tokens[i + 1]; if (nextToken && !nextToken.startsWith('-') && !nextToken.includes('=')) { // If value is quoted, keep space format if (nextToken.startsWith('"') || nextToken.startsWith("'")) { result.push(`${token} ${nextToken}`); } else { // Otherwise, use '=' to join result.push(`${token}=${nextToken}`); } i++; // Skip next token, already consumed } else { // This is a flag without value result.push(token); } } } return result; }; // ordinal.ts const enOrdinalRules = new Intl.PluralRules('en', { type: 'ordinal' }); const suffixMap: Record = { one: 'st', two: 'nd', few: 'rd', other: 'th' }; export function formatOrdinal(n: number): string { const rule = enOrdinalRules.select(n); return `${n}${suffixMap[rule]}`; }