|
|
(function () {
|
|
|
'use strict';
|
|
|
|
|
|
/******************************************************************************
|
|
|
Copyright (c) Microsoft Corporation.
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
|
purpose with or without fee is hereby granted.
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
PERFORMANCE OF THIS SOFTWARE.
|
|
|
***************************************************************************** */
|
|
|
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
|
|
|
|
|
|
|
function __spreadArray(to, from, pack) {
|
|
|
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
|
if (ar || !(i in from)) {
|
|
|
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
|
ar[i] = from[i];
|
|
|
}
|
|
|
}
|
|
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
|
}
|
|
|
|
|
|
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
|
var e = new Error(message);
|
|
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
|
};
|
|
|
|
|
|
var CONSOLE_TYPES = ['log', 'warn', 'error', 'info', 'debug'];
|
|
|
var originalConsole = /*@__PURE__*/ CONSOLE_TYPES.reduce(function (methods, type) {
|
|
|
methods[type] = console[type].bind(console);
|
|
|
return methods;
|
|
|
}, {});
|
|
|
|
|
|
var sendError = null;
|
|
|
// App.onError会监听到两类错误,一类是小程序自身抛出的,一类是 vue 的 errorHandler 触发的
|
|
|
// uni.onError 和 App.onError 会同时监听到错误(主要是App.onError监听之前的错误),所以需要用 Set 来去重
|
|
|
// uni.onError 会在 App.onError 上边同时增加监听,因为要监听 vue 的errorHandler
|
|
|
// 目前 vue 的 errorHandler 仅会callHook('onError'),所以需要把uni.onError的也挂在 App.onError 上
|
|
|
var errorQueue = new Set();
|
|
|
var errorExtra = {};
|
|
|
function sendErrorMessages(errors) {
|
|
|
if (sendError == null) {
|
|
|
errors.forEach(function (error) {
|
|
|
errorQueue.add(error);
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
var data = errors
|
|
|
.map(function (err) {
|
|
|
if (typeof err === 'string') {
|
|
|
return err;
|
|
|
}
|
|
|
var isPromiseRejection = err && 'promise' in err && 'reason' in err;
|
|
|
var prefix = isPromiseRejection ? 'UnhandledPromiseRejection: ' : '';
|
|
|
if (isPromiseRejection) {
|
|
|
err = err.reason;
|
|
|
}
|
|
|
if (err instanceof Error && err.stack) {
|
|
|
if (err.message && !err.stack.includes(err.message)) {
|
|
|
return "".concat(prefix).concat(err.message, "\n").concat(err.stack);
|
|
|
}
|
|
|
return "".concat(prefix).concat(err.stack);
|
|
|
}
|
|
|
if (typeof err === 'object' && err !== null) {
|
|
|
try {
|
|
|
return prefix + JSON.stringify(err);
|
|
|
}
|
|
|
catch (err) {
|
|
|
return prefix + String(err);
|
|
|
}
|
|
|
}
|
|
|
return prefix + String(err);
|
|
|
})
|
|
|
.filter(Boolean);
|
|
|
if (data.length > 0) {
|
|
|
sendError(JSON.stringify(Object.assign({
|
|
|
type: 'error',
|
|
|
data: data,
|
|
|
}, errorExtra)));
|
|
|
}
|
|
|
}
|
|
|
function setSendError(value, extra) {
|
|
|
if (extra === void 0) { extra = {}; }
|
|
|
sendError = value;
|
|
|
Object.assign(errorExtra, extra);
|
|
|
if (value != null && errorQueue.size > 0) {
|
|
|
var errors = Array.from(errorQueue);
|
|
|
errorQueue.clear();
|
|
|
sendErrorMessages(errors);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function formatMessage(type, args) {
|
|
|
try {
|
|
|
return {
|
|
|
type: type,
|
|
|
args: formatArgs(args),
|
|
|
};
|
|
|
}
|
|
|
catch (e) {
|
|
|
// originalConsole.error(e)
|
|
|
}
|
|
|
return {
|
|
|
type: type,
|
|
|
args: [],
|
|
|
};
|
|
|
}
|
|
|
function formatArgs(args) {
|
|
|
return args.map(function (arg) { return formatArg(arg); });
|
|
|
}
|
|
|
function formatArg(arg, depth) {
|
|
|
if (depth === void 0) { depth = 0; }
|
|
|
if (depth >= 7) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
value: '[Maximum depth reached]',
|
|
|
};
|
|
|
}
|
|
|
var type = typeof arg;
|
|
|
switch (type) {
|
|
|
case 'string':
|
|
|
return formatString(arg);
|
|
|
case 'number':
|
|
|
return formatNumber(arg);
|
|
|
case 'boolean':
|
|
|
return formatBoolean(arg);
|
|
|
case 'object':
|
|
|
try {
|
|
|
// 鸿蒙里边 object 可能包含 nativePtr 指针,该指针 typeof 是 object
|
|
|
// 但是又不能访问上边的任意属性,否则会报:TypeError: Can not get Prototype on non ECMA Object
|
|
|
// 所以这里需要捕获异常,防止报错
|
|
|
return formatObject(arg, depth);
|
|
|
}
|
|
|
catch (e) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
value: {
|
|
|
properties: [],
|
|
|
},
|
|
|
};
|
|
|
}
|
|
|
case 'undefined':
|
|
|
return formatUndefined();
|
|
|
case 'function':
|
|
|
return formatFunction(arg);
|
|
|
case 'symbol':
|
|
|
{
|
|
|
return formatSymbol(arg);
|
|
|
}
|
|
|
case 'bigint':
|
|
|
return formatBigInt(arg);
|
|
|
}
|
|
|
}
|
|
|
function formatFunction(value) {
|
|
|
return {
|
|
|
type: 'function',
|
|
|
value: "function ".concat(value.name, "() {}"),
|
|
|
};
|
|
|
}
|
|
|
function formatUndefined() {
|
|
|
return {
|
|
|
type: 'undefined',
|
|
|
};
|
|
|
}
|
|
|
function formatBoolean(value) {
|
|
|
return {
|
|
|
type: 'boolean',
|
|
|
value: String(value),
|
|
|
};
|
|
|
}
|
|
|
function formatNumber(value) {
|
|
|
return {
|
|
|
type: 'number',
|
|
|
value: String(value),
|
|
|
};
|
|
|
}
|
|
|
function formatBigInt(value) {
|
|
|
return {
|
|
|
type: 'bigint',
|
|
|
value: String(value),
|
|
|
};
|
|
|
}
|
|
|
function formatString(value) {
|
|
|
return {
|
|
|
type: 'string',
|
|
|
value: value,
|
|
|
};
|
|
|
}
|
|
|
function formatSymbol(value) {
|
|
|
return {
|
|
|
type: 'symbol',
|
|
|
value: value.description,
|
|
|
};
|
|
|
}
|
|
|
function formatObject(value, depth) {
|
|
|
if (value === null) {
|
|
|
return {
|
|
|
type: 'null',
|
|
|
};
|
|
|
}
|
|
|
{
|
|
|
if (isComponentPublicInstance(value)) {
|
|
|
return formatComponentPublicInstance(value, depth);
|
|
|
}
|
|
|
if (isComponentInternalInstance(value)) {
|
|
|
return formatComponentInternalInstance(value, depth);
|
|
|
}
|
|
|
if (isUniElement(value)) {
|
|
|
return formatUniElement(value, depth);
|
|
|
}
|
|
|
if (isCSSStyleDeclaration(value)) {
|
|
|
return formatCSSStyleDeclaration(value, depth);
|
|
|
}
|
|
|
}
|
|
|
if (Array.isArray(value)) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
subType: 'array',
|
|
|
value: {
|
|
|
properties: value.map(function (v, i) {
|
|
|
return formatArrayElement(v, i, depth + 1);
|
|
|
}),
|
|
|
},
|
|
|
};
|
|
|
}
|
|
|
if (value instanceof Set) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
subType: 'set',
|
|
|
className: 'Set',
|
|
|
description: "Set(".concat(value.size, ")"),
|
|
|
value: {
|
|
|
entries: Array.from(value).map(function (v) { return formatSetEntry(v, depth + 1); }),
|
|
|
},
|
|
|
};
|
|
|
}
|
|
|
if (value instanceof Map) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
subType: 'map',
|
|
|
className: 'Map',
|
|
|
description: "Map(".concat(value.size, ")"),
|
|
|
value: {
|
|
|
entries: Array.from(value.entries()).map(function (v) { return formatMapEntry(v, depth + 1); }),
|
|
|
},
|
|
|
};
|
|
|
}
|
|
|
if (value instanceof Promise) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
subType: 'promise',
|
|
|
value: {
|
|
|
properties: [],
|
|
|
},
|
|
|
};
|
|
|
}
|
|
|
if (value instanceof RegExp) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
subType: 'regexp',
|
|
|
value: String(value),
|
|
|
className: 'Regexp',
|
|
|
};
|
|
|
}
|
|
|
if (value instanceof Date) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
subType: 'date',
|
|
|
value: String(value),
|
|
|
className: 'Date',
|
|
|
};
|
|
|
}
|
|
|
if (value instanceof Error) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
subType: 'error',
|
|
|
value: value.message || String(value),
|
|
|
className: value.name || 'Error',
|
|
|
};
|
|
|
}
|
|
|
var className = undefined;
|
|
|
{
|
|
|
var constructor = value.constructor;
|
|
|
if (constructor) {
|
|
|
// @ts-expect-error
|
|
|
if (constructor.get$UTSMetadata$) {
|
|
|
// @ts-expect-error
|
|
|
className = constructor.get$UTSMetadata$().name;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
var entries = Object.entries(value);
|
|
|
if (isHarmonyBuilderParams(value)) {
|
|
|
entries = entries.filter(function (_a) {
|
|
|
var key = _a[0];
|
|
|
return key !== 'modifier' && key !== 'nodeContent';
|
|
|
});
|
|
|
}
|
|
|
return {
|
|
|
type: 'object',
|
|
|
className: className,
|
|
|
value: {
|
|
|
properties: entries.map(function (entry) {
|
|
|
return formatObjectProperty(entry[0], entry[1], depth + 1);
|
|
|
}),
|
|
|
},
|
|
|
};
|
|
|
}
|
|
|
function isHarmonyBuilderParams(value) {
|
|
|
return value.modifier && value.modifier._attribute && value.nodeContent;
|
|
|
}
|
|
|
function isComponentPublicInstance(value) {
|
|
|
return value.$ && isComponentInternalInstance(value.$);
|
|
|
}
|
|
|
function isComponentInternalInstance(value) {
|
|
|
return value.type && value.uid != null && value.appContext;
|
|
|
}
|
|
|
function formatComponentPublicInstance(value, depth) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
className: 'ComponentPublicInstance',
|
|
|
value: {
|
|
|
properties: Object.entries(value.$.type).map(function (_a) {
|
|
|
var name = _a[0], value = _a[1];
|
|
|
return formatObjectProperty(name, value, depth + 1);
|
|
|
}),
|
|
|
},
|
|
|
};
|
|
|
}
|
|
|
function formatComponentInternalInstance(value, depth) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
className: 'ComponentInternalInstance',
|
|
|
value: {
|
|
|
properties: Object.entries(value.type).map(function (_a) {
|
|
|
var name = _a[0], value = _a[1];
|
|
|
return formatObjectProperty(name, value, depth + 1);
|
|
|
}),
|
|
|
},
|
|
|
};
|
|
|
}
|
|
|
function isUniElement(value) {
|
|
|
return value.style && value.tagName != null && value.nodeName != null;
|
|
|
}
|
|
|
function formatUniElement(value, depth) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
// 非 x 没有 UniElement 的概念
|
|
|
// className: 'UniElement',
|
|
|
value: {
|
|
|
properties: Object.entries(value)
|
|
|
.filter(function (_a) {
|
|
|
var name = _a[0];
|
|
|
return [
|
|
|
'id',
|
|
|
'tagName',
|
|
|
'nodeName',
|
|
|
'dataset',
|
|
|
'offsetTop',
|
|
|
'offsetLeft',
|
|
|
'style',
|
|
|
].includes(name);
|
|
|
})
|
|
|
.map(function (_a) {
|
|
|
var name = _a[0], value = _a[1];
|
|
|
return formatObjectProperty(name, value, depth + 1);
|
|
|
}),
|
|
|
},
|
|
|
};
|
|
|
}
|
|
|
function isCSSStyleDeclaration(value) {
|
|
|
return (typeof value.getPropertyValue === 'function' &&
|
|
|
typeof value.setProperty === 'function' &&
|
|
|
value.$styles);
|
|
|
}
|
|
|
function formatCSSStyleDeclaration(style, depth) {
|
|
|
return {
|
|
|
type: 'object',
|
|
|
value: {
|
|
|
properties: Object.entries(style.$styles).map(function (_a) {
|
|
|
var name = _a[0], value = _a[1];
|
|
|
return formatObjectProperty(name, value, depth + 1);
|
|
|
}),
|
|
|
},
|
|
|
};
|
|
|
}
|
|
|
function formatObjectProperty(name, value, depth) {
|
|
|
var result = formatArg(value, depth);
|
|
|
result.name = name;
|
|
|
return result;
|
|
|
}
|
|
|
function formatArrayElement(value, index, depth) {
|
|
|
var result = formatArg(value, depth);
|
|
|
result.name = "".concat(index);
|
|
|
return result;
|
|
|
}
|
|
|
function formatSetEntry(value, depth) {
|
|
|
return {
|
|
|
value: formatArg(value, depth),
|
|
|
};
|
|
|
}
|
|
|
function formatMapEntry(value, depth) {
|
|
|
return {
|
|
|
key: formatArg(value[0], depth),
|
|
|
value: formatArg(value[1], depth),
|
|
|
};
|
|
|
}
|
|
|
|
|
|
var sendConsole = null;
|
|
|
var messageQueue = [];
|
|
|
var messageExtra = {};
|
|
|
var EXCEPTION_BEGIN_MARK = '---BEGIN:EXCEPTION---';
|
|
|
var EXCEPTION_END_MARK = '---END:EXCEPTION---';
|
|
|
function sendConsoleMessages(messages) {
|
|
|
if (sendConsole == null) {
|
|
|
messageQueue.push.apply(messageQueue, messages);
|
|
|
return;
|
|
|
}
|
|
|
sendConsole(JSON.stringify(Object.assign({
|
|
|
type: 'console',
|
|
|
data: messages,
|
|
|
}, messageExtra)));
|
|
|
}
|
|
|
function setSendConsole(value, extra) {
|
|
|
if (extra === void 0) { extra = {}; }
|
|
|
sendConsole = value;
|
|
|
Object.assign(messageExtra, extra);
|
|
|
if (value != null && messageQueue.length > 0) {
|
|
|
var messages = messageQueue.slice();
|
|
|
messageQueue.length = 0;
|
|
|
sendConsoleMessages(messages);
|
|
|
}
|
|
|
}
|
|
|
var atFileRegex = /^\s*at\s+[\w/./-]+:\d+$/;
|
|
|
function rewriteConsole() {
|
|
|
function wrapConsole(type) {
|
|
|
return function () {
|
|
|
var args = [];
|
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
|
args[_i] = arguments[_i];
|
|
|
}
|
|
|
{
|
|
|
var originalArgs = __spreadArray([], args, true);
|
|
|
if (originalArgs.length) {
|
|
|
var maybeAtFile = originalArgs[originalArgs.length - 1];
|
|
|
// 移除最后的 at pages/index/index.uvue:6
|
|
|
if (typeof maybeAtFile === 'string' &&
|
|
|
atFileRegex.test(maybeAtFile)) {
|
|
|
originalArgs.pop();
|
|
|
}
|
|
|
}
|
|
|
originalConsole[type].apply(originalConsole, originalArgs);
|
|
|
}
|
|
|
if (type === 'error' && args.length === 1) {
|
|
|
var arg = args[0];
|
|
|
if (typeof arg === 'string' && arg.startsWith(EXCEPTION_BEGIN_MARK)) {
|
|
|
var startIndex = EXCEPTION_BEGIN_MARK.length;
|
|
|
var endIndex = arg.length - EXCEPTION_END_MARK.length;
|
|
|
sendErrorMessages([arg.slice(startIndex, endIndex)]);
|
|
|
return;
|
|
|
}
|
|
|
else if (arg instanceof Error) {
|
|
|
sendErrorMessages([arg]);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
sendConsoleMessages([formatMessage(type, args)]);
|
|
|
};
|
|
|
}
|
|
|
// 百度小程序不允许赋值,所以需要判断是否可写
|
|
|
if (isConsoleWritable()) {
|
|
|
CONSOLE_TYPES.forEach(function (type) {
|
|
|
console[type] = wrapConsole(type);
|
|
|
});
|
|
|
return function restoreConsole() {
|
|
|
CONSOLE_TYPES.forEach(function (type) {
|
|
|
console[type] = originalConsole[type];
|
|
|
});
|
|
|
};
|
|
|
}
|
|
|
return function restoreConsole() {
|
|
|
};
|
|
|
}
|
|
|
function isConsoleWritable() {
|
|
|
var value = console.log;
|
|
|
var sym = Symbol();
|
|
|
try {
|
|
|
// @ts-expect-error
|
|
|
console.log = sym;
|
|
|
}
|
|
|
catch (ex) {
|
|
|
return false;
|
|
|
}
|
|
|
// @ts-expect-error
|
|
|
var isWritable = console.log === sym;
|
|
|
console.log = value;
|
|
|
return isWritable;
|
|
|
}
|
|
|
|
|
|
function initUniWebviewRuntimeService() {
|
|
|
if (window.__UNI_CONSOLE_WEBVIEW__)
|
|
|
return;
|
|
|
window.__UNI_CONSOLE_WEBVIEW__ = true;
|
|
|
var channel = "[web-view]".concat(window.__UNI_PAGE_ROUTE__ ? "[".concat(window.__UNI_PAGE_ROUTE__, "]") : '');
|
|
|
rewriteConsole();
|
|
|
setSendConsole(function (data) {
|
|
|
sendToService(data);
|
|
|
}, {
|
|
|
channel: channel,
|
|
|
});
|
|
|
setSendError(function (data) {
|
|
|
sendToService(data);
|
|
|
}, {
|
|
|
channel: channel,
|
|
|
});
|
|
|
// 监听同步错误
|
|
|
window.addEventListener('error', function (event) {
|
|
|
sendErrorMessages([event.error]);
|
|
|
});
|
|
|
// 监听Promise未处理的异步错误
|
|
|
window.addEventListener('unhandledrejection', function (event) {
|
|
|
sendErrorMessages([event]);
|
|
|
});
|
|
|
}
|
|
|
function sendToService(data) {
|
|
|
// 发送数据到 service 层
|
|
|
var serviceMessage = {
|
|
|
type: 'WEB_INVOKE_APPSERVICE',
|
|
|
args: {
|
|
|
data: {
|
|
|
name: 'console',
|
|
|
arg: data,
|
|
|
},
|
|
|
},
|
|
|
};
|
|
|
// @ts-expect-error
|
|
|
if (window.__uniapp_x_postMessageToService) {
|
|
|
// @ts-expect-error
|
|
|
return window.__uniapp_x_postMessageToService(serviceMessage);
|
|
|
}
|
|
|
else {
|
|
|
// @ts-expect-error
|
|
|
return window.__uniapp_x_.postMessageToService(JSON.stringify(serviceMessage));
|
|
|
}
|
|
|
}
|
|
|
initUniWebviewRuntimeService();
|
|
|
|
|
|
})();
|