Created
January 3, 2020 17:51
-
-
Save alexsasharegan/557c897658175aaf11e0d4330478465e to your computer and use it in GitHub Desktop.
Wrap errors using a linked list. Error burritos 🌯
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class WrappedError<ErrKind = any> extends Error implements Iterable<WrappedError | ErrKind> { | |
previous: ErrKind | null = null; | |
guid: Guid; | |
constructor(message: string, previous?: ErrKind) { | |
super(message); | |
// We update the error's name to distinguish it from the base Error. | |
this.name = this.constructor.name; | |
this.guid = `<${this.name}:empty>`; | |
// We add our reference to the original error value (if provided). | |
if (previous != null) { | |
this.previous = previous; | |
} | |
} | |
/** | |
* Iterate through the error stack from head to tail (most recent to root error). | |
*/ | |
*[Symbol.iterator](): Iterator<WrappedError | ErrKind> { | |
let err: any = this; | |
for (; err instanceof WrappedError; err = err.previous) { | |
yield err; | |
} | |
if (err != null) { | |
yield err; | |
} | |
} | |
*messageValues(): IterableIterator<string> { | |
for (let error of this) { | |
if (error instanceof Error) { | |
yield error.message; | |
} else { | |
yield String(error); | |
} | |
} | |
} | |
/** | |
* The original error value. | |
*/ | |
get root(): WrappedError<null> | ErrKind { | |
// Base case, no child === this instance is root | |
if (this.previous == null) { | |
return this as any; | |
} | |
// When the child is another node, compute recursively | |
if (this.previous instanceof WrappedError) { | |
return this.previous.root; | |
} | |
// This instance wraps the original error | |
return this.previous; | |
} | |
/** | |
* An array of all the stringified, non-nullable errors. | |
*/ | |
get spans(): string[] { | |
return Array.from(this.messageValues()); | |
} | |
/** | |
* The unique identifier should use a short, randomly generated id string. | |
* Best practice is to prefix that id with a namespace and then a separator. | |
* Prefixes should follow this format: | |
* | |
* - Components: `<ComponentName>::$guid` | |
* - Classes: `Classname::$guid` | |
* - General file: `filename::$guid` | |
* - Special Cases: `STATIC_NAME::$guid` | |
*/ | |
setGuid(guid: Guid): this { | |
this.guid = guid; | |
return this; | |
} | |
static extractGuids(e: WrappedError) { | |
return Array.from(e, (value) => { | |
if (value instanceof WrappedError) { | |
return value.guid; | |
} | |
return "<empty>"; | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment