All files / utils support.ts

16.67% Statements 9/54
0% Branches 0/26
0% Functions 0/8
16.67% Lines 9/54

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 1555x 5x               5x                               5x                               5x                                                           5x                                                                 5x                     5x                                                     5x                        
import { logger } from './logger'
import { _global } from './global'
 
/**
 * Tells whether current environment supports ErrorEvent objects
 * {../link supportsErrorEvent}.
 *
 * ../returns Answer to the given question.
 */
export function supportsErrorEvent(): boolean {
  try {
    // tslint:disable:no-unused-expression
    new ErrorEvent('')
    return true
  } catch (e) {
    return false
  }
}
 
/**
 * Tells whether current environment supports DOMException objects
 * {../link supportsDOMException}.
 *
 * ../returns Answer to the given question.
 */
export function supportsDOMException(): boolean {
  try {
    // tslint:disable:no-unused-expression
    new DOMException('')
    return true
  } catch (e) {
    return false
  }
}
 
/**
 * Tells whether current environment supports Fetch API
 * {../link supportsFetch}.
 *
 * ../returns Answer to the given question.
 */
export function supportsFetch(): boolean {
  if (!('fetch' in _global)) {
    return false
  }
 
  try {
    // tslint:disable-next-line:no-unused-expression
    new Headers()
    // tslint:disable-next-line:no-unused-expression
    new Request('')
    // tslint:disable-next-line:no-unused-expression
    new Response()
    return true
  } catch (e) {
    return false
  }
}
/**
 * 判断是不是原生的fetch,有可能是别人重写过的
 */
function isNativeFetch(func: Function): boolean {
  return func && /^function fetch\(\)\s+\{\s+\[native code\]\s+\}$/.test(func.toString())
}
 
/**
 * Tells whether current environment supports Fetch API natively
 * {../link supportsNativeFetch}.
 *
 * ../returns true if `window.fetch` is natively implemented, false otherwise
 */
export function supportsNativeFetch(): boolean {
  if (!supportsFetch()) {
    return false
  }
 
  if (isNativeFetch(global.fetch)) {
    return true
  }
  let result = false
  const doc = global.document
  if (doc && typeof (doc.createElement as unknown) === `function`) {
    try {
      const sandbox = doc.createElement('iframe')
      sandbox.hidden = true
      doc.head.appendChild(sandbox)
      if (sandbox.contentWindow && sandbox.contentWindow.fetch) {
        result = isNativeFetch(sandbox.contentWindow.fetch)
      }
      doc.head.removeChild(sandbox)
    } catch (err) {
      logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', err)
    }
  }
 
  return result
}
 
/**
 * Tells whether current environment supports ReportingObserver API
 * {../link supportsReportingObserver}.
 *
 * ../returns Answer to the given question.
 */
export function supportsReportingObserver(): boolean {
  // tslint:disable-next-line: no-unsafe-any
  return 'ReportingObserver' in _global
}
 
/**
 * Tells whether current environment supports Referrer Policy API
 * {../link supportsReferrerPolicy}.
 *
 * ../returns Answer to the given question.
 */
export function supportsReferrerPolicy(): boolean {
  // Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default
  // https://caniuse.com/#feat=referrer-policy
  // It doesn't. And it throw exception instead of ignoring this parameter...
  // REF: https://github.com/getsentry/raven-js/issues/1233
 
  if (!supportsFetch()) {
    return false
  }
 
  try {
    // tslint:disable:no-unused-expression
    new Request('_', {
      referrerPolicy: 'origin' as ReferrerPolicy
    })
    return true
  } catch (e) {
    return false
  }
}
 
/**
 * Tells whether current environment supports History API
 * {../link supportsHistory}.
 *
 * ../returns Answer to the given question.
 */
export function supportsHistory(): boolean {
  // NOTE: in Chrome App environment, touching history.pushState, *even inside
  //       a try/catch block*, will cause Chrome to output an error to console.error
  // borrowed from: https://github.com/angular/angular.js/pull/13945/files
  const global = _global
  const chrome = (global as any).chrome
  // tslint:disable-next-line:no-unsafe-any
  const isChromePackagedApp = chrome && chrome.app && chrome.app.runtime
  const hasHistoryApi = 'history' in global && !!global.history.pushState && !!global.history.replaceState
 
  return !isChromePackagedApp && hasHistoryApi
}