|
1 | | -/* eslint-disable max-params */ |
| 1 | +import { getErrorMessage } from "@/common"; |
| 2 | +import { isError } from "@/remeda"; |
2 | 3 |
|
3 | | -import { stringify } from "@/common"; |
4 | | -import { isBigInt, isBoolean, isError, isNumber, isString, isSymbol } from "@/remeda"; |
5 | | - |
6 | | -const prepare = (message: string | undefined, contexts: string[], error: unknown) => { |
7 | | - let e: unknown; |
8 | | - let emsg: string; |
| 4 | +import type { Result } from "./result"; |
9 | 5 |
|
| 6 | +const prepare = (result: Result, msg?: string) => { |
10 | 7 | // 1. Determine error message and cause from the provided error |
11 | | - if (isError(error)) { |
12 | | - e = error; |
13 | | - emsg = error.message; |
14 | | - } else if ( |
15 | | - isString(error) || |
16 | | - isNumber(error) || |
17 | | - isBigInt(error) || |
18 | | - isBoolean(error) || |
19 | | - isSymbol(error) |
20 | | - ) { |
21 | | - emsg = error.toString(); |
22 | | - } else if (error === undefined) { |
23 | | - emsg = ""; |
24 | | - } else if (error === null) { |
25 | | - emsg = "null"; |
26 | | - } else { |
27 | | - emsg = stringify(error); |
28 | | - } |
| 8 | + const cause = result["error"]; |
| 9 | + const reason = cause === undefined ? "" : getErrorMessage(cause); |
29 | 10 |
|
30 | 11 | // 2. Concat error message to contexts as the innermost context |
31 | | - const ctxs = contexts.reverse().concat(emsg || []); |
| 12 | + const contexts = result["contexts"].reverse().concat(reason || []); |
32 | 13 |
|
33 | | - let msg = ""; |
| 14 | + let message = ""; |
34 | 15 | // 3. Use provided message as the main message if available |
35 | | - if (message) { |
36 | | - msg = message; |
| 16 | + if (msg) { |
| 17 | + message = msg; |
37 | 18 | } else { |
38 | 19 | // 4. Otherwise, use the first non-empty context as the main message |
39 | | - while (ctxs.length > 0) { |
| 20 | + while (contexts.length > 0) { |
40 | 21 | // 5. The main message is removed from contexts |
41 | | - msg = ctxs.shift()!; |
42 | | - if (msg) break; |
| 22 | + message = contexts.shift()!; |
| 23 | + if (message) break; |
43 | 24 | } |
44 | | - // 6. Them main message may still be empty, that's okay |
| 25 | + // 6. The main message may still be empty, that's okay |
45 | 26 | } |
46 | 27 |
|
47 | | - // 7. Format the display string |
48 | | - const ctx = ctxs.map((line, index) => ` ${index}: ${line}`).join("\n"); |
49 | | - const display = ` |
| 28 | + // 7. Format into a string with message and contexts |
| 29 | + const ctx = contexts.map((line, index) => ` ${index}: ${line}`).join("\n"); |
| 30 | + const formatted = ` |
50 | 31 | Message: |
51 | | - ${msg || "<empty message>"} |
52 | | -
|
| 32 | + ${message || "<empty message>"} |
53 | 33 | Context: |
54 | 34 | ${ctx.trim() || "<empty context>"} |
55 | 35 | `.trim(); |
56 | 36 |
|
57 | 37 | // 8. Prepare the error constructor options |
58 | | - const options: ErrorOptions | undefined = e ? { cause: e } : undefined; |
| 38 | + const options: ErrorOptions | undefined = isError(cause) ? { cause } : undefined; |
59 | 39 |
|
60 | | - return { message: msg, contexts: ctxs, error: e, display, options }; |
| 40 | + return { message, contexts, formatted, options }; |
61 | 41 | }; |
62 | 42 |
|
63 | 43 | export class ResultError extends Error { |
64 | | - static isResultError(value: unknown): value is ResultError { |
| 44 | + static is(value: unknown): value is ResultError { |
65 | 45 | return value instanceof ResultError; |
66 | 46 | } |
67 | 47 |
|
68 | | - #message: string; |
69 | | - #contexts: string[]; |
70 | | - #display: string; |
| 48 | + static fmt(result: Result, message?: string): string { |
| 49 | + return prepare(result, message).formatted; |
| 50 | + } |
| 51 | + |
| 52 | + #msg: string; |
| 53 | + #ctx: string[]; |
| 54 | + #formatted: string; |
71 | 55 |
|
72 | | - constructor( |
73 | | - message: string | undefined, |
74 | | - error: unknown, |
75 | | - contexts: string[], |
76 | | - caller: Function = ResultError, |
77 | | - ) { |
78 | | - const prepared = prepare(message, contexts, error); |
| 56 | + constructor(result: Result, message?: string, caller: Function = ResultError) { |
| 57 | + const prepared = prepare(result, message); |
79 | 58 |
|
80 | 59 | super( |
81 | 60 | ` |
82 | | -
|
83 | | -${prepared.display} |
84 | | -
|
| 61 | +-------------------- |
| 62 | +${prepared.formatted} |
85 | 63 | Stack trace:`, |
86 | 64 | prepared.options, |
87 | 65 | ); |
88 | 66 | Error.captureStackTrace(this, caller || this.constructor); |
89 | 67 |
|
90 | | - this.#message = prepared.message; |
91 | | - this.#contexts = prepared.contexts; |
92 | | - this.#display = prepared.display; |
| 68 | + this.#msg = prepared.message; |
| 69 | + this.#ctx = prepared.contexts; |
| 70 | + this.#formatted = prepared.formatted; |
93 | 71 | } |
94 | 72 |
|
95 | 73 | get msg(): string { |
96 | | - return this.#message; |
| 74 | + return this.#msg; |
97 | 75 | } |
98 | 76 |
|
99 | | - get ctx(): string[] { |
100 | | - return this.#contexts.slice(); |
| 77 | + get contexts(): string[] { |
| 78 | + return this.#ctx; |
101 | 79 | } |
102 | 80 |
|
103 | 81 | override toString(): string { |
104 | | - return this.#display; |
| 82 | + return this.#formatted; |
105 | 83 | } |
106 | 84 | } |
0 commit comments