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 213 | 1x 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); } } |