//// // Manages the commands on disk, in NOSE_ROOT_BIN and NOSE_BIN import { Glob } from "bun" import { watch } from "fs" import { join } from "path" import { isFile } from "./utils" import { sendAll } from "./websocket" import { expectDir } from "./utils" import { unique } from "./shared/utils" import { projectBin, projectName } from "./project" import { DEFAULT_PROJECT, NOSE_DIR, NOSE_ROOT_BIN, NOSE_BIN } from "./config" export function initCommands() { startWatchers() } export async function commands(project = DEFAULT_PROJECT): Promise { let cmds = (await findCommands(NOSE_BIN)) .concat(await findCommands(NOSE_ROOT_BIN)) if (project !== DEFAULT_PROJECT) cmds = cmds.concat(await findCommands(projectBin())) return unique(cmds).sort() } export async function findCommands(path: string): Promise { const glob = new Glob("**/*.{ts,tsx}") let list: string[] = [] for await (const file of glob.scan(path)) list.push(file.replace(".tsx", "").replace(".ts", "")) return list } export function commandPath(cmd: string): string | undefined { let paths = [ join(NOSE_BIN, cmd + ".ts"), join(NOSE_BIN, cmd + ".tsx"), join(NOSE_ROOT_BIN, cmd + ".ts"), join(NOSE_ROOT_BIN, cmd + ".tsx"), ] if (projectName() !== DEFAULT_PROJECT) paths = paths.concat( join(projectBin(), cmd + ".ts"), join(projectBin(), cmd + ".tsx"), ) return paths.find((path: string) => isFile(path)) } export function commandExists(cmd: string): boolean { return commandPath(cmd) !== undefined } export async function commandSource(name: string): Promise { const path = commandPath(name) if (!path) return "" return Bun.file(path).text() } export async function loadCommandModule(cmd: string) { const path = commandPath(cmd) if (!path) return return await import(path + "?t+" + Date.now()) } let noseDirWatcher let binCmdWatcher function startWatchers() { if (!expectDir(NOSE_BIN)) return if (!expectDir(NOSE_ROOT_BIN)) return binCmdWatcher = watch(NOSE_BIN, async (event, filename) => { sendAll({ type: "commands", data: await commands() }) }) noseDirWatcher = watch(NOSE_DIR, async (event, filename) => sendAll({ type: "commands", data: await commands() }) ) }