All files / src withUse.ts

100% Statements 44/44
100% Branches 9/9
100% Functions 2/2
100% Lines 44/44

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 451x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 119x 119x 12x 12x 12x 10x 12x 8x 3x 3x 5x 5x 2x 2x 12x 119x 119x  
import type { Pipeable } from "./types";
 
/**
 * Adds a chainable `.use()` method to any object, enabling plugin-based transformations.
 *
 * The `.use()` method accepts a plugin function that receives the source object
 * and can return a transformed version. Supports several return patterns:
 *
 * - **Void/falsy**: Returns the original source unchanged (side-effect only plugins)
 * - **Object/function with `.use`**: Returns as-is (already chainable)
 * - **Object/function without `.use`**: Wraps with `withUse()` for continued chaining
 * - **Primitive**: Returns the value directly
 *
 * @template TSource - The type of the source object being enhanced
 * @param source - The object to add `.use()` method to
 * @returns The source object with `.use()` method attached
 *
 * @example
 * // Basic usage with atom tuple
 * const mappable = withUse([signal, setter]);
 * const transformed = mappable.use(([sig, set]) => ({
 *   sig,
 *   set: (v: string) => set(Number(v))
 * }));
 *
 */
export function withUse<TSource extends object>(source: TSource) {
  return Object.assign(source, {
    use<TNew = void>(plugin: (source: TSource) => TNew): any {
      const result = plugin(source);
      // Void/falsy: return original source (side-effect only plugins)
      if (!result) return source;
      // Object or function: check if already has .use(), otherwise wrap
      if (typeof result === "object" || typeof result === "function") {
        if ("use" in result) {
          return result;
        }
        return withUse(result);
      }
      // Primitive values: return directly (not chainable)
      return result;
    },
  }) as TSource & Pipeable;
}