From 6e79ea023db477a2e4160b30c093136df6674704 Mon Sep 17 00:00:00 2001 From: Rafa Mel Date: Fri, 5 Jul 2024 17:20:00 +0200 Subject: [PATCH] feat: add atValue util to assist on new confirm, prompt, select api --- src/helpers/safe-serialize.ts | 38 +++++++++++++++++++++++++++++++++++ src/utils/at-value.ts | 20 ++++++++++++++++++ src/utils/index.ts | 1 + 3 files changed, 59 insertions(+) create mode 100644 src/helpers/safe-serialize.ts create mode 100644 src/utils/at-value.ts diff --git a/src/helpers/safe-serialize.ts b/src/helpers/safe-serialize.ts new file mode 100644 index 0000000..a173290 --- /dev/null +++ b/src/helpers/safe-serialize.ts @@ -0,0 +1,38 @@ +import { type Serial, TypeGuard } from 'type-core'; + +export function safeSerialize(value: any): string { + if (TypeGuard.isUndefined(value) || TypeGuard.isString(value)) { + return String(value); + } else { + return JSON.stringify(walk(value)); + } +} + +function walk(value: any): Serial.Type { + if ( + TypeGuard.isNullish(value) || + TypeGuard.isBoolean(value) || + TypeGuard.isString(value) || + TypeGuard.isNumber(value) + ) { + return value; + } + + if ( + TypeGuard.isArray(value) && + Object.getPrototypeOf(value) === Array.prototype + ) { + return value.map((item) => walk(item)); + } + + if ( + TypeGuard.isRecord(value) && + Object.getPrototypeOf(value) === Object.prototype + ) { + return Object.fromEntries( + Object.entries(value).map(([key, item]) => [key, walk(item)]) + ); + } + + throw new Error(`Non serializable value: ${value}`); +} diff --git a/src/utils/at-value.ts b/src/utils/at-value.ts new file mode 100644 index 0000000..fa7760c --- /dev/null +++ b/src/utils/at-value.ts @@ -0,0 +1,20 @@ +import type { Dictionary, Serial } from 'type-core'; + +import type { Task } from '../definitions'; +import { safeSerialize } from '../helpers/safe-serialize'; + +/** + * Takes a `tasks` record of `Task`s and returns a function + * that will return the `Task` of the record that matches the + * serialization of `value`; otherwise `null`. + * Particularly useful for stdio tasks such as + * confirm, prompt, and select. + */ +export function atValue( + tasks: Dictionary +): (value: Serial.Type) => Task | null { + return (value) => { + const field = safeSerialize(value); + return Object.hasOwnProperty.call(tasks, field) ? tasks[field] : null; + }; +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 88af284..64c4523 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,3 +1,4 @@ +export * from './at-value'; export * from './cancellation'; export * from './fetch'; export * from './is-ci';