ghom-eval
Version:
83 lines (82 loc) • 2.79 kB
JavaScript
import * as util from "util";
import typescript from "typescript";
// import React from "react"
// import ReactDOMServer from "react-dom/server"
const codeInBlock = /^```((?:js|ts)x?|typescript|javascript)?\s(.+[^\\])```$/is;
export async function evaluate(code, options) {
const input = code;
const result = codeInBlock.exec(code);
const lang = options?.lang || result?.[1] || "js";
const startedAt = Date.now();
let duration = 0;
let failed = false;
let out;
code = result ? result[2] : code.trim();
code = /^(?:return|throw|let|const|var)|\n|\b=\b/.test(code)
? code
: `return ${code}`;
code = `${code.includes("await") ? "async" : ""} (${options?.ctxName ?? "ctx"}${"" /*lang.endsWith("x") ? "" : ", React, ReactDOMServer"*/}) => {${code}}`.trim();
if (lang === "ts" ||
lang === "typescript" // ||
// lang === "tsx" ||
// lang === "jsx"
) {
const { outputText, diagnostics } = typescript.transpileModule(code, {
compilerOptions: {
// jsx: lang.endsWith("x") ? typescript.JsxEmit.React : undefined,
...options?.compilerOptions,
noEmit: true,
declaration: false,
},
});
code = outputText;
if (diagnostics && diagnostics.length > 0) {
const message = diagnostics
.map((diagnostic) => {
const { line, character } = diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start) || { line: 0, character: 0 };
return `${diagnostic.messageText} (${line + 1},${character + 1})`;
})
.join("\n");
out = new Error(`TypeScript compilation errors:\n${message}`);
failed = true;
}
}
if (!failed) {
try {
out = await eval(code)(options?.ctx /*, React, ReactDOMServer*/);
}
catch (err) {
out = err;
failed = true;
}
}
duration = Date.now() - startedAt;
const type = typeof out;
let _class = "void";
if (out !== undefined && out !== null) {
_class = out.constructor.name;
}
if (type === "object" && out !== null) {
out = util.inspect(out, options?.inspectOptions);
}
let formatted = code;
try {
const prettify = await import("ghom-prettify");
formatted = await prettify.format(code, {
lang: "js",
semi: false,
printWidth: 86,
...options?.prettierOptions,
});
}
catch { }
return {
class: _class,
type,
duration,
failed,
input,
output: `${out}`.length > 0 ? `${out}` : "void",
evaluated: formatted,
};
}