merge-error-cause
Advanced tools
| import setErrorClass from"set-error-class"; | ||
| export const mergeClass=function(parent,child,stackError){ | ||
| const constructorError=shouldMergeClass(parent)?child:parent; | ||
| const parentA=setErrorClass( | ||
| parent, | ||
| constructorError.constructor, | ||
| stackError.name); | ||
| fixName(parentA,constructorError); | ||
| return parentA; | ||
| }; | ||
| const shouldMergeClass=function({name,wrap}){ | ||
| return name==="Error"||wrap===true; | ||
| }; | ||
| const fixName=function(parent,constructorError){ | ||
| if(parent.name!==constructorError.name){ | ||
| parent.name=constructorError.name; | ||
| } | ||
| }; | ||
| //# sourceMappingURL=class.js.map |
@@ -14,3 +14,3 @@ import{setErrorProperty}from"./set.js"; | ||
| export const mergeAggregateCauses=function(parent,mergeErrorCause){ | ||
| export const mergeAggregateCauses=function(parent,recurse){ | ||
| if(parent.errors===undefined){ | ||
@@ -20,3 +20,5 @@ return; | ||
| const errors=parent.errors.map(mergeErrorCause); | ||
| const errors=parent.errors. | ||
| map((error)=>recurse(error).error). | ||
| filter(Boolean); | ||
| setErrorProperty(parent,"errors",errors); | ||
@@ -23,0 +25,0 @@ }; |
+20
-1
@@ -0,1 +1,18 @@ | ||
| import type setErrorProps from 'set-error-props' | ||
| type NormalizeError<ErrorArg> = ErrorArg extends Error ? ErrorArg : Error | ||
| type SetErrorProps<ErrorArg, Cause extends object> = ReturnType< | ||
| typeof setErrorProps<ErrorArg, Cause, { lowPriority: true }> | ||
| > | ||
| type MergeErrorCause<ErrorArg> = 'cause' extends keyof ErrorArg | ||
| ? Omit< | ||
| ErrorArg['cause'] extends object | ||
| ? SetErrorProps<NormalizeError<ErrorArg>, ErrorArg['cause']> | ||
| : NormalizeError<ErrorArg>, | ||
| 'cause' | ||
| > | ||
| : NormalizeError<ErrorArg> | ||
| /** | ||
@@ -42,2 +59,4 @@ * This merges | ||
| */ | ||
| export default function mergeErrorCause(error: unknown): Error | ||
| export default function mergeErrorCause<ErrorArg>( | ||
| error: ErrorArg, | ||
| ): MergeErrorCause<ErrorArg> |
+34
-20
| import normalizeException from"normalize-exception"; | ||
| import setErrorProps from"set-error-props"; | ||
| import{mergeAggregateCauses,mergeAggregateErrors}from"./aggregate.js"; | ||
| import{mergeClass}from"./class.js"; | ||
| import{mergeMessage}from"./message.js"; | ||
| import{copyProps}from"./props.js"; | ||
| import{mergePrototype}from"./prototype.js"; | ||
| import{getStackIndex,fixStack}from"./stack.js"; | ||
| import{getStack,hasStack,mergeStack}from"./stack.js"; | ||
@@ -13,4 +13,3 @@ | ||
| export default function mergeErrorCause(error){ | ||
| const stackIndex=getStackIndex(error); | ||
| return mergeError(error,stackIndex); | ||
| return mergeError(error,[]).error; | ||
| } | ||
@@ -23,6 +22,16 @@ | ||
| const mergeError=function(error,stackIndex){ | ||
| const parent=normalizeException(error); | ||
| mergeAggregateCauses(parent,mergeErrorCause); | ||
| return mergeCause(parent,stackIndex); | ||
| const mergeError=function(error,parents){ | ||
| if(parents.includes(error)){ | ||
| return{}; | ||
| } | ||
| const recurse=(innerError)=>mergeError(innerError,[...parents,error]); | ||
| const stack=getStack(error); | ||
| const errorA=normalizeException(error,{shallow:true}); | ||
| const parentHasStack=hasStack(errorA,stack); | ||
| mergeAggregateCauses(errorA,recurse); | ||
| const{parent:errorB,childHasStack}=mergeCause(errorA,recurse); | ||
| const errorHasStack=parentHasStack||childHasStack; | ||
| return{error:errorB,errorHasStack}; | ||
| }; | ||
@@ -32,21 +41,26 @@ | ||
| const mergeCause=function(parent,stackIndex){ | ||
| const mergeCause=function(parent,recurse){ | ||
| if(parent.cause===undefined){ | ||
| return parent; | ||
| return{parent,childHasStack:false}; | ||
| } | ||
| const child=mergeError(parent.cause,stackIndex-1); | ||
| const{error:child,errorHasStack:childHasStack}=recurse(parent.cause); | ||
| delete parent.cause; | ||
| mergeChild(parent,child,stackIndex); | ||
| return normalizeException(parent); | ||
| const parentA=mergeChild(parent,child,childHasStack); | ||
| return{parent:parentA,childHasStack}; | ||
| }; | ||
| const mergeChild=function(parent,child,stackIndex){ | ||
| mergeMessage(parent,child); | ||
| fixStack(parent,child,stackIndex); | ||
| mergeAggregateErrors(parent,child); | ||
| copyProps(parent,child); | ||
| mergePrototype(parent,child); | ||
| const mergeChild=function(parent,child,childHasStack){ | ||
| if(child===undefined){ | ||
| return parent; | ||
| } | ||
| const stackError=mergeStack(parent,child,childHasStack); | ||
| const parentA=mergeClass(parent,child,stackError); | ||
| const parentB=mergeMessage(parentA,child,stackError); | ||
| mergeAggregateErrors(parentB,child); | ||
| const parentC=setErrorProps(parentB,child,{lowPriority:true}); | ||
| return parentC; | ||
| }; | ||
| //# sourceMappingURL=main.js.map |
@@ -1,2 +0,2 @@ | ||
| import{setErrorProperty}from"./set.js"; | ||
| import setErrorMessage from"set-error-message"; | ||
@@ -12,5 +12,5 @@ | ||
| export const mergeMessage=function(parent,child){ | ||
| export const mergeMessage=function(parent,child,stackError){ | ||
| const message=getMessage(parent.message,child.message); | ||
| setErrorProperty(parent,"message",message); | ||
| return setErrorMessage(parent,message,stackError.message); | ||
| }; | ||
@@ -17,0 +17,0 @@ |
+9
-25
| import{setErrorProperty}from"./set.js"; | ||
| export const getStackIndex=function(error){ | ||
| const stackIndex=findStackIndex(error,0); | ||
| return stackIndex===undefined?0:stackIndex; | ||
| export const hasStack=function(error,stack){ | ||
| return getStack(error)===stack; | ||
| }; | ||
| const findStackIndex=function(error,index){ | ||
| if(!isObject(error)){ | ||
| return; | ||
| } | ||
| const childIndex=findStackIndex(error.cause,index+1); | ||
| if(childIndex!==undefined){ | ||
| return childIndex; | ||
| } | ||
| return hasValidStack(error)?index:undefined; | ||
| export const getStack=function(error){ | ||
| return typeof error==="object"&&error!==null?error.stack:undefined; | ||
| }; | ||
@@ -26,11 +17,4 @@ | ||
| const isObject=function(value){ | ||
| return typeof value==="object"&&value!==null; | ||
| }; | ||
| const hasValidStack=function({stack}){ | ||
| return typeof stack==="string"&&stack.includes(STACK_LINE_START); | ||
| }; | ||
| const STACK_LINE_START="at "; | ||
@@ -41,10 +25,10 @@ | ||
| export const mergeStack=function(parent,child,childHasStack){ | ||
| if(!childHasStack){ | ||
| return parent; | ||
| } | ||
| export const fixStack=function(parent,child,stackIndex){ | ||
| if(stackIndex>0){ | ||
| setErrorProperty(parent,"stack",child.stack); | ||
| } | ||
| return child; | ||
| }; | ||
| //# sourceMappingURL=stack.js.map |
+8
-5
| { | ||
| "name": "merge-error-cause", | ||
| "version": "2.0.0", | ||
| "version": "2.1.0", | ||
| "type": "module", | ||
@@ -33,3 +33,3 @@ "exports": "./build/src/main.js", | ||
| "error-reporting", | ||
| "error-type", | ||
| "error-classes", | ||
| "merge", | ||
@@ -50,7 +50,10 @@ "exceptions" | ||
| "dependencies": { | ||
| "normalize-exception": "^1.8.0" | ||
| "normalize-exception": "^2.5.1", | ||
| "set-error-class": "^1.0.1", | ||
| "set-error-message": "^1.1.0", | ||
| "set-error-props": "^1.1.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@ehmicky/dev-tasks": "^1.0.84", | ||
| "test-each": "^5.2.1" | ||
| "@ehmicky/dev-tasks": "^1.0.86", | ||
| "test-each": "^5.3.0" | ||
| }, | ||
@@ -57,0 +60,0 @@ "engines": { |
+18
-11
@@ -66,3 +66,3 @@ [](https://codecov.io/gh/ehmicky/merge-error-cause) | ||
| `error` `any`\ | ||
| `error` `Error | any`\ | ||
| _Return value_: `Error` | ||
@@ -111,3 +111,3 @@ | ||
| ) { | ||
| // So does checking for error type | ||
| // So does checking for error class | ||
| } | ||
@@ -267,5 +267,5 @@ } | ||
| ## Error type | ||
| ## Error class | ||
| The outer error type is used. | ||
| The outer error class is used. | ||
@@ -283,4 +283,4 @@ ```js | ||
| If the parent error type is `Error`, the child type is used instead. This allows | ||
| wrapping the error message or properties while keeping its type. | ||
| If the parent error class is `Error`, the child class is used instead. This | ||
| allows wrapping the error message or properties while keeping its class. | ||
@@ -296,3 +296,3 @@ ```js | ||
| `error.wrap: true` has the same effect, but works with any parent error type. | ||
| `error.wrap: true` has the same effect, but works with any parent error class. | ||
@@ -303,3 +303,3 @@ ```js | ||
| } catch (cause) { | ||
| const error = new AnyError('Could not create user.', { cause }) | ||
| const error = new UserError('Could not create user.', { cause }) | ||
| error.wrap = true | ||
@@ -367,5 +367,6 @@ console.log(mergeErrorCause(error) instanceof TypeError) // true | ||
| like it's 2022 🔮 | ||
| - [`create-error-types`](https://github.com/ehmicky/create-error-types): Create | ||
| multiple error types | ||
| - [`error-type`](https://github.com/ehmicky/error-type): Create one error type | ||
| - [`error-custom-classes`](https://github.com/ehmicky/error-custom-classes): | ||
| Create multiple error classes | ||
| - [`error-custom-class`](https://github.com/ehmicky/error-custom-class): Create | ||
| one error class | ||
| - [`error-serializer`](https://github.com/ehmicky/error-serializer): Convert | ||
@@ -375,2 +376,8 @@ errors to/from plain objects | ||
| Normalize exceptions/errors | ||
| - [`set-error-class`](https://github.com/ehmicky/set-error-class): Properly | ||
| update an error's class | ||
| - [`set-error-message`](https://github.com/ehmicky/set-error-message): Properly | ||
| update an error's message | ||
| - [`set-error-props`](https://github.com/ehmicky/set-error-props): Properly | ||
| update an error's properties | ||
| - [`error-cause-polyfill`](https://github.com/ehmicky/error-cause-polyfill): | ||
@@ -377,0 +384,0 @@ Polyfill `error.cause` |
| export const copyProps=function(parent,child){ | ||
| for(const propName of Reflect.ownKeys(child)){ | ||
| mergeProp(parent,child,propName); | ||
| } | ||
| }; | ||
| const mergeProp=function(parent,child,propName){ | ||
| if(propName in parent){ | ||
| return; | ||
| } | ||
| const descriptor=Object.getOwnPropertyDescriptor(child,propName); | ||
| if(descriptor!==undefined&&!CORE_ERROR_PROPS.has(propName)){ | ||
| Object.defineProperty(parent,propName,descriptor); | ||
| } | ||
| }; | ||
| const CORE_ERROR_PROPS=new Set([ | ||
| "name", | ||
| "message", | ||
| "stack", | ||
| "cause", | ||
| "errors"]); | ||
| //# sourceMappingURL=props.js.map |
| export const mergePrototype=function(parent,child){ | ||
| if(!shouldMergePrototype(parent)){ | ||
| return; | ||
| } | ||
| Object.setPrototypeOf(parent,Object.getPrototypeOf(child)); | ||
| fixPrototypeProps(parent,child); | ||
| }; | ||
| const shouldMergePrototype=function({name,wrap}){ | ||
| return name==="Error"||wrap===true; | ||
| }; | ||
| const fixPrototypeProps=function(parent,child){ | ||
| PROTOTYPE_PROPS.forEach((propName)=>{ | ||
| fixPrototypeProp(parent,child,propName); | ||
| }); | ||
| }; | ||
| const PROTOTYPE_PROPS=["constructor","name"]; | ||
| const fixPrototypeProp=function(parent,child,propName){ | ||
| if(parent[propName]!==child[propName]){ | ||
| parent[propName]=child[propName]; | ||
| } | ||
| }; | ||
| //# sourceMappingURL=prototype.js.map |
31725
1.94%409
1.74%4
300%10
-9.09%188
-4.08%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
Updated