UNPKG

hackmud-script-manager

Version:

Script manager for game hackmud, with minification, TypeScript support, and player script type definition generation.

71 lines (70 loc) 2.94 kB
import { readDirectoryWithStats } from "@samual/lib/readDirectoryWithStats" import { basename, resolve } from "path" async function generateTypeDeclaration(sourceDirectory, hackmudPath) { const users = new Set() if (hackmudPath) for (const { stats, name } of await readDirectoryWithStats(hackmudPath)) stats.isFile() && name.endsWith(".key") && users.add(basename(name, ".key")) const wildScripts = [], wildAnyScripts = [], allScripts = {}, allAnyScripts = {} await Promise.all( (await readDirectoryWithStats(sourceDirectory)) .filter(({ stats, name }) => !stats.isDirectory() || /^[a-z_][a-z\d_]{0,24}$/.test(name)) .map(async ({ stats, name }) => { if (stats.isFile()) name.endsWith(".ts") ? name.endsWith(".d.ts") || wildScripts.push(basename(name, ".ts")) : name.endsWith(".js") && wildAnyScripts.push(basename(name, ".js")) else if (stats.isDirectory()) { const scripts = [], anyScripts = [] allScripts[name] = scripts allAnyScripts[name] = anyScripts users.add(name) for (const child of await readDirectoryWithStats(resolve(sourceDirectory, name))) child.stats.isFile() && (child.name.endsWith(".ts") ? name.endsWith(".d.ts") || scripts.push(basename(child.name, ".ts")) : child.name.endsWith(".js") && anyScripts.push(basename(child.name, ".js"))) } }) ) let o = "" for (const script of wildScripts) o += `type $${script}$ = typeof import(${JSON.stringify(resolve(sourceDirectory, script))}).default\n` o += "\n" for (const user in allScripts) { const scripts = allScripts[user] for (const script of scripts) o += `type $${user}$${script}$ = typeof import(${JSON.stringify(resolve(sourceDirectory, user, script))}).default\n` } o += "\ntype ArrayRemoveFirst<A> = A extends [ infer FirstItem, ...infer Rest ] ? Rest : never\n\ntype Subscript<T extends (...args: any) => any> =\n\t(...args: ArrayRemoveFirst<Parameters<T>>) => ReturnType<T> | ScriptFailure\n\ntype WildFullsec = Record<string, () => ScriptFailure> & {\n" for (const script of wildScripts) o += `\t${script}: Subscript<$${script}$>\n` for (const script of wildAnyScripts) o += `\t${script}: (...args: any) => any\n` o += "}\n\ninterface PlayerFullsec {" let lastWasMultiLine = !0 for (const user of users) { const scripts = allScripts[user], anyScripts = allAnyScripts[user] if ((scripts && scripts.length) || (anyScripts && anyScripts.length)) { lastWasMultiLine = !0 o += `\n\t${user}: WildFullsec & {\n` if (scripts) for (const script of scripts) o += `\t\t${script}: Subscript<$${user}$${script}$>\n` if (anyScripts) for (const script of anyScripts) o += `\t\t${script}: (...args: any) => any\n` o += "\t}" } else { if (lastWasMultiLine) { o += "\n" lastWasMultiLine = !1 } o += `\t${user}: WildFullsec` } o += "\n" } o += "}\n" return o } export { generateTypeDeclaration }