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