All files / src/utils StringUtils.tsx

65.17% Statements 73/112
68.05% Branches 49/72
76% Functions 19/25
66.66% Lines 72/108

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 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254                  1198x       253x       250x       259x     69x 940x                       836x                                             410x 2x   408x 408x 10x   398x                   214x 214x 214x 214x       518x       518x                                                       3x     69x 3x     69x 3x     69x 5x 2x   3x 3x   1x   2x     69x     5x 5x   3x 3x     2x     69x                                                     69x 2x           2x 2x 2x   2x 2x   2x 2x     69x 8x 2x 6x 2x 1x   1x     4x 1x   3x         69x 3x     3x 3x 3x 3x 3x   3x     69x 8x 8x 15x 3x     5x             69x                      
import { ReactElement } from "react";
import i18n from '@config/i18n';
import { SearchKeywordHighlightContextSize } from "@config/base";
 
/**
 * 将词的第一个字母大写
 * @param input 传入的词
 */
export function capitalizeFirstLetter(input: string): string {
  return (input === '' || input == null) ? input : input.charAt(0).toUpperCase() + input.slice(1);
}
 
export function stripPackagePart(input: string): string {
  return (input === '' || input == null) ? input : input.substring(input.lastIndexOf('_') + 1);
}
 
export function lowerFirstLetterCase(input: string | null | undefined): string {
  return (input === '' || input == null) ? "" : input.charAt(0).toLowerCase() + input.slice(1);
}
 
export function typeWithPackageToSimpleType(input: string | null | undefined): string {
  return (input === '' || input == null) ? "" : lowerFirstLetterCase(stripPackagePart(input));
}
 
export const camelCaseToSentence = (word: string): string =>
  word == null ? "" : capitalizeFirstLetter(word
    .replace(/([A-Z][a-z]+)/g, ' $1')
    .replace(/([A-Z]{2,})/g, ' $1')
    .replace(/\s{2,}/g, ' ')
    .trim());
 
/**
 * Change a string to title style, if the parameter is a ReactNode,
 * then it will be returned back directly
 * @param title the string or react node to be transfer
 */
export function humanReadableTitle(title: string | ReactElement): string | ReactElement {
  return (typeof title != 'string') ? title : camelCaseToSentence(title);
}
 
/**
 * Quote all quotes inside a string using another quote character
 * @param content the string to be quoted
 */
export function quoteQuote(content: string | undefined): string | undefined {
  if (typeof content !== "string") {
    return content;
  }
  if (typeof content.replaceAll !== 'undefined') {
    return content.replaceAll(`"`, `""`);
  } else {
    return content.replace(/`"`/g, `""`);
  }
}
 
/**
 * Remove package part from a type
 * @param content the string to be handle
 */
export function removePackagePart(content: string | undefined): string | undefined {
  if (typeof content !== 'string') {
    return content;
  }
  const lastIndexOfUnderscore = content.lastIndexOf("_");
  if (lastIndexOfUnderscore > 0) {
    return content.substring(lastIndexOfUnderscore + 1);
  }
  return content;
}
 
/**
 * 将包含 java package 的 domainName 修改为界面上显示的不包含 java package,
 * 且将驼峰词转换为空格分隔的单个单词的形式
 * 比如将 tech_muyan_dynamic_form_DynamicForm 转换为 Dynamic Form
 * @param domainName 输入的 domainName
 */
export function fullDomainNameToHumanReadable(domainName: string | undefined): string {
  Iif (domainName == null) return '';
  const domainTitle = capitalizeFirstLetter(typeWithPackageToSimpleType(domainName));
  const key = `domainTitle:${domainTitle}`;
  return i18n.t(key);
}
 
