From b8e445ddfe1c36216502844ffa3de0e820db90f8 Mon Sep 17 00:00:00 2001 From: Walter van der Giessen Date: Wed, 20 Dec 2023 21:05:22 +0100 Subject: [PATCH] Human readable error messages --- package-lock.json | 10 ++++---- package.json | 4 ++-- rollup.config.dev.js | 1 + rollup.config.js | 1 + src/lib/getErrorPreview.ts | 49 ++++++++++++++++++++++++++++++++++++++ src/lib/worker.worker.ts | 28 +++++++++++++++------- 6 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 src/lib/getErrorPreview.ts diff --git a/package-lock.json b/package-lock.json index 9bdbb1e..88d8fa4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "multithreading", - "version": "0.1.13", + "version": "0.1.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "multithreading", - "version": "0.1.13", + "version": "0.1.15", "license": "MIT", "devDependencies": { "@babel/plugin-transform-runtime": "^7.23.6", @@ -2615,9 +2615,9 @@ } }, "node_modules/@mdn/browser-compat-data": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.5.0.tgz", - "integrity": "sha512-H+jO7BSlQAf7W1md2+CcBeWGhfOpuYSOemm0cCU3ffyWEodOJLIODaYSe6+Y1hQ8JxprsoXHFwGau8Hzudd70A==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.5.1.tgz", + "integrity": "sha512-uKCxAlG5dqNEuCqGSAHa8cSFCZujnv0SRBOuMWMLiza4YK/eSiyNlMwXtWJSrRmeCT+33DBk1VUtAcZdSRdA+g==", "dev": true }, "node_modules/@pkgjs/parseargs": { diff --git a/package.json b/package.json index 325c478..2c8a813 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "multithreading", - "version": "0.1.15", - "description": "⚡ Multithreading functions in JavaScript, designed to be as simple and fast as possible.", + "version": "0.1.16", + "description": "⚡ Multithreading functions in JavaScript to speedup heavy workloads, designed to feel like writing vanilla functions.", "author": "Walter van der Giessen ", "homepage": "https://multithreading.io", "license": "MIT", diff --git a/rollup.config.dev.js b/rollup.config.dev.js index 9a51ecb..87dff32 100644 --- a/rollup.config.dev.js +++ b/rollup.config.dev.js @@ -15,6 +15,7 @@ export default ["cjs"].flatMap((type) => { replace({ __INLINE_WORKER__: fs .readFileSync(`.temp/worker.${type}${version}.js`, "utf8") + .replaceAll("\\", "\\\\") .replaceAll("`", "\\`") .replaceAll("$", "\\$"), }), diff --git a/rollup.config.js b/rollup.config.js index f5ae509..20996e9 100755 --- a/rollup.config.js +++ b/rollup.config.js @@ -33,6 +33,7 @@ export default ["esm", "cjs"].flatMap((type) => { replace({ __INLINE_WORKER__: fs .readFileSync(`.temp/worker.${type}${version}.js`, "utf8") + .replaceAll("\\", "\\\\") .replaceAll("`", "\\`") .replaceAll("$", "\\$"), }), diff --git a/src/lib/getErrorPreview.ts b/src/lib/getErrorPreview.ts new file mode 100644 index 0000000..0b42ec4 --- /dev/null +++ b/src/lib/getErrorPreview.ts @@ -0,0 +1,49 @@ +const colorRed = "\x1b[31m"; +const colorReset = "\x1b[39m"; + +export function getErrorPreview(error: Error) { + const [message, ...serializedStackFrames] = error.stack!.split("\n"); + + const stackFrame = decodeURIComponent(serializedStackFrames[0]); + + const [functionPart, ...otherParts] = stackFrame.split( + " (data:text/javascript;charset=utf-8," + ); + + const other = otherParts.join(); + const codeLines = other.split(/\r?\n/); + const lastLine = codeLines.pop()!; + + const [lineNumber, columnNumber] = lastLine + .slice(0, -1) + .split(":") + .slice(-2) + .map((n) => parseInt(n)); + + const amountOfPreviousLines = Math.min(3, lineNumber - 1); + const amountOfNextLines = 2; + + const previewLines = codeLines.slice( + lineNumber - (amountOfPreviousLines + 1), + lineNumber + amountOfNextLines + ); + + const previousLineLength = + codeLines[lineNumber - 1].trimEnd().length - columnNumber; + + previewLines.splice( + amountOfPreviousLines + 1, + 0, + colorRed + + " ".repeat(columnNumber - 1) + + "^".repeat(previousLineLength) + + " " + + message + + colorReset + ); + + const preview = + `${error.name} ${functionPart.trim()}:\n\n` + previewLines.join("\n"); + + return preview; +} diff --git a/src/lib/worker.worker.ts b/src/lib/worker.worker.ts index 75135e7..80748d9 100644 --- a/src/lib/worker.worker.ts +++ b/src/lib/worker.worker.ts @@ -11,6 +11,7 @@ import { ThreadEvent, } from "./types"; import { replaceContents } from "./replaceContents.ts"; +import { getErrorPreview } from "./getErrorPreview.ts"; declare var pid: number; @@ -35,12 +36,17 @@ globalThis.onmessage = async (e: MessageEvent) => { } }; -const cyanStart = "\x1b[36m"; -const cyanEnd = "\x1b[39m"; +const colorCyan = "\x1b[36m"; +const colorRed = "\x1b[31m"; +const colorReset = "\x1b[39m"; const originalLog = console.log; console.log = (...args) => { - originalLog(`${cyanStart}[Thread_${pid}]${cyanEnd}`, ...args); + originalLog(`${colorCyan}[Thread_${pid}]${colorReset}`, ...args); +}; +const originalError = console.error; +console.error = (...args) => { + originalError(`${colorRed}[Thread_${pid}]${colorReset}`, ...args); }; const $claim = async function $claim(value: Object) { @@ -125,11 +131,17 @@ namespace Thread { ): Promise { const gen = globalThis[GLOBAL_FUNCTION_NAME](...data[$.Args]); - hasYield && gen.next(); - const returnValue = await gen.next({ - $claim, - $unclaim, - }); + let returnValue = { value: undefined }; + + try { + hasYield && gen.next(); + returnValue = await gen.next({ + $claim, + $unclaim, + }); + } catch (error) { + console.error(getErrorPreview(error)); + } globalThis.postMessage({ [$.EventType]: $.Return,