import fs from 'fs'; import { Readable, Writable } from 'stream'; import { LogLevel, Logger } from '../Logger'; import { Err, Ok, Result, ResultPromise } from '../models/Result'; export type ContentFile = readonly [content: string, path: string]; export type StreamFile = readonly [stream: Readable, path: string]; export async function readFile(file: string): ResultPromise { try { return Ok(await fs.promises.readFile(file, 'utf-8')); } catch (err) { return Err(`failed to read file: ${err instanceof Error ? err.message : 'unknown error'}`); } } export function writeFile(path: string) { return async function writeFile(content: string) { try { await fs.promises.writeFile(path, content); return Ok(content); } catch (err) { return Err(`failed to write file: ${err instanceof Error ? err.message : 'unknown error'}`); } }; } export function createWriteStream(path: string) { try { return Ok(fs.createWriteStream(path)); } catch (err) { return Err(`failed to create write stream to file: ${err instanceof Error ? err.message : 'unknown error'}`); } } export function pipeStream(readable: Pick) { return function pipeStream(writable: Writable) { return readable.pipe(writable); }; } export async function writeStream(file: StreamFile) { const [stream, path] = file; try { const output = fs.createWriteStream(path); stream.pipe(output); return new Promise>((resolve) => { output.on('error', (err) => { resolve(Err(`failed to write file: ${err.message}`)); }); output.on('finish', () => resolve(Ok(file))); }); } catch (err) { return Err(`failed to write file: ${err instanceof Error ? err.message : 'unknown error'}`); } } export function parseJSON(content: string): Result { try { return Ok(JSON.parse(content)); } catch (err) { return Err(`failed to parse content: ${err instanceof Error ? err.message : 'unknown error'}`); } } export function pass(t: T): T { return t; } export function failIfEmpty(error: E) { return function failIfEmpty(t: T[]): Result { return t.length ? Ok(t) : Err(error); }; } export function map(fn: (t: T) => B) { return function map(t: T[]) { return t.map(fn); }; } export function mapAsync(fn: (t: T) => B | Promise) { return async function map(t: T[]) { return await Promise.all(t.map(fn)); }; } export function filter(fn: (t: T) => boolean) { return function filter(t: T[]) { return t.filter(fn); }; } export function filterAsync(fn: (t: T) => boolean | Promise) { return async function filterAsync(t: T[]) { const results = await Promise.all(t.map(async (v) => [v, await fn(v)] as const)); return results.filter((r) => r[1]).map((r) => r[0]); }; } export function log(logger: Logger, level: LogLevel) { return function log(message: string | ((t: T) => string)) { return inspect((t) => logger[level](typeof message === 'function' ? message(t) : message)); }; } export function inspect(fn: (t: T) => unknown) { return function inspect(t: T): T { fn(t); return t; }; } export function not(value: boolean) { return !value; }