From a396ab1c2bd95f652f2e55c75ce95ec8d19a87a2 Mon Sep 17 00:00:00 2001 From: Neko Date: Mon, 26 Jan 2026 23:03:21 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(utils):=20added=20errorCauseFr?= =?UTF-8?q?om,=20errorMessageFrom,=20errorNameFrom=20(#11864)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/utils/src/error.ts | 74 +++++++++++++++++++++++++++++++++++++ packages/utils/src/index.ts | 1 + 2 files changed, 75 insertions(+) create mode 100644 packages/utils/src/error.ts diff --git a/packages/utils/src/error.ts b/packages/utils/src/error.ts new file mode 100644 index 0000000000..e985100184 --- /dev/null +++ b/packages/utils/src/error.ts @@ -0,0 +1,74 @@ +// Source copied from: https://github.com/moeru-ai/std/blob/72279973ff997b65672a9c85555c3736554bd9b9/packages/std/src/error/index.ts#L41-L46 + +type Nullable = { + [P in keyof T]: null | T[P] +} + +/** + * ErrorLike utility interface for containing error-like objects. + */ +export type ErrorLike = Nullable>> & Pick & { cause?: C } + +export const isError = (err: null | undefined | unknown): err is Error => + err instanceof Error + +export const isErrorLike = (err: null | undefined | unknown): err is ErrorLike => { + // eslint-disable-next-line eqeqeq + if (err == null) + return false + + if (isError(err)) + return true + + if (typeof err !== 'object') + return false + + return 'name' in err && typeof err.name === 'string' && 'message' in err && typeof err.message === 'string' +} + +/** + * Error.name extractor. + * + * @param {Error} err + * @returns {string | undefined} + */ +export const errorNameFrom = (err: null | undefined | unknown): string | undefined => + isErrorLike(err) + ? err.name + : undefined + +/** + * Error.message extractor. + * + * @param {Error} err + * @returns {string | undefined} + */ +export const errorMessageFrom = (err: null | undefined | unknown): string | undefined => + isErrorLike(err) + ? err.message + : undefined + +/** + * Error.stack extractor. + * + * @param {Error} err + * @returns {string | undefined} + */ +export const errorStackFrom = (err: null | undefined | unknown): null | string | undefined => + isErrorLike(err) + ? err.stack ?? new Error(errorMessageFrom(err)).stack + : undefined + +/** + * Error.cause extractor. + * + * @param {Error} err + * @returns {unknown | undefined} + */ +export const errorCauseFrom = (err: null | undefined | unknown): C | undefined => { + // eslint-disable-next-line eqeqeq + if (!isErrorLike(err) || err.cause == null) + return undefined + + return err.cause as C | undefined +} diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 31b9113172..99d77a9153 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -3,6 +3,7 @@ export * from './chunkers' export * from './client/cookie'; export * from './detectChinese'; export * from './env'; +export * from './error'; export * from './folderStructure'; export * from './format'; export * from './imageToBase64';