All files / src errorId.ts

54.9% Statements 28/51
35% Branches 7/20
50% Functions 4/8
55.1% Lines 27/49

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 1071x   1x         1x   9x 9x   4x 4x               5x 5x               9x 9x 3x   6x 2x   4x     6x                                                                                         1x 16x           1x 10x       9x 9x 9x 468x 468x 468x   9x    
import { ERRORTYPES, EVENTTYPES } from './common/common'
import { ReportDataType } from './types/transportData'
const allErrorNumber: unknown = {}
/**
 * error合并规则
 * @param data
 */
export default function createErrorId(data: ReportDataType): number | null {
  let id: any
  const originUrl = getRealPageOrigin(data.url)
  switch (data.type) {
    case ERRORTYPES.FETCH_ERROR:
      id = data.type + data.request.method + data.response.status + getRealPath(data.request.url) + originUrl
      break
    case ERRORTYPES.JAVASCRIPT_ERROR:
    case ERRORTYPES.VUE_ERROR:
    case ERRORTYPES.REACT_ERROR:
      id = data.type + data.name + data.message + originUrl
      break
    case ERRORTYPES.BUSINESS_ERROR:
    case ERRORTYPES.LOG_ERROR:
      id = data.customTag + data.type + data.name + originUrl
      break
    case ERRORTYPES.PROMISE_ERROR:
      id = generatePromiseErrorId(data, originUrl)
      break
    default:
      id = data.type + data.message + originUrl
      break
  }
  id = hashCode(id)
  if (allErrorNumber[id] > 1) {
    return null
  }
  if (typeof allErrorNumber[id] === 'number') {
    allErrorNumber[id]++
  } else {
    allErrorNumber[id] = 1
  }
 
  return id
}
 
function generatePromiseErrorId(data: ReportDataType, originUrl: string) {
  const locationUrl = getRealPath(data.url)
  if (data.name === EVENTTYPES.UNHANDLEDREJECTION) {
    return data.type + objectOrder(data.message) + originUrl
  }
  return data.type + data.name + objectOrder(data.message) + locationUrl
}
 
/**
 * 排序对象键值对
 * ../param reason promise.reject
 */
function objectOrder(reason: any) {
  const sortFn = (obj: any) => {
    return Object.keys(obj)
      .sort()
      .reduce((total, key) => {
        if (Object.prototype.toString.call(obj[key]) === '[object Object]') {
          total[key] = sortFn(obj[key])
        } else {
          total[key] = obj[key]
        }
        return total
      }, {})
  }
  try {
    if (/\{.*\}/.test(reason)) {
      let obj = JSON.parse(reason)
      obj = sortFn(obj)
      return JSON.stringify(obj)
    }
  } catch (error) {
    return reason
  }
}
 
/**
 * http://.../project?id=1#a => http://.../project
 * http://.../id/123=> http://.../id/{param}
 *
 * @param url
 */
export function getRealPath(url: string): string {
  return url.replace(/[\?#].*$/, '').replace(/\/\d+([\/]*$)/, '{param}$1')
}
/**
 * http://a.b.com/#/project?id=1 => a.b.com
 * @param url
 */
export function getRealPageOrigin(url: string): string {
  return getRealPath(url.replace(/(\S+)(\/#\/)(\S*)/, `$1`).replace(/(\S*)(\/\/)(\S+)/, '$3'))
}
 
function hashCode(str: string): number {
  let hash = 0
  Iif (str.length == 0) return hash
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i)
    hash = (hash << 5) - hash + char
    hash = hash & hash
  }
  return hash
}