sounisi5011/readme-generator

View on GitHub
src/utils/bent.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { inspect } from 'util';

import { indent, isObject } from '.';

function setProp(obj: unknown, propName: PropertyKey, value: unknown, enumerable = true): void {
    Object.defineProperty(obj, propName, {
        configurable: true,
        enumerable,
        writable: true,
        value,
    });
}

function tryParseJSON(text: string, callback: (value: ReturnType<typeof JSON.parse>) => void): void {
    try {
        callback(JSON.parse(text));
    } catch {
        //
    }
}

function isError(error: unknown, constructorName: string): error is Error & Record<PropertyKey, unknown> {
    return error instanceof Error && error.constructor.name === constructorName;
}

function genErrerMessage(
    {
        statusCode,
        headers,
        messageBodyStr,
    }: {
        statusCode: number;
        headers: Record<PropertyKey, unknown>;
        messageBodyStr: string;
    },
): string {
    return [
        `HTTP ${statusCode}`,
        indent([
            ...(
                Object.entries(headers)
                    .filter(([name]) => /^x-(?!(?:frame-options|content-type-options|xss-protection)$)/i.test(name))
                    .sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)
                    .map(([name, value]) => `${name}: ${String(value)}`)
            ),
            `body:`,
            indent(messageBodyStr),
        ]),
    ].join('\n');
}

export async function bentErrorFixer(error: unknown): Promise<never> {
    if (
        !(isError(error, 'StatusError')
            && typeof error.statusCode === 'number' && typeof error.text === 'function' && isObject(error.headers))
    ) {
        // eslint-disable-next-line @typescript-eslint/return-await
        return Promise.reject(error);
    }

    setProp(error, 'name', error.constructor.name, false);

    let messageBodyStr = await error.text();
    setProp(error, 'body', messageBodyStr);
    delete error.text;

    if (typeof error.arrayBuffer === 'function') delete error.arrayBuffer;
    if (typeof error.json === 'function') {
        tryParseJSON(messageBodyStr, value => {
            Object.defineProperty(error, 'body', { value });
            messageBodyStr = inspect(value);
        });
        delete error.json;
    }

    const { statusCode, headers } = error;
    setProp(error, 'message', genErrerMessage({ statusCode, headers, messageBodyStr }), false);

    return Promise.reject(error);
}