From 8f393f7ef121955b9f0c42ef7bca2ae42d8146e7 Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Wed, 17 Apr 2024 13:47:23 +0800 Subject: [PATCH] =?UTF-8?q?feat(x-ios):=20=E6=8F=90=E4=BE=9B=20parseUTSJav?= =?UTF-8?q?aScriptRuntimeStacktrace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uni-app-harmony/dist/uni.runtime.esm.js | 237 +++++++++++++++++- .../uni-app-uts/src/plugins/ios/plugin.ts | 15 +- packages/uni-h5/dist-x/uni-h5.cjs.js | 17 +- packages/uni-h5/dist-x/uni-h5.es.js | 23 +- .../stacktrace.runtime.spec.ts.snap | 23 ++ .../sourcemap/index.kt.map | 0 .../sourcemap/pages/index/index.kt.map | 0 .../src/.manifest.json | 0 .../{.kotlin => app-android}/src/index.kt | 0 .../src/pages/index/index.kt | 0 .../app-ios/sourcemap/app-service.js.map | 1 + .../__tests__/stacktrace.runtime.spec.ts | 30 ++- packages/uni-uts-v1/src/stacktrace/js.ts | 157 ++++++++++++ packages/uni-uts-v1/src/stacktrace/kotlin.ts | 42 ++-- packages/uni-uts-v1/src/stacktrace/utils.ts | 27 ++ 15 files changed, 531 insertions(+), 41 deletions(-) rename packages/uni-uts-v1/__tests__/examples/uni-app-x/unpackage/cache/{.kotlin => app-android}/sourcemap/index.kt.map (100%) rename packages/uni-uts-v1/__tests__/examples/uni-app-x/unpackage/cache/{.kotlin => app-android}/sourcemap/pages/index/index.kt.map (100%) rename packages/uni-uts-v1/__tests__/examples/uni-app-x/unpackage/cache/{.kotlin => app-android}/src/.manifest.json (100%) rename packages/uni-uts-v1/__tests__/examples/uni-app-x/unpackage/cache/{.kotlin => app-android}/src/index.kt (100%) rename packages/uni-uts-v1/__tests__/examples/uni-app-x/unpackage/cache/{.kotlin => app-android}/src/pages/index/index.kt (100%) create mode 100644 packages/uni-uts-v1/__tests__/examples/uni-app-x/unpackage/cache/app-ios/sourcemap/app-service.js.map create mode 100644 packages/uni-uts-v1/src/stacktrace/js.ts diff --git a/packages/uni-app-harmony/dist/uni.runtime.esm.js b/packages/uni-app-harmony/dist/uni.runtime.esm.js index d349707ae7..7d7f8cbd94 100644 --- a/packages/uni-app-harmony/dist/uni.runtime.esm.js +++ b/packages/uni-app-harmony/dist/uni.runtime.esm.js @@ -1,6 +1,7 @@ import picker from '@ohos.file.picker'; import fs from '@ohos.file.fs'; import promptAction from '@ohos.promptAction'; +import { getCurrentInstance, onMounted, nextTick, onBeforeUnmount } from 'vue'; /** * @vue/shared v3.4.21 @@ -39,7 +40,26 @@ const capitalize = cacheStringFunction((str) => { }); const LINEFEED = '\n'; +const ON_READY = 'onReady'; +const ON_UNLOAD = 'onUnload'; +let lastLogTime = 0; +function formatLog(module, ...args) { + const now = Date.now(); + const diff = lastLogTime ? now - lastLogTime : 0; + lastLogTime = now; + return `[${now}][${diff}ms][${module}]:${args + .map((arg) => JSON.stringify(arg)) + .join(' ')}`; +} + +const invokeArrayFns = (fns, arg) => { + let ret; + for (let i = 0; i < fns.length; i++) { + ret = fns[i](arg); + } + return ret; +}; function once(fn, ctx = null) { let res; return ((...args) => { @@ -51,6 +71,86 @@ function once(fn, ctx = null) { }); } +class EventChannel { + id; + listener; + emitCache; + constructor(id, events) { + this.id = id; + this.listener = {}; + this.emitCache = []; + if (events) { + Object.keys(events).forEach((name) => { + this.on(name, events[name]); + }); + } + } + emit(eventName, ...args) { + const fns = this.listener[eventName]; + if (!fns) { + return this.emitCache.push({ + eventName, + args, + }); + } + fns.forEach((opt) => { + opt.fn.apply(opt.fn, args); + }); + this.listener[eventName] = fns.filter((opt) => opt.type !== 'once'); + } + on(eventName, fn) { + this._addListener(eventName, 'on', fn); + this._clearCache(eventName); + } + once(eventName, fn) { + this._addListener(eventName, 'once', fn); + this._clearCache(eventName); + } + off(eventName, fn) { + const fns = this.listener[eventName]; + if (!fns) { + return; + } + if (fn) { + for (let i = 0; i < fns.length;) { + if (fns[i].fn === fn) { + fns.splice(i, 1); + i--; + } + i++; + } + } + else { + delete this.listener[eventName]; + } + } + _clearCache(eventName) { + for (let index = 0; index < this.emitCache.length; index++) { + const cache = this.emitCache[index]; + const _name = eventName + ? cache.eventName === eventName + ? eventName + : null + : cache.eventName; + if (!_name) + continue; + const location = this.emit.apply(this, [_name, ...cache.args]); + if (typeof location === 'number') { + this.emitCache.pop(); + continue; + } + this.emitCache.splice(index, 1); + index--; + } + } + _addListener(eventName, type, fn) { + (this.listener[eventName] || (this.listener[eventName] = [])).push({ + fn, + type, + }); + } +} + const CHOOSE_SIZE_TYPES = ['original', 'compressed']; const CHOOSE_SOURCE_TYPES = ['album', 'camera']; function elemsInArray(strArr, optionalVal) { @@ -878,6 +978,55 @@ const initI18nChooseImageMsgsOnce = /*#__PURE__*/ once(() => { } }); +function getCurrentPage() { + const pages = getCurrentPages(); + const len = pages.length; + if (len) { + return pages[len - 1]; + } +} +function getCurrentPageVm() { + const page = getCurrentPage(); + if (page) { + return page.$vm; + } +} + +function invokeHook(vm, name, args) { + if (isString(vm)) { + args = name; + name = vm; + vm = getCurrentPageVm(); + } + else if (typeof vm === 'number') { + const page = getCurrentPages().find((page) => page.$page.id === vm); + if (page) { + vm = page.$vm; + } + else { + vm = getCurrentPageVm(); + } + } + if (!vm) { + return; + } + const hooks = vm.$[name]; + return hooks && invokeArrayFns(hooks, args); +} + +function initPageVm(pageVm, page) { + pageVm.route = page.route; + pageVm.$vm = pageVm; + pageVm.$page = page; + pageVm.$mpType = 'page'; + pageVm.$fontFamilySet = new Set(); + if (page.meta.isTabBar) { + pageVm.$.__isTabBar = true; + // TODO preload? 初始化时,状态肯定是激活 + pageVm.$.__isActive = true; + } +} + const API_CHOOSE_IMAGE = 'chooseImage'; const ChooseImageOptions = { formatArgs: { @@ -1031,6 +1180,90 @@ var uni$1 = { getSystemInfoSync: getSystemInfoSync }; -globalThis.uni = uni$1; +const pages = []; +function addCurrentPage(page) { + const $page = page.$page; + if (!$page.meta.isNVue) { + return pages.push(page); + } + // 开发阶段热刷新需要移除旧的相同 id 的 page + const index = pages.findIndex((p) => p.$page.id === page.$page.id); + if (index > -1) { + pages.splice(index, 1, page); + } + else { + pages.push(page); + } +} + +function setupPage(component) { + const oldSetup = component.setup; + component.inheritAttrs = false; // 禁止继承 __pageId 等属性,避免告警 + component.setup = (_, ctx) => { + const { attrs: { __pageId, __pagePath, __pageQuery, __pageInstance }, } = ctx; + if (('production' !== 'production')) { + console.log(formatLog(__pagePath, 'setup')); + } + const instance = getCurrentInstance(); + const pageVm = instance.proxy; + initPageVm(pageVm, __pageInstance); + addCurrentPage(initScope(__pageId, pageVm, __pageInstance)); + { + onMounted(() => { + nextTick(() => { + // onShow被延迟,故onReady也同时延迟 + invokeHook(pageVm, ON_READY); + }); + // TODO preloadSubPackages + }); + onBeforeUnmount(() => { + invokeHook(pageVm, ON_UNLOAD); + }); + } + if (oldSetup) { + return oldSetup(__pageQuery, ctx); + } + }; + return component; +} +function initScope(pageId, vm, pageInstance) { + { + const $getAppWebview = () => { + return plus.webview.getWebviewById(pageId + ''); + }; + vm.$getAppWebview = $getAppWebview; + vm.$.ctx.$scope = { + $getAppWebview, + }; + } + vm.getOpenerEventChannel = () => { + if (!pageInstance.eventChannel) { + pageInstance.eventChannel = new EventChannel(pageId); + } + return pageInstance.eventChannel; + }; + return vm; +} + +function isVuePageAsyncComponent(component) { + return isFunction(component); +} +const pagesMap = new Map(); +function definePage(pagePath, asyncComponent) { + pagesMap.set(pagePath, once(createFactory(asyncComponent))); +} +function createFactory(component) { + return () => { + if (isVuePageAsyncComponent(component)) { + return component().then((component) => setupPage(component)); + } + return setupPage(component); + }; +} + +var index = { + uni: uni$1, + __definePage: definePage, +}; -export { uni$1 as uni }; +export { index as default }; diff --git a/packages/uni-app-uts/src/plugins/ios/plugin.ts b/packages/uni-app-uts/src/plugins/ios/plugin.ts index f78d13a721..ea88fbceff 100644 --- a/packages/uni-app-uts/src/plugins/ios/plugin.ts +++ b/packages/uni-app-uts/src/plugins/ios/plugin.ts @@ -72,11 +72,16 @@ export function uniAppIOSPlugin(): UniVitePlugin { const appServiceMap = bundle[APP_SERVICE_FILENAME_MAP] if (appServiceMap && appServiceMap.type === 'asset') { fs.outputFileSync( - path.resolve( - process.env.UNI_OUTPUT_DIR, - '../.sourcemap/app-ios', - APP_SERVICE_FILENAME_MAP - ), + process.env.UNI_APP_X_CACHE_DIR + ? path.resolve( + process.env.UNI_APP_X_CACHE_DIR, + APP_SERVICE_FILENAME_MAP + ) + : path.resolve( + process.env.UNI_OUTPUT_DIR, + '../.sourcemap/app-ios', + APP_SERVICE_FILENAME_MAP + ), appServiceMap.source ) delete bundle[APP_SERVICE_FILENAME_MAP] diff --git a/packages/uni-h5/dist-x/uni-h5.cjs.js b/packages/uni-h5/dist-x/uni-h5.cjs.js index cc468f2d3c..0fc3c9e8a2 100644 --- a/packages/uni-h5/dist-x/uni-h5.cjs.js +++ b/packages/uni-h5/dist-x/uni-h5.cjs.js @@ -13457,6 +13457,17 @@ function createRightWindowTsx(rightWindow, layoutState, windowState) { }, windowState), null, 16)])], 12, ["data-show"]), [[vue.vShow, layoutState.showRightWindow || layoutState.apiShowRightWindow]]); } } +function updateBackgroundColorContent(backgroundColorContent) { + { + return; + } +} +function useBackgroundColorContent(pageMeta) { + function update() { + updateBackgroundColorContent(pageMeta.backgroundColorContent || ""); + } + vue.watchEffect(update); +} function usePageHeadTransparentBackgroundColor(backgroundColor) { const { r, g: g2, b } = hexToRgba(backgroundColor); return `rgba(${r},${g2},${b},0)`; @@ -13915,10 +13926,10 @@ const index = defineSystemComponent({ const pageMeta = providePageMeta(getStateId()); const navigationBar = pageMeta.navigationBar; const pageStyle = {}; - if (pageMeta.backgroundColorContent) { - pageStyle.backgroundColor = pageMeta.backgroundColorContent; - } useDocumentTitle(pageMeta); + { + useBackgroundColorContent(pageMeta); + } return () => vue.createVNode( "uni-page", { diff --git a/packages/uni-h5/dist-x/uni-h5.es.js b/packages/uni-h5/dist-x/uni-h5.es.js index 218d267aac..0c56229c45 100644 --- a/packages/uni-h5/dist-x/uni-h5.es.js +++ b/packages/uni-h5/dist-x/uni-h5.es.js @@ -26691,6 +26691,23 @@ const UniServiceJSBridge$1 = /* @__PURE__ */ extend(ServiceJSBridge, { UniViewJSBridge.subscribeHandler(event, args, pageId); } }); +function updateBackgroundColorContent(backgroundColorContent) { + if (backgroundColorContent) { + document.body.style.setProperty( + "--background-color-content", + backgroundColorContent + ); + } else { + document.body.style.removeProperty("--background-color-content"); + } +} +function useBackgroundColorContent(pageMeta) { + function update() { + updateBackgroundColorContent(pageMeta.backgroundColorContent || ""); + } + watchEffect(update); + onActivated(update); +} function usePageHeadTransparentBackgroundColor(backgroundColor) { const { r, g: g2, b } = hexToRgba(backgroundColor); return `rgba(${r},${g2},${b},0)`; @@ -27425,10 +27442,10 @@ const index = defineSystemComponent({ const pageMeta = providePageMeta(getStateId()); const navigationBar = pageMeta.navigationBar; const pageStyle = {}; - if (pageMeta.backgroundColorContent) { - pageStyle.backgroundColor = pageMeta.backgroundColorContent; - } useDocumentTitle(pageMeta); + { + useBackgroundColorContent(pageMeta); + } return () => createVNode( "uni-page", { diff --git a/packages/uni-uts-v1/__tests__/__snapshots__/stacktrace.runtime.spec.ts.snap b/packages/uni-uts-v1/__tests__/__snapshots__/stacktrace.runtime.spec.ts.snap index bb45a25241..7f0e66be6c 100644 --- a/packages/uni-uts-v1/__tests__/__snapshots__/stacktrace.runtime.spec.ts.snap +++ b/packages/uni-uts-v1/__tests__/__snapshots__/stacktrace.runtime.spec.ts.snap @@ -1,5 +1,28 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`uts:stacktrace:runtime parseUTSJavaScriptRuntimeStacktrace 1`] = ` +"error: ReferenceError:Can't find variable: a +at pages/index/index.uvue:3:8 +1 | ","\r\n\r\n","import App from './App.uvue'\r\n\r\nimport { createSSRApp } from 'vue'\n\r\nexport function createApp() {\r\n\tconst app = createSSRApp(App)\r\n\treturn {\r\n\t\tapp\r\n\t}\r\n}"],"names":["defineComponent","createSSRApp"],"mappings":";;;IACI,UAAU,CAAC,MAAA;QACP,GAAG,CAAC,OAAO,CAAC,KAAK,EAAC,6BAA6B,EAAC,CAAC,CAAA,CAAA;IACrD,CAAC,EAAE,IAAI,CAAA,CAAA;AACP,wBAAeA,mBAAA,CAAA;QACX,MAAM,GAAA;YACF,GAAG,CAAC,OAAO,CAAC,KAAK,EAAC,6BAA6B,EAAC,CAAC,CAAA,CAAA;SACrD;KACJ,CAAA;;;;;;;;;;;;;;ACNH,sBAAeA,mBAAA,CAAA;IACd,IAAA,QAAQ,EAAE,YAAA;YACT,GAAG,CAAC,OAAO,CAAC,KAAK,EAAC,eAAe,EAAC,YAAY,CAAA,CAAA;SAC9C;IACD,IAAA,MAAM,EAAE,YAAA;YACP,GAAG,CAAC,OAAO,CAAC,KAAK,EAAC,eAAe,EAAC,UAAU,CAAA,CAAA;SAC5C;IACD,IAAA,MAAM,EAAE,YAAA;YACP,GAAG,CAAC,OAAO,CAAC,KAAK,EAAC,gBAAgB,EAAC,UAAU,CAAA,CAAA;SAC7C;IAmBD,IAAA,MAAM,EAAE,YAAA;YACP,GAAG,CAAC,OAAO,CAAC,KAAK,EAAC,gBAAgB,EAAC,UAAU,CAAA,CAAA;SAC7C;KACF,CAAA;;;;;;IC9BS,MAAM,UAAU,GAAG,OAAO,UAAU,KAAK,WAAW,GAAG,QAAQ,CAAC,aAAa,CAAC,EAAE,GAAG,UAAU,CAAA;IAC7F,UAAU,CAAC,MAAM,GAAG,IAAI,CAAA;aAKlB,SAAS,GAAA;IACxB,IAAA,MAAM,GAAG,GAAGC,gBAAY,CAAC,GAAG,CAAC,CAAA;QAC7B,OAAO;YACN,GAAG;SACH,CAAA;IACF,CAAC;IACS,SAAS,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;;;;;;"} \ No newline at end of file diff --git a/packages/uni-uts-v1/__tests__/stacktrace.runtime.spec.ts b/packages/uni-uts-v1/__tests__/stacktrace.runtime.spec.ts index d0eb95f7b6..dead784f72 100644 --- a/packages/uni-uts-v1/__tests__/stacktrace.runtime.spec.ts +++ b/packages/uni-uts-v1/__tests__/stacktrace.runtime.spec.ts @@ -1,12 +1,13 @@ import path from 'path' import { parseUTSKotlinRuntimeStacktrace } from '../src/stacktrace/kotlin' +import { parseUTSJavaScriptRuntimeStacktrace } from '../src/stacktrace/js' describe('uts:stacktrace:runtime', () => { test('parseUTSKotlinRuntimeStacktrace', async () => { const cacheDir = path.resolve( __dirname, - 'examples/uni-app-x/unpackage/cache/.kotlin' + 'examples/uni-app-x/unpackage/cache/app-android' ) expect( parseUTSKotlinRuntimeStacktrace( @@ -76,4 +77,31 @@ at uni.UNIXXXXXXX.IndexKt.test(index.kt:40)`, ) ).toMatchSnapshot() }) + test('parseUTSJavaScriptRuntimeStacktrace', async () => { + const cacheDir = path.resolve( + __dirname, + 'examples/uni-app-x/unpackage/cache/app-ios' + ) + expect( + parseUTSJavaScriptRuntimeStacktrace( + `app-service.js(5:60) ReferenceError:Can't find variable: a @app-service.js:5:60`, + { + cacheDir, + } + ) + ).toMatchSnapshot() + expect( + parseUTSJavaScriptRuntimeStacktrace( + `at +Can't find variable: a +onLoad@app-service.js:9:64 +callWithErrorHandling@uni-app-x-framework.js:2279:23 +callWithAsyncErrorHandling@uni-app-x-framework.js:2286:38 +@uni-app-x-framework.js:4763:45`, + { + cacheDir, + } + ) + ).toMatchSnapshot() + }) }) diff --git a/packages/uni-uts-v1/src/stacktrace/js.ts b/packages/uni-uts-v1/src/stacktrace/js.ts new file mode 100644 index 0000000000..8b31b7c631 --- /dev/null +++ b/packages/uni-uts-v1/src/stacktrace/js.ts @@ -0,0 +1,157 @@ +import { originalPositionForSync } from '../sourceMap' +import { + COLORS, + type GenerateRuntimeCodeFrameOptions, + generateCodeFrame, + lineColumnToStartEnd, + resolveSourceMapDirByCacheDir, + resolveSourceMapFileBySourceFile, + splitRE, +} from './utils' + +interface GenerateJavaScriptRuntimeCodeFrameOptions + extends GenerateRuntimeCodeFrameOptions {} +const JS_ERROR_RE = /\(\d+:\d+\)\s(.*)\s@([^\s]+\.js)\:(\d+)\:(\d+)/ +const VUE_ERROR_RE = /@([^\s]+\.js)\:(\d+)\:(\d+)/ + +// app-service.js(4:56) ReferenceError:Can't find variable: a @app-service.js:4:56 +export function parseUTSJavaScriptRuntimeStacktrace( + stacktrace: string, + options: GenerateJavaScriptRuntimeCodeFrameOptions +) { + const res: string[] = [] + const lines = stacktrace.split(splitRE) + const sourceMapDir = resolveSourceMapDirByCacheDir(options.cacheDir) + for (let i = 0; i < lines.length; i++) { + const line = lines[i] + let codes = parseUTSJavaScriptRuntimeStacktraceJsErrorLine( + line, + sourceMapDir + ) + if (codes.length) { + const color = options.logType + ? COLORS[options.logType as string] || '' + : '' + const [errorCode, ...other] = codes + let error = 'error: ' + errorCode + if (color) { + error = color + error + color + } + return [error, ...other].join('\n') + } + codes = parseUTSJavaScriptRuntimeStacktraceVueErrorLine(line, sourceMapDir) + if (codes.length && res.length) { + const color = options.logType + ? COLORS[options.logType as string] || '' + : '' + let error = 'error: ' + res[0] + if (color) { + error = color + error + color + } + const [, ...other] = res + const otherCodes = other.map((item) => { + if (color) { + return color + item + color + } + return item + }) + return [error, ...otherCodes, ...codes].join('\n') + } + + res.push(line) + } + return '' +} + +// at +// Can't find variable: a +// onLoad@app-service.js:9:64 +// callWithErrorHandling@uni-app-x-framework.js:2279:23 +function parseUTSJavaScriptRuntimeStacktraceVueErrorLine( + lineStr: string, + sourceMapDir: string +) { + const lines: string[] = [] + const matches = lineStr.match(VUE_ERROR_RE) + if (!matches) { + return lines + } + const [, filename, line] = matches + const sourceMapFile = resolveSourceMapFileBySourceFile(filename, sourceMapDir) + if (!sourceMapFile) { + return lines + } + + const originalPosition = originalPositionForSync({ + sourceMapFile, + line: parseInt(line), + column: 0, + withSourceContent: true, + }) + if (originalPosition.source && originalPosition.sourceContent) { + lines.push( + `at ${originalPosition.source.split('?')[0]}:${originalPosition.line}:${ + originalPosition.column + }` + ) + if (originalPosition.line !== null && originalPosition.column !== null) { + const { start, end } = lineColumnToStartEnd( + originalPosition.sourceContent, + originalPosition.line, + originalPosition.column + ) + lines.push( + generateCodeFrame(originalPosition.sourceContent, start, end).replace( + /\t/g, + ' ' + ) + ) + } + } + return lines +} + +function parseUTSJavaScriptRuntimeStacktraceJsErrorLine( + lineStr: string, + sourceMapDir: string +) { + const lines: string[] = [] + const matches = lineStr.match(JS_ERROR_RE) + if (!matches) { + return lines + } + const [, error, filename, line] = matches + const sourceMapFile = resolveSourceMapFileBySourceFile(filename, sourceMapDir) + if (!sourceMapFile) { + return lines + } + + const originalPosition = originalPositionForSync({ + sourceMapFile, + line: parseInt(line), + column: 0, + withSourceContent: true, + }) + if (originalPosition.source && originalPosition.sourceContent) { + lines.push(error) + lines.push( + `at ${originalPosition.source.split('?')[0]}:${originalPosition.line}:${ + originalPosition.column + }` + ) + if (originalPosition.line !== null && originalPosition.column !== null) { + const { start, end } = lineColumnToStartEnd( + originalPosition.sourceContent, + originalPosition.line, + originalPosition.column + ) + lines.push( + generateCodeFrame(originalPosition.sourceContent, start, end).replace( + /\t/g, + ' ' + ) + ) + } + } + return lines +} diff --git a/packages/uni-uts-v1/src/stacktrace/kotlin.ts b/packages/uni-uts-v1/src/stacktrace/kotlin.ts index 363fd20d34..6800e72df9 100644 --- a/packages/uni-uts-v1/src/stacktrace/kotlin.ts +++ b/packages/uni-uts-v1/src/stacktrace/kotlin.ts @@ -2,7 +2,15 @@ import path from 'path' import fs from 'fs-extra' import { relative } from '../utils' import { originalPositionFor, originalPositionForSync } from '../sourceMap' -import { generateCodeFrame, lineColumnToStartEnd, splitRE } from './utils' +import { + COLORS, + type GenerateRuntimeCodeFrameOptions, + generateCodeFrame, + lineColumnToStartEnd, + resolveSourceMapDirByCacheDir, + resolveSourceMapFileBySourceFile, + splitRE, +} from './utils' export interface MessageSourceLocation { type: 'exception' | 'error' | 'warning' | 'info' | 'logging' | 'output' @@ -175,31 +183,14 @@ function parseFilenameByClassName(className: string) { return kotlinManifest.manifest[className.split('$')[0]] || 'index.kt' } -function resolveSourceMapFileByKtFile(file: string, sourceMapDir: string) { - const sourceMapFile = path.resolve(sourceMapDir, file + '.map') - if (fs.existsSync(sourceMapFile)) { - return sourceMapFile - } -} - -const COLORS: Record = { - warn: '\u200B', - error: '\u200C', -} - -interface GenerateRuntimeCodeFrameOptions { +interface GenerateKotlinRuntimeCodeFrameOptions + extends GenerateRuntimeCodeFrameOptions { appid: string - cacheDir: string - logType?: 'log' | 'info' | 'warn' | 'debug' | 'error' -} - -function resolveSourceMapDirByCacheDir(cacheDir: string) { - return path.resolve(cacheDir, 'sourceMap') } export function parseUTSKotlinRuntimeStacktrace( stacktrace: string, - options: GenerateRuntimeCodeFrameOptions + options: GenerateKotlinRuntimeCodeFrameOptions ) { const appid = normalizeAppid(options.appid || DEFAULT_APPID) if (!stacktrace.includes('uni.' + appid + '.')) { @@ -209,13 +200,10 @@ export function parseUTSKotlinRuntimeStacktrace( const re = createRegExp(appid) const res: string[] = [] const lines = stacktrace.split(splitRE) + const sourceMapDir = resolveSourceMapDirByCacheDir(options.cacheDir) for (let i = 0; i < lines.length; i++) { const line = lines[i] - const codes = parseUTSKotlinRuntimeStacktraceLine( - line, - re, - resolveSourceMapDirByCacheDir(options.cacheDir) - ) + const codes = parseUTSKotlinRuntimeStacktraceLine(line, re, sourceMapDir) if (codes.length && res.length) { const color = options.logType ? COLORS[options.logType as string] || '' @@ -245,7 +233,7 @@ function parseUTSKotlinRuntimeStacktraceLine( } const [, className, line] = matches - const sourceMapFile = resolveSourceMapFileByKtFile( + const sourceMapFile = resolveSourceMapFileBySourceFile( parseFilenameByClassName(className), sourceMapDir ) diff --git a/packages/uni-uts-v1/src/stacktrace/utils.ts b/packages/uni-uts-v1/src/stacktrace/utils.ts index 0d31e3ff4f..dec9803bca 100644 --- a/packages/uni-uts-v1/src/stacktrace/utils.ts +++ b/packages/uni-uts-v1/src/stacktrace/utils.ts @@ -1,5 +1,32 @@ +import fs from 'fs' +import path from 'path' + +export interface GenerateRuntimeCodeFrameOptions { + cacheDir: string + logType?: 'log' | 'info' | 'warn' | 'debug' | 'error' +} + +export const COLORS: Record = { + warn: '\u200B', + error: '\u200C', +} + export const splitRE = /\r?\n/ +export function resolveSourceMapDirByCacheDir(cacheDir: string) { + return path.resolve(cacheDir, 'sourcemap') +} + +export function resolveSourceMapFileBySourceFile( + file: string, + sourceMapDir: string +) { + const sourceMapFile = path.resolve(sourceMapDir, file + '.map') + if (fs.existsSync(sourceMapFile)) { + return sourceMapFile + } +} + const range: number = 2 function posToNumber( -- GitLab