@mpxjs/core 2.7.50 → 2.8.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/@types/index.d.ts +342 -27
  2. package/package.json +10 -5
  3. package/src/convertor/convertor.js +2 -2
  4. package/src/convertor/mergeLifecycle.js +4 -4
  5. package/src/convertor/wxToAli.js +3 -4
  6. package/src/convertor/wxToSwan.js +2 -2
  7. package/src/convertor/wxToTt.js +1 -10
  8. package/src/convertor/wxToWeb.js +14 -7
  9. package/src/core/implement.js +2 -2
  10. package/src/core/injectMixins.js +1 -1
  11. package/src/core/innerLifecycle.js +15 -2
  12. package/src/core/mergeOptions.js +11 -5
  13. package/src/core/proxy.js +343 -229
  14. package/src/core/transferOptions.js +5 -2
  15. package/src/helper/const.js +10 -0
  16. package/src/index.js +73 -147
  17. package/src/observer/array.js +12 -17
  18. package/src/observer/computed.js +27 -56
  19. package/src/observer/dep.js +1 -1
  20. package/src/observer/effect.js +113 -0
  21. package/src/observer/effectScope.js +109 -0
  22. package/src/observer/{index.js → reactive.js} +74 -70
  23. package/src/observer/ref.js +97 -0
  24. package/src/observer/scheduler.js +171 -56
  25. package/src/observer/watch.js +163 -39
  26. package/src/platform/builtInMixins/i18nMixin.js +238 -31
  27. package/src/platform/builtInMixins/pageScrollMixin.web.js +4 -5
  28. package/src/platform/builtInMixins/pageStatusMixin.js +76 -54
  29. package/src/platform/builtInMixins/pageStatusMixin.web.js +35 -22
  30. package/src/platform/builtInMixins/proxyEventMixin.js +40 -22
  31. package/src/platform/builtInMixins/proxyEventMixin.web.js +16 -24
  32. package/src/platform/builtInMixins/refsMixin.js +81 -72
  33. package/src/platform/builtInMixins/refsMixin.web.js +0 -47
  34. package/src/platform/builtInMixins/relationsMixin.js +10 -9
  35. package/src/platform/builtInMixins/renderHelperMixin.js +1 -1
  36. package/src/platform/builtInMixins/showMixin.js +1 -1
  37. package/src/platform/createApp.js +5 -5
  38. package/src/platform/export/api.js +23 -0
  39. package/src/platform/export/api.web.js +26 -0
  40. package/src/platform/export/index.js +45 -0
  41. package/src/platform/export/index.web.js +36 -0
  42. package/src/platform/index.js +1 -5
  43. package/src/platform/patch/ali/getDefaultOptions.js +33 -31
  44. package/src/platform/patch/ali/lifecycle.js +21 -13
  45. package/src/platform/patch/builtInKeysMap.js +2 -1
  46. package/src/platform/patch/index.js +4 -9
  47. package/src/platform/patch/swan/getDefaultOptions.js +3 -3
  48. package/src/platform/patch/swan/lifecycle.js +17 -14
  49. package/src/platform/patch/web/getDefaultOptions.js +40 -16
  50. package/src/platform/patch/web/lifecycle.js +6 -3
  51. package/src/platform/patch/wx/getDefaultOptions.js +38 -31
  52. package/src/platform/patch/wx/lifecycle.js +18 -11
  53. package/src/runtime/createFactory.js +6 -2
  54. package/src/vue.web.js +5 -2
  55. package/src/vuePlugin.js +31 -0
  56. package/src/core/createStore.js +0 -241
  57. package/src/core/mapStore.js +0 -94
  58. package/src/helper/env.js +0 -20
  59. package/src/helper/getByPath.js +0 -127
  60. package/src/helper/log.js +0 -31
  61. package/src/helper/utils.js +0 -652
  62. package/src/observer/watcher.js +0 -244
@@ -1,4 +1,11 @@
1
- import { BEFORECREATE, CREATED, DESTROYED, MOUNTED, UPDATED, BEFOREMOUNT } from '../../../core/innerLifecycle'
1
+ import {
2
+ CREATED,
3
+ UNMOUNTED,
4
+ MOUNTED,
5
+ ONSHOW,
6
+ ONHIDE,
7
+ ONLOAD
8
+ } from '../../../core/innerLifecycle'
2
9
 
