diff --git a/repl.js b/repl.js index ab9cb30..faa222a 100644 --- a/repl.js +++ b/repl.js @@ -1 +1,118 @@ -// RIP +// In contrast to `node run `, this opens a shell-like +// environment that allows faster execution of code since it +// doesn't have to reload the plugin system. This is mostly +// done since Clover's primary dev-env is a Windows 7 laptop; +// It takes her machine 600ms to load the plugin file on it's own. +import process from "node:process"; +import * as util from "node:util"; +const exts = [".tsx", ".ts", ".js", ".marko"]; + +process.stderr.write("Loading..."); +const { hot } = await import("./run.js"); // get plugins ready +const { errorAllWidgets } = hot.load("@paperclover/console/Widget"); +process.stderr.write("\r" + " ".repeat("Loading...".length) + "\r"); +hot.load("node:repl").start({ + prompt: "% ", + eval(code, _global, _id, done) { + evaluate(code) + .catch((err) => { + // TODO: improve @paperclover/console's ability to print AggregateError + // and errors with extra random properties + console.error(inspect(err)); + }) + .then((result) => done(null, result)); + }, + ignoreUndefined: true, + //completer, +}); + +setTimeout(() => { + hot.reloadRecursive("./framework/engine/ssr.ts"); + hot.reloadRecursive("./framework/bundle.ts"); +}, 100); + +async function evaluate(code) { + code = code.trim(); + + if (code === "clear" || code === "cls") { + return console.clear(); + } + + if (code[0] === "=") { + try { + const result = await eval(code[1]); + console.log(inspect(result)); + } catch (err) { + if (err instanceof SyntaxError) { + const result = await eval("(async() => { return " + code + " })()"); + console.log(inspect(result)); + } else { + throw err; + } + } + } + + let split = code.split(/\s+/); + if (split.length === 0) return; + + // Shell commands + const cliPassthrough = [ + "deno", + "explorer", + "git", + "iexplore", + "node", + "npm", + "open", + "rg", + "start", + "vi", + ]; + if (cliPassthrough.includes(split[0]) || split[0].startsWith("$")) { + if (split[0].startsWith("$")) { + if ((split[0] = split[0].slice(1)).trim() === "") split.shift(); + } + if (process.platform === "win32" && split[0] === "open") split[0] = "start"; + if (split[0] === "explorer" || split[0] === "start") { + split[1] = split[1]?.replaceAll("/", "\\"); + } + try { + child_process.execSync(split.join(" "), { + stdio: "inherit", + env: { EDITOR: "vi", ...process.env }, + }); + } catch (err) { + const { status, signalCode } = err; + console.error( + `Exited with ${status ? "code " + status : "signal " + signalCode}`, + ); + } + return; + } + + let found; + for (const base of [".", "framework"]) { + for (const e of exts) { + const file = path.join(base, split[0] + e); + if (fs.existsSync(file)) { + found = file; + break; + } + } + } + + if (!found) { + console.error("\x1b[33mNo file matches: " + split[0] + "\x1b[0m"); + return; + } + + const m = hot.reloadRecursive(found); + await m.main?.(); + errorAllWidgets( + path.basename(found, path.extname(found)) + ".main() returning", + ); +} + +import * as fs from "node:fs"; +import * as path from "node:path"; +import * as child_process from "node:child_process";