/// namespace Leaf { export class ErrorDoc { private errorNames: string[] private errors: TErrors = {} as TErrors static create(): ErrorDoc { return new ErrorDoc() } static build(info: TErrors): { [K in keyof TErrors]: CustomErrorConstructor } { let result = {} for (let name in info) { result[name as string] = createError(name, Error, info[name] || {}) } return result as any } public define(name: string, base?: string | Error | Constructor, defaultProperty?: any) { let Base: Function = Error if (typeof base === "string") { let _ = this[base] if (typeof _ === "function") { Base = _ } } else if (typeof base === "function") { Base = base } else if (base) { console.warn("Unknown base error", base) } let E = createError(name, Base as Constructor, defaultProperty) this.errors[name] = E return this } public generate() { return this.errors } } export type Constructor = { new(...params: any[]): T } export function createError(name: string, Base?: Constructor, defaultProperty?: any) { return class E extends Base { constructor(message: string, detail: any) { super(message, detail) if (typeof message === "object") { if (!detail) { detail = message message = name } else { try { message = JSON.stringify(message, null, 4) } catch (e) { message = name + "Warning: recursive error property" + e.toString() } } } this.name = name this.message = message || name if (typeof defaultProperty === "function") { let _ = Base Base = defaultProperty defaultProperty = _ } if (!detail) detail = {} if (!defaultProperty) defaultProperty = {} for (let prop in defaultProperty) { this[prop] = defaultProperty[prop] } if (!this.detail) { this.detail = {} } for (let prop in detail) { this.detail[prop] = detail[prop] } for (let prop in detail) { this[prop] = detail[prop] } if (detail.via) { this.via = detail.via } this.toJSON = () => { let result = {} as any for (let prop in this) { if (this.hasOwnProperty(prop) && typeof this[prop] !== "function") { result[prop] = this[prop] } } if (this.message) { result["message"] = this.message } result["name"] = this.name return result } } message: string name: string detail: any = null via: Error = null toJSON: () => any = null } //let E = function (message: string, detail: any) { // if (typeof message === "object") { // if (!detail) { // detail = message // message = name // } else { // try { // message = JSON.stringify(message, null, 4) // } catch (e) { // message = name + "Warning: recursive error property" + e.toString() // } // } // } // this.name = name // this.message = message || name // if (typeof defaultProperty === "function") { // let _ = base // base = defaultProperty // defaultProperty = _ // } // if (!detail) detail = {} // if (!defaultProperty) defaultProperty = {} // for (let prop in defaultProperty) { // this[prop] = defaultProperty[prop] // } // if (!this.detail) { // this.detail = {} // } // for (let prop in detail) { // this.detail[prop] = detail[prop] // } // if (detail.via) { // this.via = detail.via // } //} } export type Partial = { [P in keyof T]?: T[P] } export interface CustomErrorConstructor { //new (message?: string, detail?: any): void new(message?: string, detail?: Partial & { via?: Error }): { detail: TDetail } & Error & { via: Error } } export const Errors = ErrorDoc.create() .define("Timeout") .define("Abort") .define("IOError") .define("NetworkError") .generate() as ErrorsOf<{ Timeout: {} Abort: {} IOError: {} NetworkError: { raw?: string } }> export type ErrorsOf = { [P in keyof T]?: CustomErrorConstructor; } }