diff --git a/packages/uni-stacktracey/LICENSE b/packages/uni-stacktracey/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..7a4a3ea2424c09fbe48d455aed1eaa94d9124835 --- /dev/null +++ b/packages/uni-stacktracey/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/packages/uni-stacktracey/dist/uni-stacktracey.cjs.js b/packages/uni-stacktracey/dist/uni-stacktracey.cjs.js new file mode 100644 index 0000000000000000000000000000000000000000..389d2d323e10089d4c5a2d57d9c1f8aa0ce748e6 --- /dev/null +++ b/packages/uni-stacktracey/dist/uni-stacktracey.cjs.js @@ -0,0 +1,534 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var fs = require('fs'); +var sourceMap = require('source-map'); + +function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } + +var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs); + +/* ------------------------------------------------------------------------ */ +const O = Object, isBrowser = +/* eslint-disable */ +typeof window !== 'undefined' && + /* eslint-disable */ + window.window === window && + /* eslint-disable */ + window.navigator, nodeRequire = isBrowser ? null : module.require, // to prevent bundlers from expanding the require call +lastOf = (x) => x[x.length - 1], nixSlashes$1 = (x) => x.replace(/\\/g, '/'), pathRoot = isBrowser ? window.location.href : nixSlashes$1(process.cwd()) + '/'; +/* ------------------------------------------------------------------------ */ +class StackTracey { + constructor(input, uniPlatform, offset) { + this.itemsHeader = []; + this.isMP = false; + const originalInput = input, isParseableSyntaxError = input && input instanceof SyntaxError && !isBrowser; + /* new StackTracey () */ + if (!input) { + input = new Error(); + offset = offset === undefined ? 1 : offset; + } + /* new StackTracey (Error) */ + if (input instanceof Error) { + input = input.stack || ''; + } + /* new StackTracey (string) */ + if (typeof input === 'string') { + this.isMP = uniPlatform === 'mp-weixin'; + input = this.rawParse(input) + .slice(offset) + .map((x) => this.extractEntryMetadata(x)); + } + /* new StackTracey (array) */ + if (Array.isArray(input)) { + if (isParseableSyntaxError) { + const rawLines = nodeRequire('util') + .inspect(originalInput) + .split('\n'), fileLine = rawLines[0].split(':'), line = fileLine.pop(), file = fileLine.join(':'); + if (file) { + input.unshift({ + file: nixSlashes$1(file), + line: line, + column: (rawLines[2] || '').indexOf('^') + 1, + sourceLine: rawLines[1], + callee: '(syntax error)', + syntaxError: true, + }); + } + } + this.items = input; + } + else { + this.items = []; + } + } + extractEntryMetadata(e) { + const decomposedPath = this.decomposePath(e.file || ''); + const fileRelative = decomposedPath[0]; + const externalDomain = decomposedPath[1]; + return O.assign(e, { + calleeShort: e.calleeShort || lastOf((e.callee || '').split('.')), + fileRelative: fileRelative, + fileShort: this.shortenPath(fileRelative), + fileName: lastOf((e.file || '').split('/')), + thirdParty: this.isThirdParty(fileRelative, externalDomain) && !e.index, + externalDomain: externalDomain, + }); + } + shortenPath(relativePath) { + return relativePath + .replace(/^node_modules\//, '') + .replace(/^webpack\/bootstrap\//, '') + .replace(/^__parcel_source_root\//, ''); + } + decomposePath(fullPath) { + let result = fullPath; + if (isBrowser) + result = result.replace(pathRoot, ''); + const externalDomainMatch = result.match(/^(http|https)\:\/\/?([^\/]+)\/{1,}(.*)/); + const externalDomain = externalDomainMatch + ? externalDomainMatch[2] + : undefined; + result = externalDomainMatch ? externalDomainMatch[3] : result; + // if (!isBrowser) result = nodeRequire!('path').relative(pathRoot, result) + return [ + nixSlashes$1(result).replace(/^.*\:\/\/?\/?/, ''), + externalDomain, + ]; + } + isThirdParty(relativePath, externalDomain) { + if (this.isMP) { + if (typeof externalDomain === 'undefined') + return false; + return externalDomain !== 'usr'; + } + return ( + // 由于 hello-uniapp web 端报错携带 hellouniapp.dcloud.net.cn + // externalDomain || + relativePath[0] === '~' || // webpack-specific heuristic + relativePath[0] === '/' || // external source + relativePath.indexOf('@dcloudio') !== -1 || + relativePath.indexOf('weex-main-jsfm') !== -1 || + relativePath.indexOf('webpack/bootstrap') === 0); + } + rawParse(str) { + const lines = (str || '').split('\n'); + const entries = lines.map((line, index) => { + line = line.trim(); + let callee, fileLineColumn = [], native, planA, planB; + if (line.indexOf('file:') !== -1) { + line = line.replace(/file:\/\/(.*)www/, 'file://'); + } + if ((planA = line.match(/at (.+) \(eval at .+ \((.+)\), .+\)/)) || // eval calls + (planA = line.match(/at (.+) \((.+)\)/)) || + (line.slice(0, 3) !== 'at ' && (planA = line.match(/(.*)@(.*)/)))) { + this.itemsHeader.push('%StacktraceyItem%'); + callee = planA[1]; + native = planA[2] === 'native'; + fileLineColumn = (planA[2].match(/(.*):(\d+):(\d+)/) || + planA[2].match(/(.*):(\d+)/) || + planA[2].match(/\[(.*)\]/) || + []).slice(1); + } + else if ((planB = line.match(/^(at\s*)*(.*)\s+(.+):(\d+):(\d+)/))) { + this.itemsHeader.push('%StacktraceyItem%'); + callee = planB[2].trim(); + fileLineColumn = planB.slice(3); + } + else { + this.itemsHeader.push(line); + return undefined; + } + /* Detect things like Array.reduce + TODO: detect more built-in types */ + if (callee && !fileLineColumn[0]) { + const type = callee.split('.')[0]; + if (type === 'Array') { + native = true; + } + } + return { + beforeParse: line, + callee: callee || '', + /* eslint-disable */ + index: isBrowser && fileLineColumn[0] === window.location.href, + native: native || false, + file: nixSlashes$1(fileLineColumn[0] || ''), + line: parseInt(fileLineColumn[1] || '', 10) || undefined, + column: parseInt(fileLineColumn[2] || '', 10) || undefined, + }; + }); + return entries.filter((x) => x !== undefined); + } + maxColumnWidths() { + return { + callee: 30, + file: 60, + sourceLine: 80, + }; + } + asTable(opts) { + const maxColumnWidths = (opts && opts.maxColumnWidths) || this.maxColumnWidths(); + const trimmed = this + .filter((e) => !e.thirdParty) + .map((e) => parseItem(e, maxColumnWidths, this.isMP)); + const trimmedThirdParty = this + .filter((e) => e.thirdParty) + .map((e) => parseItem(e, maxColumnWidths, this.isMP)); + return { + items: trimmed.items, + thirdPartyItems: trimmedThirdParty.items, + }; + } +} +const trimEnd = (s, n) => s && (s.length > n ? s.slice(0, n - 1) + '…' : s); +const trimStart = (s, n) => s && (s.length > n ? '…' + s.slice(-(n - 1)) : s); +function parseItem(e, maxColumnWidths, isMP) { + if (!e.parsed) { + return e.beforeParse; + } + const filePath = (isMP ? e.file && e.file : e.fileShort && e.fileShort) + + `${e.line ? ':' + e.line : ''}` + + `${e.column ? ':' + e.column : ''}`; + return [ + 'at ' + trimEnd(isMP ? e.callee : e.calleeShort, maxColumnWidths.callee), + trimStart(filePath || '', maxColumnWidths.file), + trimEnd((e.sourceLine || '').trim() || '', maxColumnWidths.sourceLine), + ]; +} +['map', 'filter', 'slice', 'concat'].forEach((method) => { + StackTracey.prototype[method] = function ( /*...args */) { + // no support for ...args in Node v4 :( + return new StackTracey(this.items[method].apply(this.items, arguments)); + }; +}); +/* ------------------------------------------------------------------------ */ +var StackTracey$1 = StackTracey; + +const nixSlashes = (x) => x.replace(/\\/g, '/'); +const sourcemapCatch = {}; +function stacktracey(stacktrace, opts) { + const stack = opts.preset.parseStacktrace(stacktrace); + let parseStack = Promise.resolve(); + stack.items.forEach((item, index) => { + const fn = (item, index) => { + const { line = 0, column = 0, file, fileName, fileRelative } = item; + if (item.thirdParty) { + return Promise.resolve(); + } + function _getSourceMapContent(file, fileName, fileRelative) { + return opts.preset + .getSourceMapContent(file, fileName, fileRelative) + .then((content) => { + if (content) { + return getConsumer(content).then((consumer) => { + return parseSourceMapContent(consumer, { + line, + column, + }); + }); + } + }); + } + try { + return _getSourceMapContent(file, fileName, fileRelative).then((sourceMapContent) => { + if (sourceMapContent) { + const { source, sourcePath, sourceLine, sourceColumn, fileName = '', } = sourceMapContent; + stack.items[index] = Object.assign({}, item, { + file: source, + line: sourceLine, + column: sourceColumn, + fileShort: sourcePath, + fileRelative: source, + fileName, + thirdParty: isThirdParty(sourcePath), + parsed: true, + }); + /** + * 以 .js 结尾 + * 包含 app-service.js 则需要再解析 两次 + * 不包含 app-service.js 则无需再解析 一次 + */ + const curItem = stack.items[index]; + if (stack.isMP && + curItem.beforeParse.indexOf('app-service') !== -1) { + return fn(curItem, index); + } + } + }); + } + catch (error) { + return Promise.resolve(); + } + }; + parseStack = parseStack.then(() => { + return new Promise((resolve, reject) => { + setTimeout(() => { + fn(item, index).then(resolve); + }, 0); + }); + }); + }); + const _promise = new Promise((resolve, reject) => { + parseStack + .then(() => { + const parseError = opts.preset.asTableStacktrace({ + stack, + maxColumnWidths: { + callee: 999, + file: 999, + sourceLine: 999, + }, + stacktrace, + }); + resolve(parseError); + }) + .catch(() => { + resolve(stacktrace); + }); + }); + return _promise; +} +function isThirdParty(relativePath) { + return relativePath.indexOf('@dcloudio') !== -1; +} +function getConsumer(content) { + return new Promise((resolve, reject) => { + try { + if (sourceMap.SourceMapConsumer.with) { + sourceMap.SourceMapConsumer.with(content, null, (consumer) => { + resolve(consumer); + }); + } + else { + // @ts-ignore + const consumer = sourceMap.SourceMapConsumer(content); + resolve(consumer); + } + } + catch (error) { + reject(); + } + }); +} +function getSourceMapContent(sourcemapUrl) { + try { + return (sourcemapCatch[sourcemapUrl] || + (sourcemapCatch[sourcemapUrl] = new Promise((resolve, reject) => { + try { + if (/^[http|https]+:/i.test(sourcemapUrl)) { + uni.request({ + url: sourcemapUrl, + success: (res) => { + if (res.statusCode === 200) { + sourcemapCatch[sourcemapUrl] = res.data; + resolve(sourcemapCatch[sourcemapUrl]); + } + else { + resolve((sourcemapCatch[sourcemapUrl] = '')); + } + }, + fail() { + resolve((sourcemapCatch[sourcemapUrl] = '')); + }, + }); + } + else { + sourcemapCatch[sourcemapUrl] = fs__default["default"].readFileSync(sourcemapUrl, 'utf-8'); + resolve(sourcemapCatch[sourcemapUrl]); + } + } + catch (error) { + resolve(''); + } + }))); + } + catch (error) { + return ''; + } +} +function parseSourceMapContent(consumer, obj) { + // source -> 'uni-app:///node_modules/@sentry/browser/esm/helpers.js' + const { source, line: sourceLine, column: sourceColumn, } = consumer.originalPositionFor(obj); + if (source) { + const sourcePathSplit = source.split('/'); + const sourcePath = sourcePathSplit.slice(3).join('/'); + const fileName = sourcePathSplit.pop(); + return { + source, + sourcePath, + sourceLine: sourceLine === null ? 0 : sourceLine, + sourceColumn: sourceColumn === null ? 0 : sourceColumn, + fileName, + }; + } +} +function joinItem(item) { + if (typeof item === 'string') { + return item; + } + const a = item[0]; + const b = item[1] ? ` ${item[1]}` : ''; + const c = item[2] ? ` ${item[2]}` : ''; + return `${a}${b}${c}`; +} +function uniStracktraceyPreset(opts) { + const { base, sourceRoot, splitThirdParty, uniPlatform } = opts; + let stack; + return { + /** + * + * 微信特殊处理 + * 微信解析步骤: + * 1. //usr/app-service.js -> 'weixin/__APP__/app-service.map.map' + * 2. //usr/pages/API/app-service.js -> 'weixin/pages/API/app-service.map.map' + * 3. uni-list-item/uni-list-item.js -> ${base}/uni-list-item/uni-list-item.js.map + */ + parseSourceMapUrl(file, fileName, fileRelative) { + // 组合 sourceMapUrl + if (fileRelative.indexOf('(') !== -1) + fileRelative = fileRelative.match(/\((.*)/)[1]; + if (!base || !fileRelative) + return ''; + if (sourceRoot) { + return `${fileRelative.replace(sourceRoot, base + '/')}.map`; + } + let baseAfter = ''; + if (stack.isMP) { + if (fileRelative.indexOf('app-service.js') !== -1) { + baseAfter = (base.match(/\w$/) ? '/' : '') + '__WEIXIN__'; + if (fileRelative === fileName) { + baseAfter += '/__APP__'; + } + fileRelative = fileRelative.replace('.js', '.map'); + } + if (baseAfter && !!fileRelative.match(/^\w/)) + baseAfter += '/'; + } + return `${base}${baseAfter}${fileRelative}.map`; + }, + getSourceMapContent(file, fileName, fileRelative) { + if (stack.isMP && fileRelative.indexOf('.js') === -1) { + return Promise.resolve(''); + } + const sourcemapUrl = this.parseSourceMapUrl(file, fileName, fileRelative); + return Promise.resolve(getSourceMapContent(sourcemapUrl)); + }, + parseStacktrace(stacktrace) { + stack = new StackTracey$1(stacktrace, uniPlatform); + return stack; + }, + asTableStacktrace({ maxColumnWidths, stacktrace, stack }) { + const errorName = stacktrace.split('\n')[0]; + const lines = stack.asTable + ? stack.asTable(maxColumnWidths ? { maxColumnWidths } : undefined) + : { items: [], thirdPartyItems: [] }; + if (lines.items.length || lines.thirdPartyItems.length) { + const { items: stackLines, thirdPartyItems: stackThirdPartyLines } = lines; + const userError = stack.itemsHeader + .map((item) => { + if (item === '%StacktraceyItem%') { + const _stack = stackLines.shift(); + return _stack ? joinItem(_stack) : ''; + } + return item; + }) + .filter(Boolean) + .join('\n'); + const thirdParty = stackThirdPartyLines.length + ? stackThirdPartyLines.map(joinItem).join('\n') + : ''; + if (splitThirdParty) { + return { + userError, + thirdParty, + }; + } + return userError + '\n' + thirdParty; + } + else { + if (splitThirdParty) { + return { + userError: errorName, + thirdParty: '', + }; + } + return errorName; + } + }, + }; +} +function utsStracktraceyPreset(opts) { + const { base, sourceRoot } = opts; + let errStack = []; + return { + parseSourceMapUrl(file, fileName, fileRelative) { + // 组合 sourceMapUrl + if (sourceRoot) { + return `${file.replace(sourceRoot, base + '/')}.map`; + } + return `${base}/${file}.map`; + }, + getSourceMapContent(file, fileName, fileRelative) { + // 根据 base,filename 组合 sourceMapUrl + return Promise.resolve(getSourceMapContent(this.parseSourceMapUrl(file, fileName, fileRelative))); + }, + parseStacktrace(str) { + const lines = (str || '').split('\n'); + const entries = lines + .map((line, index) => { + line = line.trim(); + let callee, fileLineColumn = [], planA, planB; + if ((planA = line.match(/e: (.+\.kt)(.+\))*:\s*(.+)*/))) { + errStack.push('%StacktraceyItem%'); + callee = 'e: '; + fileLineColumn = (planA[2].match(/.*:.*\((\d+).+?(\d+)\)/) || []).slice(1); + } + else { + errStack.push(line); + return undefined; + } + const fileName = planA[1] + ? (planB = planA[1].match(/(.*)*\/(.+)/) || [])[2] || '' + : ''; + return { + beforeParse: line, + callee: callee || '', + index: false, + native: false, + file: nixSlashes(planA[1] || ''), + line: parseInt(fileLineColumn[0] || '', 10) || undefined, + column: parseInt(fileLineColumn[1] || '', 10) || undefined, + fileName, + fileShort: planB ? planB[1] : '', + errMsg: planA[3] || '', + calleeShort: '', + fileRelative: '', + thirdParty: false, + }; + }) + .filter((x) => x !== undefined); + return { + items: entries, + itemsHeader: [], + }; + }, + asTableStacktrace({ maxColumnWidths, stacktrace, stack }) { + return errStack + .map((item) => { + if (item === '%StacktraceyItem%') { + const _stack = stack.items.shift(); + if (_stack) + return `${_stack.callee}${_stack.file}: (${_stack.line}, ${_stack.column}): ${_stack.errMsg}`; + } + return item; + }) + .join('\n'); + }, + }; +} + +exports.stacktracey = stacktracey; +exports.uniStracktraceyPreset = uniStracktraceyPreset; +exports.utsStracktraceyPreset = utsStracktraceyPreset; diff --git a/packages/uni-stacktracey/dist/uni-stacktracey.es.js b/packages/uni-stacktracey/dist/uni-stacktracey.es.js new file mode 100644 index 0000000000000000000000000000000000000000..5dbfcce215fe287b4c931fa6c0df8c57f90ca76d --- /dev/null +++ b/packages/uni-stacktracey/dist/uni-stacktracey.es.js @@ -0,0 +1,534 @@ +import fs from 'fs'; +import { SourceMapConsumer } from 'source-map'; + +/* ------------------------------------------------------------------------ */ +const O = Object, isBrowser = +/* eslint-disable */ +typeof window !== 'undefined' && + /* eslint-disable */ + window.window === window && + /* eslint-disable */ + window.navigator, nodeRequire = isBrowser ? null : module.require, // to prevent bundlers from expanding the require call +lastOf = (x) => x[x.length - 1], nixSlashes$1 = (x) => x.replace(/\\/g, '/'), pathRoot = isBrowser ? window.location.href : nixSlashes$1(process.cwd()) + '/'; +/* ------------------------------------------------------------------------ */ +class StackTracey { + constructor(input, uniPlatform, offset) { + this.itemsHeader = []; + this.isMP = false; + const originalInput = input, isParseableSyntaxError = input && input instanceof SyntaxError && !isBrowser; + /* new StackTracey () */ + if (!input) { + input = new Error(); + offset = offset === undefined ? 1 : offset; + } + /* new StackTracey (Error) */ + if (input instanceof Error) { + input = input.stack || ''; + } + /* new StackTracey (string) */ + if (typeof input === 'string') { + this.isMP = uniPlatform === 'mp-weixin'; + input = this.rawParse(input) + .slice(offset) + .map((x) => this.extractEntryMetadata(x)); + } + /* new StackTracey (array) */ + if (Array.isArray(input)) { + if (isParseableSyntaxError) { + const rawLines = nodeRequire('util') + .inspect(originalInput) + .split('\n'), fileLine = rawLines[0].split(':'), line = fileLine.pop(), file = fileLine.join(':'); + if (file) { + input.unshift({ + file: nixSlashes$1(file), + line: line, + column: (rawLines[2] || '').indexOf('^') + 1, + sourceLine: rawLines[1], + callee: '(syntax error)', + syntaxError: true, + }); + } + } + this.items = input; + } + else { + this.items = []; + } + } + extractEntryMetadata(e) { + const decomposedPath = this.decomposePath(e.file || ''); + const fileRelative = decomposedPath[0]; + const externalDomain = decomposedPath[1]; + return O.assign(e, { + calleeShort: e.calleeShort || lastOf((e.callee || '').split('.')), + fileRelative: fileRelative, + fileShort: this.shortenPath(fileRelative), + fileName: lastOf((e.file || '').split('/')), + thirdParty: this.isThirdParty(fileRelative, externalDomain) && !e.index, + externalDomain: externalDomain, + }); + } + shortenPath(relativePath) { + return relativePath + .replace(/^node_modules\//, '') + .replace(/^webpack\/bootstrap\//, '') + .replace(/^__parcel_source_root\//, ''); + } + decomposePath(fullPath) { + let result = fullPath; + if (isBrowser) + result = result.replace(pathRoot, ''); + const externalDomainMatch = result.match(/^(http|https)\:\/\/?([^\/]+)\/{1,}(.*)/); + const externalDomain = externalDomainMatch + ? externalDomainMatch[2] + : undefined; + result = externalDomainMatch ? externalDomainMatch[3] : result; + // if (!isBrowser) result = nodeRequire!('path').relative(pathRoot, result) + return [ + nixSlashes$1(result).replace(/^.*\:\/\/?\/?/, ''), + externalDomain, + ]; + } + isThirdParty(relativePath, externalDomain) { + if (this.isMP) { + if (typeof externalDomain === 'undefined') + return false; + return externalDomain !== 'usr'; + } + return ( + // 由于 hello-uniapp web 端报错携带 hellouniapp.dcloud.net.cn + // externalDomain || + relativePath[0] === '~' || // webpack-specific heuristic + relativePath[0] === '/' || // external source + relativePath.indexOf('@dcloudio') !== -1 || + relativePath.indexOf('weex-main-jsfm') !== -1 || + relativePath.indexOf('webpack/bootstrap') === 0); + } + rawParse(str) { + const lines = (str || '').split('\n'); + const entries = lines.map((line, index) => { + line = line.trim(); + let callee, fileLineColumn = [], native, planA, planB; + if (line.indexOf('file:') !== -1) { + line = line.replace(/file:\/\/(.*)www/, 'file://'); + } + if ((planA = line.match(/at (.+) \(eval at .+ \((.+)\), .+\)/)) || // eval calls + (planA = line.match(/at (.+) \((.+)\)/)) || + (line.slice(0, 3) !== 'at ' && (planA = line.match(/(.*)@(.*)/)))) { + this.itemsHeader.push('%StacktraceyItem%'); + callee = planA[1]; + native = planA[2] === 'native'; + fileLineColumn = (planA[2].match(/(.*):(\d+):(\d+)/) || + planA[2].match(/(.*):(\d+)/) || + planA[2].match(/\[(.*)\]/) || + []).slice(1); + } + else if ((planB = line.match(/^(at\s*)*(.*)\s+(.+):(\d+):(\d+)/))) { + this.itemsHeader.push('%StacktraceyItem%'); + callee = planB[2].trim(); + fileLineColumn = planB.slice(3); + } + else { + this.itemsHeader.push(line); + return undefined; + } + /* Detect things like Array.reduce + TODO: detect more built-in types */ + if (callee && !fileLineColumn[0]) { + const type = callee.split('.')[0]; + if (type === 'Array') { + native = true; + } + } + return { + beforeParse: line, + callee: callee || '', + /* eslint-disable */ + index: isBrowser && fileLineColumn[0] === window.location.href, + native: native || false, + file: nixSlashes$1(fileLineColumn[0] || ''), + line: parseInt(fileLineColumn[1] || '', 10) || undefined, + column: parseInt(fileLineColumn[2] || '', 10) || undefined, + }; + }); + return entries.filter((x) => x !== undefined); + } + maxColumnWidths() { + return { + callee: 30, + file: 60, + sourceLine: 80, + }; + } + asTable(opts) { + const maxColumnWidths = (opts && opts.maxColumnWidths) || this.maxColumnWidths(); + const trimmed = this + .filter((e) => !e.thirdParty) + .map((e) => parseItem(e, maxColumnWidths, this.isMP)); + const trimmedThirdParty = this + .filter((e) => e.thirdParty) + .map((e) => parseItem(e, maxColumnWidths, this.isMP)); + return { + items: trimmed.items, + thirdPartyItems: trimmedThirdParty.items, + }; + } +} +const trimEnd = (s, n) => s && (s.length > n ? s.slice(0, n - 1) + '…' : s); +const trimStart = (s, n) => s && (s.length > n ? '…' + s.slice(-(n - 1)) : s); +function parseItem(e, maxColumnWidths, isMP) { + if (!e.parsed) { + return e.beforeParse; + } + const filePath = (isMP ? e.file && e.file : e.fileShort && e.fileShort) + + `${e.line ? ':' + e.line : ''}` + + `${e.column ? ':' + e.column : ''}`; + return [ + 'at ' + trimEnd(isMP ? e.callee : e.calleeShort, maxColumnWidths.callee), + trimStart(filePath || '', maxColumnWidths.file), + trimEnd((e.sourceLine || '').trim() || '', maxColumnWidths.sourceLine), + ]; +} +['map', 'filter', 'slice', 'concat'].forEach((method) => { + StackTracey.prototype[method] = function ( /*...args */) { + // no support for ...args in Node v4 :( + return new StackTracey(this.items[method].apply(this.items, arguments)); + }; +}); +/* ------------------------------------------------------------------------ */ +var StackTracey$1 = StackTracey; + +// @ts-ignore +{ + // @ts-ignore + if (SourceMapConsumer.initialize) { + // @ts-ignore + SourceMapConsumer.initialize({ + 'lib/mappings.wasm': 'https://unpkg.com/source-map@0.7.3/lib/mappings.wasm', + }); + } +} +const nixSlashes = (x) => x.replace(/\\/g, '/'); +const sourcemapCatch = {}; +function stacktracey(stacktrace, opts) { + const stack = opts.preset.parseStacktrace(stacktrace); + let parseStack = Promise.resolve(); + stack.items.forEach((item, index) => { + const fn = (item, index) => { + const { line = 0, column = 0, file, fileName, fileRelative } = item; + if (item.thirdParty) { + return Promise.resolve(); + } + function _getSourceMapContent(file, fileName, fileRelative) { + return opts.preset + .getSourceMapContent(file, fileName, fileRelative) + .then((content) => { + if (content) { + return getConsumer(content).then((consumer) => { + return parseSourceMapContent(consumer, { + line, + column, + }); + }); + } + }); + } + try { + return _getSourceMapContent(file, fileName, fileRelative).then((sourceMapContent) => { + if (sourceMapContent) { + const { source, sourcePath, sourceLine, sourceColumn, fileName = '', } = sourceMapContent; + stack.items[index] = Object.assign({}, item, { + file: source, + line: sourceLine, + column: sourceColumn, + fileShort: sourcePath, + fileRelative: source, + fileName, + thirdParty: isThirdParty(sourcePath), + parsed: true, + }); + /** + * 以 .js 结尾 + * 包含 app-service.js 则需要再解析 两次 + * 不包含 app-service.js 则无需再解析 一次 + */ + const curItem = stack.items[index]; + if (stack.isMP && + curItem.beforeParse.indexOf('app-service') !== -1) { + return fn(curItem, index); + } + } + }); + } + catch (error) { + return Promise.resolve(); + } + }; + parseStack = parseStack.then(() => { + return new Promise((resolve, reject) => { + setTimeout(() => { + fn(item, index).then(resolve); + }, 0); + }); + }); + }); + const _promise = new Promise((resolve, reject) => { + parseStack + .then(() => { + const parseError = opts.preset.asTableStacktrace({ + stack, + maxColumnWidths: { + callee: 999, + file: 999, + sourceLine: 999, + }, + stacktrace, + }); + resolve(parseError); + }) + .catch(() => { + resolve(stacktrace); + }); + }); + return _promise; +} +function isThirdParty(relativePath) { + return relativePath.indexOf('@dcloudio') !== -1; +} +function getConsumer(content) { + return new Promise((resolve, reject) => { + try { + if (SourceMapConsumer.with) { + SourceMapConsumer.with(content, null, (consumer) => { + resolve(consumer); + }); + } + else { + // @ts-ignore + const consumer = SourceMapConsumer(content); + resolve(consumer); + } + } + catch (error) { + reject(); + } + }); +} +function getSourceMapContent(sourcemapUrl) { + try { + return (sourcemapCatch[sourcemapUrl] || + (sourcemapCatch[sourcemapUrl] = new Promise((resolve, reject) => { + try { + if (/^[http|https]+:/i.test(sourcemapUrl)) { + uni.request({ + url: sourcemapUrl, + success: (res) => { + if (res.statusCode === 200) { + sourcemapCatch[sourcemapUrl] = res.data; + resolve(sourcemapCatch[sourcemapUrl]); + } + else { + resolve((sourcemapCatch[sourcemapUrl] = '')); + } + }, + fail() { + resolve((sourcemapCatch[sourcemapUrl] = '')); + }, + }); + } + else { + sourcemapCatch[sourcemapUrl] = fs.readFileSync(sourcemapUrl, 'utf-8'); + resolve(sourcemapCatch[sourcemapUrl]); + } + } + catch (error) { + resolve(''); + } + }))); + } + catch (error) { + return ''; + } +} +function parseSourceMapContent(consumer, obj) { + // source -> 'uni-app:///node_modules/@sentry/browser/esm/helpers.js' + const { source, line: sourceLine, column: sourceColumn, } = consumer.originalPositionFor(obj); + if (source) { + const sourcePathSplit = source.split('/'); + const sourcePath = sourcePathSplit.slice(3).join('/'); + const fileName = sourcePathSplit.pop(); + return { + source, + sourcePath, + sourceLine: sourceLine === null ? 0 : sourceLine, + sourceColumn: sourceColumn === null ? 0 : sourceColumn, + fileName, + }; + } +} +function joinItem(item) { + if (typeof item === 'string') { + return item; + } + const a = item[0]; + const b = item[1] ? ` ${item[1]}` : ''; + const c = item[2] ? ` ${item[2]}` : ''; + return `${a}${b}${c}`; +} +function uniStracktraceyPreset(opts) { + const { base, sourceRoot, splitThirdParty, uniPlatform } = opts; + let stack; + return { + /** + * + * 微信特殊处理 + * 微信解析步骤: + * 1. //usr/app-service.js -> 'weixin/__APP__/app-service.map.map' + * 2. //usr/pages/API/app-service.js -> 'weixin/pages/API/app-service.map.map' + * 3. uni-list-item/uni-list-item.js -> ${base}/uni-list-item/uni-list-item.js.map + */ + parseSourceMapUrl(file, fileName, fileRelative) { + // 组合 sourceMapUrl + if (fileRelative.indexOf('(') !== -1) + fileRelative = fileRelative.match(/\((.*)/)[1]; + if (!base || !fileRelative) + return ''; + if (sourceRoot) { + return `${fileRelative.replace(sourceRoot, base + '/')}.map`; + } + let baseAfter = ''; + if (stack.isMP) { + if (fileRelative.indexOf('app-service.js') !== -1) { + baseAfter = (base.match(/\w$/) ? '/' : '') + '__WEIXIN__'; + if (fileRelative === fileName) { + baseAfter += '/__APP__'; + } + fileRelative = fileRelative.replace('.js', '.map'); + } + if (baseAfter && !!fileRelative.match(/^\w/)) + baseAfter += '/'; + } + return `${base}${baseAfter}${fileRelative}.map`; + }, + getSourceMapContent(file, fileName, fileRelative) { + if (stack.isMP && fileRelative.indexOf('.js') === -1) { + return Promise.resolve(''); + } + const sourcemapUrl = this.parseSourceMapUrl(file, fileName, fileRelative); + return Promise.resolve(getSourceMapContent(sourcemapUrl)); + }, + parseStacktrace(stacktrace) { + stack = new StackTracey$1(stacktrace, uniPlatform); + return stack; + }, + asTableStacktrace({ maxColumnWidths, stacktrace, stack }) { + const errorName = stacktrace.split('\n')[0]; + const lines = stack.asTable + ? stack.asTable(maxColumnWidths ? { maxColumnWidths } : undefined) + : { items: [], thirdPartyItems: [] }; + if (lines.items.length || lines.thirdPartyItems.length) { + const { items: stackLines, thirdPartyItems: stackThirdPartyLines } = lines; + const userError = stack.itemsHeader + .map((item) => { + if (item === '%StacktraceyItem%') { + const _stack = stackLines.shift(); + return _stack ? joinItem(_stack) : ''; + } + return item; + }) + .filter(Boolean) + .join('\n'); + const thirdParty = stackThirdPartyLines.length + ? stackThirdPartyLines.map(joinItem).join('\n') + : ''; + if (splitThirdParty) { + return { + userError, + thirdParty, + }; + } + return userError + '\n' + thirdParty; + } + else { + if (splitThirdParty) { + return { + userError: errorName, + thirdParty: '', + }; + } + return errorName; + } + }, + }; +} +function utsStracktraceyPreset(opts) { + const { base, sourceRoot } = opts; + let errStack = []; + return { + parseSourceMapUrl(file, fileName, fileRelative) { + // 组合 sourceMapUrl + if (sourceRoot) { + return `${file.replace(sourceRoot, base + '/')}.map`; + } + return `${base}/${file}.map`; + }, + getSourceMapContent(file, fileName, fileRelative) { + // 根据 base,filename 组合 sourceMapUrl + return Promise.resolve(getSourceMapContent(this.parseSourceMapUrl(file, fileName, fileRelative))); + }, + parseStacktrace(str) { + const lines = (str || '').split('\n'); + const entries = lines + .map((line, index) => { + line = line.trim(); + let callee, fileLineColumn = [], planA, planB; + if ((planA = line.match(/e: (.+\.kt)(.+\))*:\s*(.+)*/))) { + errStack.push('%StacktraceyItem%'); + callee = 'e: '; + fileLineColumn = (planA[2].match(/.*:.*\((\d+).+?(\d+)\)/) || []).slice(1); + } + else { + errStack.push(line); + return undefined; + } + const fileName = planA[1] + ? (planB = planA[1].match(/(.*)*\/(.+)/) || [])[2] || '' + : ''; + return { + beforeParse: line, + callee: callee || '', + index: false, + native: false, + file: nixSlashes(planA[1] || ''), + line: parseInt(fileLineColumn[0] || '', 10) || undefined, + column: parseInt(fileLineColumn[1] || '', 10) || undefined, + fileName, + fileShort: planB ? planB[1] : '', + errMsg: planA[3] || '', + calleeShort: '', + fileRelative: '', + thirdParty: false, + }; + }) + .filter((x) => x !== undefined); + return { + items: entries, + itemsHeader: [], + }; + }, + asTableStacktrace({ maxColumnWidths, stacktrace, stack }) { + return errStack + .map((item) => { + if (item === '%StacktraceyItem%') { + const _stack = stack.items.shift(); + if (_stack) + return `${_stack.callee}${_stack.file}: (${_stack.line}, ${_stack.column}): ${_stack.errMsg}`; + } + return item; + }) + .join('\n'); + }, + }; +} + +export { stacktracey, uniStracktraceyPreset, utsStracktraceyPreset }; diff --git a/packages/uni-stacktracey/package.json b/packages/uni-stacktracey/package.json new file mode 100644 index 0000000000000000000000000000000000000000..d03d533daaa4c5159c961a8f9bc0cc02aaf5c599 --- /dev/null +++ b/packages/uni-stacktracey/package.json @@ -0,0 +1,28 @@ +{ + "name": "@dcloudio/uni-stacktracey", + "version": "2.0.1-34720220422001", + "description": "@dcloudio/uni-stacktracey", + "main": "dist/uni-stacktracey.cjs.js", + "module": "dist/uni-stacktracey.es.js", + "files": [ + "dist", + "lib" + ], + "sideEffects": false, + "repository": { + "type": "git", + "url": "git+https://github.com/dcloudio/uni-app.git", + "directory": "packages/uni-stacktracey" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/dcloudio/uni-app/issues" + }, + "gitHead": "33e807d66e1fe47e2ee08ad9c59247e37b8884da", + "dependencies": { + "source-map": "^0.7.3" + }, + "devDependencies": { + "@dcloudio/types": "^2.6.12" + } +} diff --git a/packages/vue-cli-plugin-uni/generator.js b/packages/vue-cli-plugin-uni/generator.js index 3d2fd84749b2fded55dfb2c3dc51d09aae275a4d..639920ae05c034b81831592eedbb1f365e43c657 100644 --- a/packages/vue-cli-plugin-uni/generator.js +++ b/packages/vue-cli-plugin-uni/generator.js @@ -69,6 +69,7 @@ module.exports = (api, options, rootOptions) => { '@dcloudio/uni-quickapp-webview': version, '@dcloudio/uni-stat': version, '@dcloudio/uni-i18n': version, + '@dcloudio/uni-stacktracey': version, '@vue/shared': '^3.0.0', flyio: '^0.6.2', vuex: '^3.2.0'