Files
modeling-app/src/lib/trap.ts
Kurt Hutten Irev-Dev 1e9cf6f256 Revert "Revert multi-profile (#4812)"
This reverts commit efe8089b08.
2024-12-18 07:08:41 +11:00

104 lines
2.4 KiB
TypeScript

import toast from 'react-hot-toast'
type ExcludeErr<T> = Exclude<T, Error>
/**
* Similar to Error, but more lightweight, without the stack trace. It can also
* be used to represent a reason for not being able to provide an alternative,
* which isn't necessarily an error.
*/
export class Reason {
message: string
constructor(message: string) {
this.message = message
}
toError() {
return new Error(this.message)
}
}
/**
* This is intentionally *not* exported due to misuse. We'd like to add a lint.
*/
function isErr<T>(value: ExcludeErr<T> | Error): value is Error {
return value instanceof Error
}
// Used to bubble errors up
export function err<T>(value: ExcludeErr<T> | Error): value is Error {
if (!isErr(value)) {
return false
}
// TODO: Remove this once we have a lint to prevent misuse of this function.
console.error(value)
return true
}
/** Takes array of maybe error and types narrows them into
* @returns [hasErr, arrayWithoutErr, arrayWithErr]
*/
export function cleanErrs<T>(
value: Array<ExcludeErr<T> | Error>
): [boolean, Array<ExcludeErr<T>>, Array<Error>] {
const argsWOutErr: Array<ExcludeErr<T>> = []
const argsWErr: Array<Error> = []
for (const v of value) {
if (isErr(v)) {
argsWErr.push(v)
} else {
argsWOutErr.push(v)
}
}
return [argsWOutErr.length !== value.length, argsWOutErr, argsWErr]
}
export function report(
message: string,
{ showToast }: { showToast: boolean } = { showToast: false }
) {
console.error(message)
if (showToast) {
toast.error(message, { id: 'error' })
}
}
/**
* Report a promise rejection. The type of reason is `any` so that it matches
* Promise.prototype.catch.
*/
export function reportRejection(reason: any) {
report((reason ?? 'Unknown promise rejection').toString())
}
/**
* Report an error to the user. Trapping is the opposite of propagating an
* error. We should propagate errors in low-level functions and trap at the top
* level.
*/
export function trap<T>(
value: ExcludeErr<T> | Error,
opts?: {
altErr?: Error
suppress?: boolean
}
): value is Error {
if (!isErr(value)) {
return false
}
console.error(value)
opts?.suppress ||
toast.error((opts?.altErr ?? value ?? new Error('Unknown')).toString(), {
id: 'error',
})
return true
}
export function reject(errOrString: Error | string): Promise<never> {
return Promise.reject(errOrString)
}