3
10
  const APP_HOOKS = [
4
11
  'onLaunch',
@@ -18,33 +25,33 @@ const PAGE_HOOKS = [
18
25
  'onUnload',
19
26
  'onPullDownRefresh',
20
27
  'onReachBottom',
21
- 'onShareAppMessage',
22
28
  'onPageScroll',
29
+ 'onAddToFavorites',
30
+ 'onShareAppMessage',
31
+ 'onShareTimeline',
32
+ 'onResize',
23
33
  'onTabItemTap',
24
- 'onResize'
34
+ 'onSaveExitState'
25
35
  ]
26
36
 
27
37
  const COMPONENT_HOOKS = [
28
- 'beforeCreate',
29
38
  'created',
30
39
  'attached',
31
40
  'ready',
32
41
  'moved',
33
42
  'detached',
34
- 'updated',
35
43
  'pageShow',
36
- 'pageHide',
37
- 'definitionFilter'
44
+ 'pageHide'
38
45
  ]
39
46
 
40
47
  export const lifecycleProxyMap = {
41
- [BEFORECREATE]: ['beforeCreate'],
42
48
  // 类微信平台中onLoad不能代理到CREATED上,否则Component构造页面时无法获取页面参数
43
49
  [CREATED]: ['created', 'attached'],
44
- [UPDATED]: ['updated'],
45
- [BEFOREMOUNT]: ['beforeMount'],
46
50
  [MOUNTED]: ['ready', 'onReady'],
47
- [DESTROYED]: ['detached', 'onUnload']
51
+ [UNMOUNTED]: ['detached', 'onUnload'],
52
+ [ONSHOW]: ['pageShow', 'onShow'],
53
+ [ONHIDE]: ['pageHide', 'onHide'],
54
+ [ONLOAD]: ['onLoad']
48
55
  }
49
56
 
50
57
  export const LIFECYCLE = {
@@ -1,4 +1,8 @@
1
- const mpx = require('../index').default
1
+ const factoryMap = {
2
+ App: require('../index').createApp,
3
+ Page: require('../index').createPage,
4
+ Component: require('../index').createComponent
5
+ }
2
6
 
3
7
  module.exports = (type) => (...args) => {
4
8
  if (type === 'Behavior') {
@@ -13,5 +17,5 @@ module.exports = (type) => (...args) => {
13
17
  }
14
18
  return args[0]
15
19
  }
16
- return mpx[`create${type}`] && mpx[`create${type}`].apply(null, args.concat({ isNative: true }))
20
+ return factoryMap[type].apply(null, args.concat({ isNative: true }))
17
21
  }
package/src/vue.web.js CHANGED
@@ -1,3 +1,6 @@
1
- import vue from 'vue'
1
+ import Vue from 'vue'
2
+ import install from './vuePlugin'
2
3
 
3
- export default vue
4
+ Vue.use(install)
5
+
6
+ export default Vue
@@ -0,0 +1,31 @@
1
+ import { walkChildren, parseSelector, error } from '@mpxjs/utils'
2
+ import * as webApi from '@mpxjs/api-proxy/src/web/api'
3
+
4
+ export default function install (Vue) {
5
+ Vue.prototype.triggerEvent = function (eventName, eventDetail) {
6
+ return this.$emit(eventName, {
7
+ type: eventName,
8
+ detail: eventDetail
9
+ })
10
+ }
11
+ Vue.prototype.selectComponent = function (selector, all) {
12
+ const result = []
13
+ if (/[>\s]/.test(selector)) {
14
+ const location = this.__mpxProxy.options.mpxFileResource
15
+ error('The selectComponent or selectAllComponents only supports the basic selector, the relation selector is not supported.', location)
16
+ } else {
17
+ const selectorGroups = parseSelector(selector)
18
+ walkChildren(this, selectorGroups, this, result, all)
19
+ }
20
+ return all ? result : result[0]
21
+ }
22
+ Vue.prototype.selectAllComponents = function (selector) {
23
+ return this.selectComponent(selector, true)
24
+ }
25
+ Vue.prototype.createSelectorQuery = function () {
26
+ return webApi.createSelectorQuery().in(this)
27
+ }
28
+ Vue.prototype.createIntersectionObserver = function (component, options) {
29
+ return webApi.createIntersectionObserver(component, options)
30
+ }
31
+ }
@@ -1,241 +0,0 @@
1
- import { observe } from '../observer/index'
2
-
3
- import { initComputed } from '../observer/computed'
4
-
5
- import Vue from '../vue'
6
-
7
- import {
8
- proxy,
9
- getByPath
10
- } from '../helper/utils'
11
-
12
- import { warn } from '../helper/log'
13
-
14
- // 兼容在web和小程序平台中创建表现一致的store
15
-
16
- import mapStore from './mapStore'
17
-
18
- function transformGetters (getters, module, store) {
19
- const newGetters = {}
20
- for (let key in getters) {
21
- if (key in store.getters) {
22
- warn(`Duplicate getter type: ${key}.`)
23
- }
24
- const getter = function () {
25
- if (store.withThis) {
26
- return getters[key].call({
27
- state: module.state,
28
- getters: store.getters,
29
- rootState: store.state
30
- })
31
- }
32
- return getters[key](module.state, store.getters, store.state)
33
- }
34
- newGetters[key] = getter
35
- }
36
- return newGetters
37
- }
38
-
39
- function transformMutations (mutations, module, store) {
40
- const newMutations = {}
41
- for (let key in mutations) {
42
- if (store.mutations[key]) {
43
- warn(`Duplicate mutation type: ${key}.`)
44
- }
45
- const context = {
46
- state: module.state,
47
- commit: store.commit.bind(store)
48
- }
49
- const mutation = function (...payload) {
50
- if (store.withThis) return mutations[key].apply(context, payload)
51
- return mutations[key](module.state, ...payload)
52
- }
53
- newMutations[key] = mutation
54
- }
55
- return newMutations
56
- }
57
-
58
- function transformActions (actions, module, store) {
59
- const newActions = {}
60
- for (let key in actions) {
61
- if (store.actions[key]) {
62
- warn(`Duplicate action type: ${key}.`)
63
- }
64
- newActions[key] = function (...payload) {
65
- const context = {
66
- rootState: store.state,
67
- state: module.state,
68
- getters: store.getters,
69
- dispatch: store.dispatch.bind(store),
70
- commit: store.commit.bind(store)
71
- }
72
-
73
- let result
74
- if (store.withThis) {
75
- result = actions[key].apply(context, payload)
76
- } else {
77
- result = actions[key](context, ...payload)
78
- }
79
- // action一定返回一个promise
80
- if (result && typeof result.then === 'function' && typeof result.catch === 'function') {
81
- return result
82
- } else {
83
- return Promise.resolve(result)
84
- }
85
- }
86
- }
87
- return newActions
88
- }
89
-
90
- function mergeDeps (module, deps) {
91
- const mergeProps = ['state', 'getters', 'mutations', 'actions']
92
- Object.keys(deps).forEach(key => {
93
- const store = deps[key]
94
- mergeProps.forEach(prop => {
95
- if (module[prop] && (key in module[prop])) {
96
- warn(`Deps's name [${key}] conflicts with ${prop}'s key in current options.`)
97
- } else {
98
- module[prop] = module[prop] || {}
99
- if (prop === 'getters') {
100
- // depsGetters单独存放,不需要重新进行初始化
101
- module.depsGetters = module.depsGetters || {}
102
- module.depsGetters[key] = store.getters
103
- // module[prop][key] = () => store[prop]
104
- } else {
105
- module[prop][key] = store[prop]
106
- }
107
- }
108
- })
109
- })
110
- }
111
-
112
- class Store {
113
- constructor (options) {
114
- const {
115
- plugins = []
116
- } = options
117
- this.withThis = options.withThis
118
- this.__wrappedGetters = {}
119
- this.__depsGetters = {}
120
- this.getters = {}
121
- this.mutations = {}
122
- this.actions = {}
123
- this._subscribers = []
124
- this.state = this.registerModule(options).state
125
- this.resetStoreVM()
126
- Object.assign(this, mapStore(this))
127
- plugins.forEach(plugin => plugin(this))
128
- }
129
-
130
- dispatch (type, ...payload) {
131
- const action = getByPath(this.actions, type)
132
- if (!action) {
133
- return Promise.reject(new Error(`unknown action type: ${type}`))
134
- } else {
135
- return action(...payload)
136
- }
137
- }
138
-
139
- commit (type, ...payload) {
140
- const mutation = getByPath(this.mutations, type)
141
- if (!mutation) {
142
- warn(`Unknown mutation type: ${type}.`)
143
- } else {
144
- mutation(...payload)
145
- return this._subscribers.slice().forEach(sub => sub({ type, payload }, this.state))
146
- }
147
- }
148
-
149
- subscribe (fn, options) {
150
- return genericSubscribe(fn, this._subscribers, options)
151
- }
152
-
153
- registerModule (module) {
154
- const state = module.state || {}
155
- const reactiveModule = {
156
- state
157
- }
158
- if (module.getters) {
159
- reactiveModule.getters = transformGetters(module.getters, reactiveModule, this)
160
- }
161
- if (module.mutations) {
162
- reactiveModule.mutations = transformMutations(module.mutations, reactiveModule, this)
163
- }
164
- if (module.actions) {
165
- reactiveModule.actions = transformActions(module.actions, reactiveModule, this)
166
- }
167
- if (module.deps) {
168
- mergeDeps(reactiveModule, module.deps)
169
- }
170
- Object.assign(this.__depsGetters, reactiveModule.depsGetters)
171
- Object.assign(this.__wrappedGetters, reactiveModule.getters)
172
- // merge mutations
173
- Object.assign(this.mutations, reactiveModule.mutations)
174
- // merge actions
175
- Object.assign(this.actions, reactiveModule.actions)
176
- // 子module
177
- if (module.modules) {
178
- const childs = module.modules
179
- Object.keys(childs).forEach(key => {
180
- reactiveModule.state[key] = this.registerModule(childs[key]).state
181
- })
182
- }
183
- return reactiveModule
184
- }
185
-
186
- resetStoreVM () {
187
- if (__mpx_mode__ === 'web') {
188
- this._vm = new Vue({
189
- data: {
190
- __mpxState: this.state
191
- },
192
- computed: this.__wrappedGetters
193
- })
194
- const computedKeys = Object.keys(this.__wrappedGetters)
195
- proxy(this.getters, this._vm, computedKeys)
196
- proxy(this.getters, this.__depsGetters)
197
- } else {
198
- this._vm = {}
199
- observe(this.state, true)
200
- initComputed(this._vm, this.getters, this.__wrappedGetters)
201
- proxy(this.getters, this.__depsGetters)
202
- }
203
- }
204
- }
205
-
206
- function genericSubscribe (fn, subs, options) {
207
- if (subs.indexOf(fn) < 0) {
208
- options && options.prepend
209
- ? subs.unshift(fn)
210
- : subs.push(fn)
211
- }
212
- return () => {
213
- const i = subs.indexOf(fn)
214
- if (i > -1) {
215
- subs.splice(i, 1)
216
- }
217
- }
218
- }
219
-
220
- export default function createStore (options) {
221
- return new Store(options)
222
- }
223
-
224
- // ts util functions
225
- export function createStateWithThis (state) {
226
- return state
227
- }
228
- export function createGettersWithThis (getters, options = {}) {
229
- return getters
230
- }
231
- export function createMutationsWithThis (mutations, options = {}) {
232
- return mutations
233
- }
234
- export function createActionsWithThis (actions, options = {}) {
235
- return actions
236
- }
237
-
238
- export function createStoreWithThis (options) {
239
- options.withThis = true
240
- return new Store(options)
241
- }
@@ -1,94 +0,0 @@
1
- import {
2
- normalizeMap,
3
- getByPath
4
- } from '../helper/utils'
5
-
6
- import { warn, error } from '../helper/log'
7
-
8
- function mapFactory (type, store) {
9
- return function (depPath, maps) {
10
- maps = normalizeMap(depPath, maps)
11
- const result = {}
12
- Object.entries(maps).forEach(([key, value]) => {
13
- result[key] = function (payload) {
14
- switch (type) {
15
- case 'state':
16
- if (typeof value === 'function') {
17
- return value.call(this, store.state, store.getters)
18
- } else {
19
- let stateVal = getByPath(store.state, value, '', '__NOTFOUND__')
20
- if (stateVal === '__NOTFOUND__') {
21
- warn(`Unknown state named [${value}].`)
22
- stateVal = ''
23
- }
24
- return stateVal
25
- }
26
- case 'getters':
27
- let getterVal = getByPath(store.getters, value, '', '__NOTFOUND__')
28
- if (getterVal === '__NOTFOUND__') {
29
- warn(`Unknown getter named [${value}].`)
30
- getterVal = ''
31
- }
32
- return getterVal
33
- case 'mutations':
34
- return store.commit(value, payload)
35
- case 'actions':
36
- return store.dispatch(value, payload)
37
- }
38
- }
39
- })
40
- return result
41
- }
42
- }
43
-
44
- function checkMapInstance (args) {
45
- const context = args[args.length - 1]
46
- const isValid = context && typeof context === 'object' && context.__mpxProxy
47
- if (!isValid) {
48
- error(`调用map**ToInstance时必须传入当前component实例this`)
49
- }
50
-
51
- args.splice(-1)
52
-
53
- return {
54
- restParams: args,
55
- context
56
- }
57
- }
58
-
59
- export default function (store) {
60
- return {
61
- mapGetters: mapFactory('getters', store),
62
- mapMutations: mapFactory('mutations', store),
63
- mapActions: mapFactory('actions', store),
64
- mapState: mapFactory('state', store),
65
- // 以下是map**ToInstance用于异步store的,参数args:depPath, maps, context
66
- mapStateToInstance: (...args) => {
67
- const { context, restParams } = checkMapInstance(args)
68
- const mapStateFun = mapFactory('state', store)
69
- const result = mapStateFun(...restParams)
70
- // 将result挂载到mpxProxy实例属性上
71
- context.__mpxProxy.options.computed = context.__mpxProxy.options.computed || {}
72
- Object.assign(context.__mpxProxy.options.computed, result)
73
- },
74
- mapGettersToInstance: (...args) => {
75
- const { context, restParams } = checkMapInstance(args)
76
- const mapGetFun = mapFactory('getters', store)
77
- const result = mapGetFun(...restParams)
78
- context.__mpxProxy.options.computed = context.__mpxProxy.options.computed || {}
79
- Object.assign(context.__mpxProxy.options.computed, result)
80
- },
81
- mapMutationsToInstance: (...args) => {
82
- const { context, restParams } = checkMapInstance(args)
83
- const mapMutationFun = mapFactory('mutations', store)
84
- const result = mapMutationFun(...restParams)
85
- Object.assign(context, result)
86
- },
87
- mapActionsToInstance: (...args) => {
88
- const { context, restParams } = checkMapInstance(args)
89
- const mapActionFun = mapFactory('actions', store)
90
- const result = mapActionFun(...restParams)
91
- Object.assign(context, result)
92
- }
93
- }
94
- }
package/src/helper/env.js DELETED
@@ -1,20 +0,0 @@
1
- export function getEnvObj () {
2
- switch (__mpx_mode__) {
3
- case 'wx':
4
- return wx
5
- case 'ali':
6
- return my
7
- case 'swan':
8
- return swan
9
- case 'qq':
10
- return qq
11
- case 'tt':
12
- return tt
13
- case 'jd':
14
- return jd
15
- case 'qa':
16
- return qa
17
- case 'dd':
18
- return dd
19
- }
20
- }
@@ -1,127 +0,0 @@
1
- let curStack
2
- let targetStacks
3
- let property
4
-
5
- class Stack {
6
- constructor (mark) {
7
- this.mark = mark
8
- // 字符串stack需要特殊处理
9
- this.type = /['"]/.test(mark) ? 'string' : 'normal'
10
- this.value = []
11
- }
12
-
13
- push (data) {
14
- this.value.push(data)
15
- }
16
- }
17
-
18
- function startStack (mark) {
19
- // 开启栈或关闭栈都意味着前面的字符拼接截止
20
- propertyJoinOver()
21
- curStack && targetStacks.push(curStack)
22
- curStack = new Stack(mark)
23
- }
24
-
25
- function endStack () {
26
- // 开启栈或关闭栈都意味着前面的字符拼接截止
27
- propertyJoinOver()
28
- // 字符串栈直接拼接
29
- const result = curStack.type === 'string' ? '__mpx_str_' + curStack.value.join('') : curStack.value
30
- curStack = targetStacks.pop()
31
- // 将当前stack结果保存到父级stack里
32
- curStack.push(result)
33
- }
34
-
35
- function propertyJoinOver () {
36
- property = property.trim()
37
- if (property) curStack.push(property)
38
- property = ''
39
- }
40
-
41
- function init () {
42
- property = ''
43
- // 根stack
44
- curStack = new Stack()
45
- targetStacks = []
46
- }
47
-
48
- function parse (str) {
49
- init()
50
- for (const char of str) {
51
- // 当前遍历引号内的字符串时
52
- if (curStack.type === 'string') {
53
- // 若为对应的结束flag,则出栈,反之直接push
54
- curStack.mark === char ? endStack() : curStack.push(char)
55
- } else if (/['"[]/.test(char)) {
56
- startStack(char)
57
- } else if (char === ']') {
58
- endStack()
59
- } else if (char === '.' || char === '+') {
60
- propertyJoinOver()
61
- if (char === '+') curStack.push(char)
62
- } else {
63
- property += char
64
- }
65
- }
66
- // 字符解析收尾
67
- propertyJoinOver()
68
- return curStack.value
69
- }
70
-
71
- function outPutByPath (context, path, isSimple, transfer) {
72
- let result = context
73
- const len = path.length
74
- const meta = {
75
- isEnd: false,
76
- stop: false
77
- }
78
- for (let index = 0; index < len; index++) {
79
- if (index === len - 1) meta.isEnd = true
80
- let key
81
- const item = path[index]
82
- if (result) {
83
- if (isSimple) {
84
- key = item
85
- } else if (Array.isArray(item)) {
86
- // 获取子数组的输出结果作为当前key
87
- key = outPutByPath(context, item, isSimple, transfer)
88
- } else if (/^__mpx_str_/.test(item)) {
89
- // 字符串一定会被[]包裹,一定在子数组中
90
- result = item.replace('__mpx_str_', '')
91
- } else if (/^\d+$/.test(item)) {
92
- // 数字一定会被[]包裹,一定在子数组中
93
- result = +item
94
- } else if (item === '+') {
95
- // 获取加号后面所有path最终的结果
96
- result += outPutByPath(context, path.slice(index + 1), isSimple, transfer)
97
- break
98
- } else {
99
- key = item
100
- }
101
- if (key !== undefined) {
102
- result = transfer ? transfer(result, key, meta) : result[key]
103
- if (meta.stop) break
104
- }
105
- } else {
106
- break
107
- }
108
- }
109
- return result
110
- }
111
-
112
- export default function getByPath (context, pathStrOrArr, transfer) {
113
- if (!pathStrOrArr) {
114
- return context
115
- }
116
- let isSimple = false
117
- if (Array.isArray(pathStrOrArr)) {
118
- isSimple = true
119
- } else if (!/[[\]]/.test(pathStrOrArr)) {
120
- pathStrOrArr = pathStrOrArr.split('.')
121
- isSimple = true
122
- }
123
-
124
- if (!isSimple) pathStrOrArr = parse(pathStrOrArr)
125
-
126
- return outPutByPath(context, pathStrOrArr, isSimple, transfer)
127
- }
package/src/helper/log.js DELETED
@@ -1,31 +0,0 @@
1
- import EXPORT_MPX from '../index'
2
-
3
- export function warn (msg, location, e) {
4
- const condition = EXPORT_MPX.config.ignoreWarning
5
- let ignore = false
6
- if (typeof condition === 'boolean') {
7
- ignore = condition
8
- } else if (typeof condition === 'string') {
9
- ignore = msg.indexOf(condition) !== -1
10
- } else if (typeof condition === 'function') {
11
- ignore = condition(msg, location, e)
12
- } else if (condition instanceof RegExp) {
13
- ignore = condition.test(msg)
14
- }
15
- if (!ignore) return log('warn', msg, location, e)
16
- }
17
-
18
- export function error (msg, location, e) {
19
- return log('error', msg, location, e)
20
- }
21
-
22
- function log (type, msg, location, e) {
23
- if (process.env.NODE_ENV !== 'production') {
24
- let header = `[Mpx runtime ${type}]: `
25
- if (location) {
26
- header = `[Mpx runtime ${type} at ${location}]: `
27
- }
28
- console[type](header + msg)
29
- if (e) console[type](e)
30
- }
31
- }