|
1 | 1 | // SPDX-License-Identifier: GPL-3.0-or-later WITH EXCEPTIONS |
2 | 2 | // Copyright (c) 2025 James Prevett |
3 | 3 |
|
4 | | -import { omit } from 'utilium'; |
5 | | - |
6 | 4 | /** |
7 | 5 | * Standard POSIX error codes. |
8 | 6 | * @see https://en.wikipedia.org/wiki/Errno.h |
@@ -407,152 +405,19 @@ const errnoMessages = { |
407 | 405 | [Errno.EHWPOISON]: 'Memory page has hardware error', |
408 | 406 | } as const satisfies Record<Errno, string>; |
409 | 407 |
|
| 408 | +type ErrName<T extends Errno> = T extends (typeof Errno)[infer K extends keyof typeof Errno] ? K : keyof typeof Errno; |
| 409 | + |
| 410 | +export function errname<const T extends Errno>(err: T): ErrName<T> { |
| 411 | + return Errno[err] as ErrName<T>; |
| 412 | +} |
| 413 | + |
410 | 414 | type ErrnoMessage<T extends Errno | keyof typeof Errno> = (typeof errnoMessages)[T extends Errno |
411 | 415 | ? T |
412 | 416 | : T extends keyof typeof Errno |
413 | 417 | ? (typeof Errno)[T] |
414 | | - : '']; |
| 418 | + : string]; |
415 | 419 |
|
416 | 420 | export function strerror<const T extends Errno | keyof typeof Errno>(errno: T): ErrnoMessage<T> { |
417 | 421 | const _errno: Errno = typeof errno == 'string' ? Errno[errno] : errno; |
418 | 422 | return (_errno in errnoMessages ? errnoMessages[_errno] : '') as ErrnoMessage<T>; |
419 | 423 | } |
420 | | - |
421 | | -export interface ExceptionExtra { |
422 | | - path?: string; |
423 | | - dest?: string; |
424 | | - syscall?: string; |
425 | | - [k: string]: any; |
426 | | -} |
427 | | - |
428 | | -/** |
429 | | - * JSON representation of an error. |
430 | | - */ |
431 | | -export interface ExceptionJSON { |
432 | | - errno: Errno; |
433 | | - message: string; |
434 | | - code: keyof typeof Errno; |
435 | | - stack: string; |
436 | | - path?: string; |
437 | | - dest?: string; |
438 | | - syscall?: string; |
439 | | -} |
440 | | - |
441 | | -/** |
442 | | - * Set the message of an exception to the UV-style message. |
443 | | - */ |
444 | | -export function setUVMessage<T extends ExceptionJSON>(ex: T): T { |
445 | | - let message = `${ex.code}: ${errnoMessages[ex.errno]}, ${ex.syscall}`; |
446 | | - |
447 | | - if (ex.path) message += ` '${ex.path}'`; |
448 | | - if (ex.dest) message += ` -> '${ex.dest}'`; |
449 | | - if (ex.message && !ex.message.startsWith(errnoMessages[ex.errno])) message += ` (${ex.message})`; |
450 | | - |
451 | | - ex.message = message; |
452 | | - return ex; |
453 | | -} |
454 | | - |
455 | | -/** |
456 | | - * An error with additional information about what happened. |
457 | | - * |
458 | | - * @privateRemarks |
459 | | - * |
460 | | - * This is modeled after Node.js's `ErrnoException` and `UVException`. |
461 | | - * |
462 | | - * `Error.captureStackTrace` is used when available to hide irrelevant stack frames. |
463 | | - * This is being standardized, however it is not available in Deno and behind a flag in Firefox. |
464 | | - * See https://github.com/tc39/proposal-error-capturestacktrace for more details. |
465 | | - */ |
466 | | -export class Exception extends Error implements ExceptionJSON { |
467 | | - declare public stack: string; |
468 | | - |
469 | | - public code: keyof typeof Errno; |
470 | | - |
471 | | - public path?: string; |
472 | | - public dest?: string; |
473 | | - public syscall?: string; |
474 | | - |
475 | | - public constructor(errno: Errno, message: false, context: ExceptionExtra); |
476 | | - public constructor(errno: Errno, message?: string); |
477 | | - public constructor( |
478 | | - public errno: Errno, |
479 | | - message?: string | false, |
480 | | - ctx: ExceptionExtra = {} |
481 | | - ) { |
482 | | - const code = Errno[errno] as keyof typeof Errno; |
483 | | - |
484 | | - super(message || ''); |
485 | | - |
486 | | - this.code = code; |
487 | | - Object.assign(this, omit(ctx, 'message')); |
488 | | - if (!message) setUVMessage(this); |
489 | | - |
490 | | - Error.captureStackTrace?.(this, this.constructor); |
491 | | - } |
492 | | - |
493 | | - public toString(): string { |
494 | | - return this.message; |
495 | | - } |
496 | | - |
497 | | - public toJSON(): ExceptionJSON { |
498 | | - const json: ExceptionJSON = { |
499 | | - errno: this.errno, |
500 | | - code: this.code, |
501 | | - stack: this.stack, |
502 | | - message: this.message, |
503 | | - }; |
504 | | - |
505 | | - if (this.path) json.path = this.path; |
506 | | - if (this.dest) json.dest = this.dest; |
507 | | - if (this.syscall) json.syscall = this.syscall; |
508 | | - |
509 | | - return json; |
510 | | - } |
511 | | - |
512 | | - public static fromJSON(this: void, json: ExceptionJSON): Exception { |
513 | | - const err = json.syscall ? new Exception(json.errno, false, json) : new Exception(json.errno, json.message); |
514 | | - err.stack = json.stack; |
515 | | - return err; |
516 | | - } |
517 | | -} |
518 | | - |
519 | | -/** |
520 | | - * Shortcut for UV-style exceptions. |
521 | | - */ |
522 | | -export function UV(this: void, code: keyof typeof Errno, syscall: string, path?: string, dest?: string): Exception; |
523 | | -export function UV(this: void, code: keyof typeof Errno, context?: ExceptionExtra): Exception; |
524 | | -export function UV( |
525 | | - this: void, |
526 | | - code: keyof typeof Errno, |
527 | | - context?: ExceptionExtra | string, |
528 | | - path?: string, |
529 | | - dest?: string |
530 | | -): Exception { |
531 | | - if (typeof context === 'string') context = { syscall: context, path, dest }; |
532 | | - const err = new Exception(Errno[code], false, context ?? {}); |
533 | | - Error.captureStackTrace?.(err, UV); |
534 | | - return err; |
535 | | -} |
536 | | - |
537 | | -/** |
538 | | - * Shortcut to easily create an `Exception` with a specific error code. |
539 | | - */ |
540 | | -export function withErrno(this: void, code: keyof typeof Errno, message?: string): Exception { |
541 | | - const err = new Exception(Errno[code], message ?? errnoMessages[Errno[code]]); |
542 | | - Error.captureStackTrace?.(err, withErrno); |
543 | | - return err; |
544 | | -} |
545 | | - |
546 | | -export function rethrow(syscall: string, path?: string, dest?: string): (e: Exception) => never; |
547 | | -export function rethrow(extra: ExceptionExtra): (e: Exception) => never; |
548 | | -export function rethrow(extra: ExceptionExtra | string, path?: string, dest?: string): (e: Exception) => never { |
549 | | - const ctx = typeof extra === 'string' ? { syscall: extra } : extra; |
550 | | - if (path) ctx.path = path; |
551 | | - if (dest) ctx.dest = dest; |
552 | | - |
553 | | - return function (e: Exception) { |
554 | | - Object.assign(e, ctx); |
555 | | - setUVMessage(e); |
556 | | - throw e; |
557 | | - }; |
558 | | -} |
0 commit comments