| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 | 'use strict'type PotentialError = Errlop | Error | ErrorCodeHolder | stringinterface ErrorCodeHolder {	exitCode?: string | number	errno?: string | number	code?: string | number}/** Only accept codes that are numbers, otherwise discard them */function parseCode(code: any): number | null {	const number = Number(code)	if (isNaN(number)) return null	return number}/** Fetch the code from the value */function fetchCode(value: any): string | number | null {	return (		value &&		(parseCode(value.exitCode) ||			parseCode(value.errno) ||			parseCode(value.code))	)}/** Prevent [a weird error on node version 4](https://github.com/bevry/errlop/issues/1) and below. */function isValid(value: any): boolean {	/* eslint no-use-before-define:0 */	return value instanceof Error || Errlop.isErrlop(value)}export default class Errlop extends Error {	/** Duck typing as node 4 and intanceof does not work for error extensions */	public klass: typeof Errlop	/**	 * The parent error if it was provided.	 * If a parent was provided, then use that, otherwise use the input's parent, if it exists.	 */	public parent?: Errlop | Error	/** An array of all the ancestors. From parent, to grand parent, and so on. */	public ancestors: Array<Errlop | Error>	/**	 * A numeric code to use for the exit status if desired by the consumer.	 * It cycles through [input, this, ...ancestors] until it finds the first [exitCode, errno, code] that is valid.	 */	public exitCode?: string | number	/**	 * The stack for our instance alone, without any parents.	 * If the input contained a stack, then use that.	 */	public orphanStack: string	/**	 * The stack which now contains the accumalated stacks of its ancestors.	 * This is used instead of an alias like `fullStack` or the like, to ensure existing code that uses `err.stack` doesn't need to be changed to remain functional.	 */	public stack: string	/**	 * Syntatic sugar for Errlop class creation.	 * Enables `Errlop.create(...args)` to achieve `new Errlop(...args)`	 */	static create(input: PotentialError, parent?: Errlop | Error): Errlop {		return new this(input, parent)	}	/**	 * Create an instance of an error, using a message, as well as an optional parent.	 * If the parent is provided, then the `fullStack` property will include its stack too	 */	constructor(input: PotentialError, parent?: Errlop | Error) {		if (!input) throw new Error('Attempted to create an Errlop without a input')		// Instantiate with the above		super((input as any).message || input)		// Apply		this.klass = Errlop		this.parent = parent || (input as Errlop).parent		this.ancestors = []		let ancestor = this.parent		while (ancestor) {			this.ancestors.push(ancestor)			ancestor = (ancestor as Errlop).parent		}		// this code must support node 0.8, as well as prevent a weird bug in node v4		// https://travis-ci.org/bevry/editions/jobs/408828147		let exitCode = fetchCode(input)		if (exitCode == null) exitCode = fetchCode(this)		for (			let index = 0;			index < this.ancestors.length && exitCode == null;			++index		) {			const error = this.ancestors[index]			if (isValid(error)) exitCode = fetchCode(error)		}		// Apply		if (exitCode != null) {			this.exitCode = exitCode		}		this.orphanStack = ((input as any).stack || (this as any).stack).toString()		this.stack = this.ancestors.reduce<string>(			(accumulator, error) =>				`${accumulator}\n↳ ${					(error as Errlop).orphanStack || (error as Error).stack || error				}`,			this.orphanStack		)	}	/** Check whether or not the value is an Errlop instance */	static isErrlop(value: any): boolean {		return value && (value instanceof this || value.klass === this)	}	/** Ensure that the value is an Errlop instance */	static ensure(value: any): Errlop {		return this.isErrlop(value) ? value : this.create(value)	}}
 |