export function getLinkStrRegExp(): RegExp {
  return /((http|https|ftp):\/\/[\w?=&.\\/-;#~%-]+(?![\w\s?&.\\/;#~%"=-]*>))/g;
}
 
export function getMailStrRegExp(): RegExp {
  return /([a-zA-Z0-9_.!#$%&'*+\-/=?^_`{|}~]{1,64}@[a-zA-Z0-9-]{1,255}[.][a-zA-Z]{1,233})/g;
}
 
/** 生成随机的 id */
export function makeid(length: number): string {
  const result = [];
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  const charactersLength = characters.length;
  for (let i = 0; i < length; i++) {
    result.push(characters.charAt(Math.floor(Math.random() *
      charactersLength)));
  }
  return result.join('');
}
 
/**
 * Get query parameter from a url
 * @param urlStr url to parse
 * @param paramName  name of the parameter to parse
 * @returns  value of the parameter
 */
export function getQueryParam(urlStr: string, paramName: string): string | undefined {
  const url = new URL(urlStr);
  const c = url.searchParams.get(paramName);
  return (c == null) ? undefined : c;
}
 
export function trimString(value: string, length: number): string {
  return value?.length > length ? `${value.substring(0, length)}...` : value;
}
 
export const isNotBlank = (word: string | undefined): boolean => {
  return (word != null && word !== '');
};
 
export const isBlank = (word: string | undefined): boolean => {
  return !isNotBlank(word);
};
 
export const isJsonString = (str: string | object): boolean => {
  if (typeof str === 'object') {
    return true;
  }
  try {
    JSON.parse(str);
  } catch (e) {
    return false;
  }
  return true;
};
 
export const formatJson = (jsonString: string): string => {
  let parsedJson: unknown;
 
  try {
    parsedJson = JSON.parse(jsonString);
  } catch (error) {
    console.error("Invalid JSON string provided.");
    return jsonString;
  }
 
  return JSON.stringify(parsedJson, null, 2);
};
 
export const copyToClipBoard = async(copyMe: string): Promise<void> => {
  // navigator clipboard 需要https等安全上下文
  if (navigator.clipboard && window.isSecureContext) {
    // navigator clipboard 向剪贴板写文本
    return navigator.clipboard.writeText(copyMe);
  } else {
    // https://www.cnblogs.com/hellxz/p/15192573.html
    // https://stackoverflow.com/questions/39501289/in-reactjs-how-to-copy-text-to-clipboard
    // 创建text area
    const textArea = document.createElement("textarea");
    textArea.value = copyMe;
    // 使text area不在viewport,同时设置不可见
    textArea.style.position = "absolute";
    textArea.style.opacity = "0";
    textArea.style.left = "-999999px";
    textArea.style.top = "-999999px";
    document.body.appendChild(textArea);
    textArea.focus();
    textArea.select();
    return new Promise((res, rej) => {
      // 执行复制命令并移除文本框
      document.execCommand('copy') ? res() : rej();
      textArea.remove();
    });
  }
};
 
export const stripAbstract = (content: string, searchKeyword: string): string => {
  const firstIndexOfKeyword = content?.toLowerCase().indexOf(searchKeyword?.toLowerCase());
  // 如果 firstIndexOfKeyword 小于 50, 则开始 index 为 0
  // 如果 firstIndexOfKeyword 大于 50, 则开始 index 为 firstIndexOfKeyword - 50
  // 如果 firstIndexOfKeyword 大于 content.length - 50, 则结束 index 为 content.length
  // 如果 firstIndexOfKeyword 小于 content.length - 50, 则结束 index 为 firstIndexOfKeyword + 50
  // 如果 firstIndexOfKeyword 为 -1, 则开始 index 为 0, 结束 index 为 content.length 和 100 之间更小的值
  const cs = SearchKeywordHighlightContextSize;
  const startIndex = (firstIndexOfKeyword < cs) ? 0 : firstIndexOfKeyword - cs;
  const endIndex = (firstIndexOfKeyword === 0) ?
    cs * 2 : (firstIndexOfKeyword < content?.length - cs) ? firstIndexOfKeyword + cs : content?.length;
  const prefix = ((startIndex > 0) ? "... " : "");
  const suffix = ((endIndex < content?.length) ? " ..." : "");
  // Abstract 中去除 Html 标签
  const absStr = prefix + content?.substring(startIndex, endIndex)?.replace(/<[^>]+>/g, '') + suffix;
  return absStr;
};
 
export const getRefreshIntervalDisplay = (refreshInterval: number | undefined): string => {
  if (refreshInterval == null || refreshInterval === 0) {
    return i18n.t("No auto refresh");
  } else if (refreshInterval < 60) {
    if (refreshInterval === 1) {
      return refreshInterval + i18n.t("second");
    } else {
      return refreshInterval + i18n.t("seconds");
    }
  } else {
    if (refreshInterval/60 === 1) {
      return 1 + i18n.t("minute");
    } else {
      return (refreshInterval/60) + i18n.t("minutes");
    }
  }
};
 
export const getParamsFromUrl = (url: string): Record<string, string> => {
  Iif (isBlank(url)) {
    return {} as Record<string, string>;
  }
  const normalizedUrl = url.startsWith("http") ? url : `http://${url}`;
  const searchParams = new URLSearchParams(new URL(normalizedUrl).search);
  const params = {} as Record<string, string>;
  for (const [key, value] of searchParams) {
    params[key] = value;
  }
  return params;
};
 
export const startsWithPropKey = (str: string, obj: object): boolean => {
  const keys = Object.keys(obj);
  for (let i = 0; i < keys.length; i++) {
    if (str.startsWith(keys[i])) {
      return true;
    }
  }
  return false;
};
 
/**
 * 返回一个字符串的 hash 值
 * @param str
 */
export const stringHash = (str: string): number => {
  let hash = 0,
    i, chr;
  if (str.length === 0) return hash;
  for (i = 0; i < str.length; i++) {
    chr = str.charCodeAt(i);
    hash = ((hash << 5) - hash) + chr;
    hash |= 0; // Convert to 32bit integer
  }
  return hash;
};