All files / utils getCurrentScript.ts

55.17% Statements 16/29
42.86% Branches 12/28
100% Functions 1/1
55.56% Lines 15/27

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                    1x   1x         1x                   1x 1x     1x 1x     1x 1x 1x 1x             1x     1x                         1x                                             1x      
/* eslint-disable prefer-const */
// ref: https://github.com/sodatea/get-current-script/blob/main/index.js
 
/**
 * 返回当前正在运行的脚本所属的 `<script>` 元素。有两点限制:
 *
 * - 只在脚本被解析后首次运行时有效;
 * - 如果当前正在执行的代码是被其他代码作为回调函数或者事件处理函数调用的,会返回 `null`。
 */
export function getCurrentScript(): HTMLScriptElement | null {
  const descriptor = Object.getOwnPropertyDescriptor(document, 'currentScript')
  // for chrome
  Iif (!descriptor && 'currentScript' in document && document.currentScript) {
    return document.currentScript as any
  }
 
  // for other browsers with native support for currentScript
  Iif (
    descriptor &&
    descriptor.get !== getCurrentScript &&
    document.currentScript
  ) {
    return document.currentScript as any
  }
 
  // IE 8-10 support script readyState
  // IE 11+ & Firefox support stack trace
  try {
    throw new Error()
  } catch (err) {
    // Find the second match for the "at" string to get file src url from stack.
    let ieStackRegExp = /.*at [^(]*\((.*):(.+):(.+)\)$/gi,
      ffStackRegExp = /@([^@]*):(\d+):(\d+)\s*$/gi,
      stackDetails =
        // @ts-ignore
        ieStackRegExp.exec(err.stack) || ffStackRegExp.exec(err.stack),
      scriptLocation = (stackDetails && stackDetails[1]) || false,
      line = (stackDetails && stackDetails[2]) || false,
      currentLocation = document.location.href.replace(
        document.location.hash,
        '',
      ),
      pageSource,
      inlineScriptSourceRegExp,
      inlineScriptSource,
      scripts = document.getElementsByTagName('script') // Live NodeList collection
 
    // try to find the matching external script first
    for (let i = 0; i < scripts.length; i++) {
      // If ready state is interactive, return the script tag
      if ((scripts[i] as any).readyState === 'interactive') {
        return scripts[i]
      }
 
      // If src matches, return the script tag
      if (scripts[i].src === scriptLocation) {
        return scripts[i]
      }
    }
 
    // if not found, the current script is likely inline
    Iif (scriptLocation === currentLocation) {
      pageSource = document.documentElement.outerHTML
      inlineScriptSourceRegExp = new RegExp(
        `(?:[^\\n]+?\\n){0,${
          (line as any) - 2
        }}[^<]*<script>([\\d\\D]*?)<\\/script>[\\d\\D]*`,
        'i',
      )
      inlineScriptSource = pageSource
        .replace(inlineScriptSourceRegExp, '$1')
        .trim()
 
      // find the matching inline script
      for (let i = 0; i < scripts.length; i++) {
        if (
          scripts[i].innerHTML &&
          scripts[i].innerHTML.trim() === inlineScriptSource
        )
          return scripts[i]
      }
    }
 
    // If no match, return null
    return null
  }
}