debug.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import config from '../config'
  2. import { noop, isArray, isFunction } from 'shared/util'
  3. import type { Component } from 'typescript/component'
  4. import { currentInstance } from 'v3/currentInstance'
  5. export let warn = noop
  6. export let tip = noop
  7. export let generateComponentTrace: (vm: Component) => string // work around flow check
  8. export let formatComponentName: (vm: Component, includeFile?: false) => string
  9. if (__DEV__) {
  10. const hasConsole = typeof console !== 'undefined'
  11. const classifyRE = /(?:^|[-_])(\w)/g
  12. const classify = str =>
  13. str.replace(classifyRE, c => c.toUpperCase()).replace(/[-_]/g, '')
  14. warn = (msg, vm = currentInstance) => {
  15. // TODO get current instance
  16. const trace = vm ? generateComponentTrace(vm) : ''
  17. if (config.warnHandler) {
  18. config.warnHandler.call(null, msg, vm, trace)
  19. } else if (hasConsole && !config.silent) {
  20. console.error(`[Vue warn]: ${msg}${trace}`)
  21. }
  22. }
  23. tip = (msg, vm) => {
  24. if (hasConsole && !config.silent) {
  25. console.warn(`[Vue tip]: ${msg}` + (vm ? generateComponentTrace(vm) : ''))
  26. }
  27. }
  28. formatComponentName = (vm, includeFile) => {
  29. if (vm.$root === vm) {
  30. return '<Root>'
  31. }
  32. const options =
  33. isFunction(vm) && (vm as any).cid != null
  34. ? (vm as any).options
  35. : vm._isVue
  36. ? vm.$options || (vm.constructor as any).options
  37. : vm
  38. let name = options.name || options._componentTag
  39. const file = options.__file
  40. if (!name && file) {
  41. const match = file.match(/([^/\\]+)\.vue$/)
  42. name = match && match[1]
  43. }
  44. return (
  45. (name ? `<${classify(name)}>` : `<Anonymous>`) +
  46. (file && includeFile !== false ? ` at ${file}` : '')
  47. )
  48. }
  49. const repeat = (str, n) => {
  50. let res = ''
  51. while (n) {
  52. if (n % 2 === 1) res += str
  53. if (n > 1) str += str
  54. n >>= 1
  55. }
  56. return res
  57. }
  58. generateComponentTrace = (vm: Component | undefined) => {
  59. if ((vm as any)._isVue && vm!.$parent) {
  60. const tree: any[] = []
  61. let currentRecursiveSequence = 0
  62. while (vm) {
  63. if (tree.length > 0) {
  64. const last = tree[tree.length - 1]
  65. if (last.constructor === vm.constructor) {
  66. currentRecursiveSequence++
  67. vm = vm.$parent!
  68. continue
  69. } else if (currentRecursiveSequence > 0) {
  70. tree[tree.length - 1] = [last, currentRecursiveSequence]
  71. currentRecursiveSequence = 0
  72. }
  73. }
  74. tree.push(vm)
  75. vm = vm.$parent!
  76. }
  77. return (
  78. '\n\nfound in\n\n' +
  79. tree
  80. .map(
  81. (vm, i) =>
  82. `${i === 0 ? '---> ' : repeat(' ', 5 + i * 2)}${
  83. isArray(vm)
  84. ? `${formatComponentName(vm[0])}... (${
  85. vm[1]
  86. } recursive calls)`
  87. : formatComponentName(vm)
  88. }`
  89. )
  90. .join('\n')
  91. )
  92. } else {
  93. return `\n\n(found in ${formatComponentName(vm!)})`
  94. }
  95. }
  96. }