All files / src/libs/Helper General.ts

91.93% Statements 57/62
86.36% Branches 19/22
91.66% Functions 11/12
92.85% Lines 52/56

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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 2131x 1x   1x                                     1x 1x                                 4x   4x 2x   2x   2x 1x     1x                         2x   2x                               3x 1x       2x   2x   1x 1x 1x       1x   1x       2x   6x 2x   2x     2x     2x     2x 6x           6x       2x     2x                 1x                 11x   7x           4x   1x   1x 3x       3x   3x 4x           4x                       3x 3x   3x         3x     3x                 2x   2x      
import { moment } from 'obsidian';
import { ImplementsStatic } from 'src/classes/decorators/ImplementsStatic';
import { Singleton } from 'src/classes/decorators/Singleton';
import { Register } from '../DependencyInjection/decorators/Register';
import { Lifecycle } from '../LifecycleManager/decorators/Lifecycle';
 
export interface IHelperGeneral_ {
    generateUID(input: string, length: number, sufix?: string): string;
    generateAcronym(text: string, length: number, prefix: string): string;
    sleep(ms: number): Promise<void>;
    deepClone<T>(obj: T): T;
    containsMarkdown(text: string): boolean;
    isEmoji(str: string): boolean;
}
 
/**
 * Represents a class for general helper methods.
 * @see {@link Singleton}
 * @see {@link Lifecycle}
 */
@ImplementsStatic<IHelperGeneral_>()
@Register('IHelperGeneral_')
export class HelperGeneral {
    private static readonly _md5 = require('crypto-js/md5');
 
    /**
     * Create a Singleton instance of the HelperObsidian class.
     */
    public constructor() {
        throw new Error('This class is not meant to be instantiated');
    }
 
    /**
     * Formats a date string according to the specified format.
     * @param date - The date string to be formatted.
     * @param format - The format string specifying the desired output format.
     * @returns The formatted date string, or the original date string if it is not in a valid format.
     */
    public static formatDate(date: string, format: string): string {
        const regexDate =
            /^\d{4}-\d{2}-\d{2}(T\d{2}(:\d{2}(:\d{2}(\.\d{3})?)?)?)?$/;
 
        if (!regexDate.test(date)) {
            return date;
        }
        const formatedDate = moment(date).format(format);
 
        if (formatedDate === 'Invalid date') {
            return date;
        }
 
        return formatedDate;
    }
 
    /**
     * Generates a UID from the given input
     * @param input The input to generate the UID from
     * @param length The length of the UID
     * @param sufix The sufix to add to the UID
     * @returns The generated UID with the given length
     * @remarks - This method uses the MD5 hash algorithm to generate the UID
     * - The UID is prefixed with a "U" to prevent the UID from starting with a number. The "U" counts to the length of the UID
     */
    public static generateUID(input: string, length = 8, sufix = 'U'): string {
        const hash = sufix + this._md5(input).toString();
 
        return hash.substring(0, length);
    }
 
    /**
     * Generates an acronym from the given text.
     * @param text The input text to generate the acronym from.
     * @param length The desired length of the acronym, default is 6.
     * @param prefix The prefix for the acronym, default is current year.
     * @returns The generated acronym with the specified prefix.
     */
    public static generateAcronym(
        text: string,
        length = 6,
        prefix = 'year',
    ): string {
        // Return an empty string if text is not provided
        if (!text) {
            return '';
        }
 
        // Determine the prefix based on the input or date
        let prefixValue = '';
 
        if (prefix === 'year') {
            // Extract the last two digits of the current year
            const currentYear: number = new Date().getFullYear();
            prefixValue = currentYear.toString().substring(2);
        } else Iif (prefix === 'month') {
            // Format the current month as a two-digit number
            const currentMonth: number = new Date().getMonth() + 1;
            prefixValue = currentMonth.toString().padStart(2, '0');
        } else if (prefix) {
            // Use the provided prefix if it's not related to date
            prefixValue = prefix;
        }
 
        // Split the text into words and filter out empty words
        const words: string[] = text
            .split(' ')
            .filter((word) => word.trim().length > 0);
        let acronym = '';
        // Determine the maximum number of characters per word
        let maxChars: number = Math.floor(length / words.length);
 
        // Ensure at least one character per word
        Iif (maxChars < 1) maxChars = 1;
 
        // Adjust maxChars if total length is insufficient
        if (maxChars * words.length < length) maxChars++;
 
        // Construct the acronym from the words
        for (let i = 0; i < words.length; i++) {
            acronym += words[i].substring(
                0,
                Math.min(maxChars, words[i].length),
            );
 
            // Stop if desired length is reached
            if (acronym.length >= length) break;
        }
 
        // Limit the acronym to the desired length
        acronym = acronym.substring(0, length);
 
        // Combine the prefix and the acronym
        return prefixValue + acronym;
    }
 
    /**
     * Sleeps for the given amount of milliseconds
     * @param ms The amount of milliseconds to sleep
     * @returns A promise that resolves after the given amount of milliseconds
     */
    public static async sleep(ms: number): Promise<void> {
        return new Promise((resolve) => setTimeout(resolve, ms));
    }
 
    /**
     * Deep clones any object.
     * @param obj - The object to be cloned.
     * @returns The cloned object.
     */
    public static deepClone<T>(obj: T): T {
        if (obj === null || typeof obj !== 'object') {
            // The value is not cloneable (e.g., primitive type), so return it directly
            return obj;
        }
 
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        let clonedObj: any;
 
        if (Array.isArray(obj)) {
            // Handle arrays
            clonedObj = [];
 
            obj.forEach((val, i) => {
                clonedObj[i] = HelperGeneral.deepClone(val);
            });
        } else {
            // Handle objects
            clonedObj = {};
 
            Object.keys(obj).forEach((key) => {
                clonedObj[key] = HelperGeneral.deepClone(
                    (obj as { [key: string]: unknown })[key],
                );
            });
        }
 
        return clonedObj as T;
    }
 
    /**
     * Checks if the given text is possibly markdown
     * @param text The text to check
     * @returns Whether the text is possibly markdown (true or false)
     * @remarks - This method checks if the text contains any of the following symbols:
     * - `*`, `_`, `[`, `]`, `=` and `-` if there is a line break
     */
    public static containsMarkdown(text: string): boolean {
        let regexMarkdownSymbols;
        const regexLineBreak = /\r?\n/;
        const lineBreak = regexLineBreak.test(text);
 
        Iif (lineBreak) {
            // If there is a line break, we need to check for the list symbol
            regexMarkdownSymbols = /[*_\-[\]=]/;
        } else {
            // If there is no line break, we do not need to check for the list symbol
            regexMarkdownSymbols = /[*_[\]=]/;
        }
 
        return regexMarkdownSymbols.test(text);
    }
 
    /**
     * Checks if the given string is an emoji
     * @param str The string to check
     * @returns Whether the string is an emoji (true or false)
     */
    public static isEmoji(str: string): boolean {
        const emojiRegex = /(\p{Emoji_Presentation}|\p{Emoji}\uFE0F)/u;
 
        return emojiRegex.test(str);
    }
}
 
Zur TypeDoc-Dokumentation