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
JavaScript
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 }