nose-pluto/src/commands.ts
Chris Wanstrath 8a6e95a500 sys -> root
2025-10-02 11:11:56 -07:00

84 lines
2.2 KiB
TypeScript

////
// 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<string[]> {
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<string[]> {
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<string> {
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() })
)
}