core-utils
    Preparing search index...

    Module @clipboard-health/util-ts - v3.12.1

    @clipboard-health/util-ts

    TypeScript utilities.

    npm install @clipboard-health/util-ts
    

    See ./src/lib for each utility.

    import { deepEqual, strictEqual } from "node:assert/strict";

    import { ERROR_CODES, ServiceError } from "@clipboard-health/util-ts";
    import { z } from "zod";

    {
    const error = new ServiceError("boom");
    strictEqual(error.toString(), `ServiceError[${error.id}]: [internal]: boom`);
    }

    try {
    throw new Error("boom");
    } catch (error) {
    const serviceError = ServiceError.fromUnknown(error);
    strictEqual(serviceError.toString(), `ServiceError[${serviceError.id}]: [internal]: boom`);
    }

    {
    const serviceError = ServiceError.fromZodError(
    new z.ZodError([{ code: "custom", path: ["foo"], message: "boom" }]),
    );
    strictEqual(serviceError.toString(), `ServiceError[${serviceError.id}]: [badRequest]: boom`);
    }

    {
    const errorWithCause = new ServiceError({
    issues: [{ message: "boom" }],
    cause: new Error("Original error"),
    });
    strictEqual(errorWithCause.toString(), `ServiceError[${errorWithCause.id}]: [internal]: boom`);
    }

    {
    const multipleIssues = new ServiceError({
    issues: [
    {
    code: ERROR_CODES.badRequest,
    message: "Invalid email format",
    path: ["data", "attributes", "email"],
    },
    {
    code: ERROR_CODES.unprocessableEntity,
    message: "Phone number too short",
    path: ["data", "attributes", "phoneNumber"],
    },
    ],
    cause: new Error("Original error"),
    });

    strictEqual(
    multipleIssues.toString(),
    `ServiceError[${multipleIssues.id}]: [badRequest]: Invalid email format; [unprocessableEntity]: Phone number too short`,
    );

    deepEqual(multipleIssues.toJsonApi(), {
    errors: [
    {
    id: multipleIssues.id,
    status: "400",
    code: "badRequest",
    title: "Invalid or malformed request",
    detail: "Invalid email format",
    source: {
    pointer: "/data/attributes/email",
    },
    },
    {
    id: multipleIssues.id,
    status: "422",
    code: "unprocessableEntity",
    title: "Request failed validation",
    detail: "Phone number too short",
    source: {
    pointer: "/data/attributes/phoneNumber",
    },
    },
    ],
    });
    }
    import { ok } from "node:assert/strict";

    import {
    ERROR_CODES,
    failure,
    isFailure,
    isSuccess,
    type ServiceResult,
    success,
    } from "@clipboard-health/util-ts";

    function validateUser(params: { email: string; phone: string }): ServiceResult<{ id: string }> {
    const { email, phone } = params;
    const code = ERROR_CODES.unprocessableEntity;

    if (!email.includes("@")) {
    return failure({ issues: [{ code, message: "Invalid email format" }] });
    }

    if (phone.length !== 12) {
    return failure({ issues: [{ code, message: "Invalid phone number" }] });
    }

    return success({ id: "user-123" });
    }

    ok(isFailure(validateUser({ email: "invalidEmail", phone: "invalidPhoneNumber" })));
    ok(isSuccess(validateUser({ email: "user@example.com", phone: "555-555-5555" })));
    import { ok, strictEqual } from "node:assert/strict";

    import { isFailure, isSuccess, ServiceError, tryCatchAsync } from "@clipboard-health/util-ts";

    async function example() {
    const successResult = await tryCatchAsync(
    async () => {
    const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
    return (await response.json()) as { id: number };
    },
    (error) => new ServiceError(`Failed to fetch: ${String(error)}`),
    );

    ok(isSuccess(successResult));
    strictEqual(successResult.value.id, 1);

    const failureResult = await tryCatchAsync(
    async () => await Promise.reject(new Error("Network error")),
    (error) => new ServiceError(`Failed to fetch: ${String(error)}`),
    );

    ok(isFailure(failureResult));
    strictEqual(failureResult.error.issues[0]?.message, "Failed to fetch: Error: Network error");
    }

    // eslint-disable-next-line unicorn/prefer-top-level-await
    void example();
    import { ok, strictEqual } from "node:assert/strict";

    import { isFailure, isSuccess, parseJson, ServiceError, tryCatch } from "@clipboard-health/util-ts";

    const successResult = tryCatch(
    () => parseJson<{ name: string }>('{"name": "John"}'),
    (error) => new ServiceError(`Parse error: ${String(error)}`),
    );

    ok(isSuccess(successResult));
    strictEqual(successResult.value.name, "John");

    const failureResult = tryCatch(
    () => parseJson("invalid json"),
    (error) => new ServiceError(`Parse error: ${String(error)}`),
    );

    ok(isFailure(failureResult));
    ok(failureResult.error.issues[0]?.message?.includes("Parse error"));
    import { ok, strictEqual } from "node:assert/strict";

    import { fromSafeParseReturnType, isFailure, isSuccess } from "@clipboard-health/util-ts";
    import { z } from "zod";

    const schema = z.object({ name: z.string(), age: z.number() });

    const validData = { name: "John", age: 30 };
    const successResult = fromSafeParseReturnType(schema.safeParse(validData));

    ok(isSuccess(successResult));
    strictEqual(successResult.value.name, "John");

    const invalidData = { name: "John", age: "thirty" };
    const failureResult = fromSafeParseReturnType(schema.safeParse(invalidData));

    ok(isFailure(failureResult));
    ok(failureResult.error.issues.length > 0);
    import { strictEqual } from "node:assert/strict";

    import { pipe } from "@clipboard-health/util-ts";

    const result = pipe(
    " hello world ",
    (s) => s.trim(),
    (s) => s.split(" "),
    (array) => array.map((word) => word.charAt(0).toUpperCase() + word.slice(1)),
    (array) => array.join(" "),
    );

    strictEqual(result, "Hello World");
    import { strictEqual } from "node:assert/strict";

    import { option as O, pipe } from "@clipboard-health/util-ts";

    function double(n: number) {
    return n * 2;
    }

    function inverse(n: number): O.Option<number> {
    return n === 0 ? O.none : O.some(1 / n);
    }

    const result = pipe(
    O.some(5),
    O.map(double),
    O.flatMap(inverse),
    O.match(
    () => "No result",
    (n) => `Result is ${n}`,
    ),
    );

    strictEqual(result, "Result is 0.1");
    import { strictEqual } from "node:assert/strict";

    import { either as E, pipe } from "@clipboard-health/util-ts";

    function double(n: number): number {
    return n * 2;
    }

    function inverse(n: number): E.Either<string, number> {
    return n === 0 ? E.left("Division by zero") : E.right(1 / n);
    }

    const result = pipe(
    E.right(5),
    E.map(double),
    E.flatMap(inverse),
    E.match(
    (error) => `Error: ${error}`,
    (result) => `Result is ${result}`,
    ),
    );

    strictEqual(result, "Result is 0.1");

    See package.json scripts for a list of commands.

    Namespaces

    either
    option

    Classes

    CbhError
    ServiceError

    Interfaces

    CbhIssue
    Failure
    Issue
    Logger
    ServiceIssue
    Success

    Type Aliases

    CbhResponse
    ErrorCode
    ErrorSource
    ErrorStatusCode
    FailureResult
    LogFunction
    NonEmptyArray
    NullOrUndefined
    OneOrArray
    OneOrNonEmptyArray
    ServiceErrorParams
    ServiceResult
    SuccessResult

    Variables

    ERROR_CODES
    ERROR_STATUS_CODES

    Functions

    chunk
    deepFreeze
    failure
    forceCast
    fromSafeParseReturnType
    fromZodIssue
    isDefined
    isError
    isFailure
    isNil
    isNullOrUndefined
    isString
    isSuccess
    mapFailure
    nullToUndefined
    parseJson
    pipe
    stringify
    success
    toError
    toErrorCbhResponse
    toErrorMessage
    toLeft
    toNonEmptyArray
    toSuccessCbhResponse
    tryCatch
    tryCatchAsync