import process from 'node:process'; import { IRuntime, ITestBase } from './types.ts'; import { noop } from './fns.ts'; import { SCROLL_ERR_FILE, SCROLL_LOG_FILE } from './config.ts'; export type { IFileIO, IRuntime, ITerminal } from './types.ts'; /** * Which Typescript runtime is currently being used */ export enum RunTimeType { Bun = 'bun', Deno = 'deno', Unknown = 'common', } export enum LogLevel { Debug = 'Debug', Info = 'Info', Notice = 'Notice', Warning = 'Warning', Error = 'Error', } let scrollRuntime: IRuntime | null = null; // ---------------------------------------------------------------------------- // Misc runtime functions // ---------------------------------------------------------------------------- export function log(s: unknown, level: LogLevel = LogLevel.Notice): void { getRuntime().then(({ file }) => { const raw = typeof s === 'string' ? s : JSON.stringify(s, null, 2); const output = `${level}: ${raw}\n`; const outputFile = (level === LogLevel.Error) ? SCROLL_ERR_FILE : SCROLL_LOG_FILE; file.appendFile(outputFile, output).then(noop); }); } /** * Append information to the scroll.err logfile */ export function logError(s: unknown): void { log(s, LogLevel.Error); } /** * Kill program, displaying an error message * @param s */ export function die(s: string | Error): void { logError(s); process.stdin.setRawMode(false); console.error(s); getRuntime().then((r) => r.exit()); } /** * Determine which Typescript runtime we are operating under */ export function runtimeType(): RunTimeType { let runtime = RunTimeType.Unknown; if ('Deno' in globalThis) { runtime = RunTimeType.Deno; } if ('Bun' in globalThis) { runtime = RunTimeType.Bun; } return runtime; } /** * Get the adapter object for the current Runtime */ export async function getRuntime(): Promise { if (scrollRuntime === null) { const runtime = runtimeType(); const path = `../${runtime}/mod.ts`; const pkg = await import(path); if ('default' in pkg) { scrollRuntime = pkg.default; } } return Promise.resolve(scrollRuntime!); } /** * Get the common test interface object */ export async function getTestRunner(): Promise { const runtime = runtimeType(); const path = `../${runtime}/test_base.ts`; const pkg = await import(path); if ('default' in pkg) { return pkg.default; } return pkg; } /** * Import a runtime-specific module * * e.g. to load "src/bun/mod.ts", if the runtime is bun, * you can use like so `await importForRuntime('index')`; * * @param path - the path within the runtime module */ export const importForRuntime = async (path: string) => { const runtime = runtimeType(); const suffix = '.ts'; const base = `../${runtime}/`; const pathParts = path .split('/') .filter((part) => part !== '' && part !== '.' && part !== suffix) .map((part) => part.replace(suffix, '')); const cleanedPath = pathParts.join('/'); const importPath = base + cleanedPath + suffix; const pkg = await import(importPath); if ('default' in pkg) { return pkg.default; } return pkg; };