hackmud-script-manager 0.19.0 → 0.19.1-4bde221

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,4 @@
1
1
  # Hackmud Script Manager
2
- ![Test](https://github.com/samualtnorman/hackmud-script-manager/workflows/Test/badge.svg)
3
-
4
2
  Command made for [hackmud-environment](https://github.com/samualtnorman/hackmud-environment), which is a scripting environment for hackmud with minification, autocompletes / intellisense, and TypeScript support.
5
3
 
6
4
  Install with `npm install hackmud-script-manager -g` to make the `hsm` command available everywhere.
package/bin/hsm.js CHANGED
@@ -1,2 +1,590 @@
1
1
  #!/usr/bin/env node
2
- import{DynamicMap as e}from"@samual/lib/DynamicMap";import{assert as t}from"@samual/lib/assert";import{countHackmudCharacters as n}from"@samual/lib/countHackmudCharacters";import{writeFilePersistent as a}from"@samual/lib/writeFilePersistent";import{readFile as s,writeFile as o,mkdir as i,rmdir as r}from"fs/promises";import{homedir as c}from"os";import{supportedExtensions as l}from"../constants.js";import{generateTypeDeclaration as f}from"../generateTypeDeclaration.js";import{pull as $}from"../pull.js";import{syncMacros as p}from"../syncMacros.js";import{resolve as m,extname as h,basename as u,dirname as g,relative as d}from"path";import"@samual/lib/copyFilePersistent";const y="0.19.0",b=m(c(),".config"),k=m(b,"hsm.json"),w=new Map,v=[],S=new e((e=>{let t=0;for(const n of e)t+=(t>>1)+t+"xi1_8ratvsw9hlbgm02y5zpdcn7uekof463qj".indexOf(n)+1;return[_,x,J,F,I,z][t%6](e)})),logNeedHackmudPathMessage=()=>console.error(D(`${W("You need to set hackmudPath in config before you can use this command")}\n\n${q("To fix this:")}\nOpen hackmud and run "${C("#dir")}"\nThis will open a file browser and print your hackmud user's script directory\nGo up 2 directories and then copy the path\nThen in a terminal run "${C("hsm")} ${I("config set")} ${E("hackmudPath")} ${z("<the path you copied>")}"`)),logHelp=()=>{const e="Push scripts from a directory to hackmud user's scripts directories",t="Watch a directory and push a script when modified",n="Minify a script file on the spot",a="Generate a type declaration file for a directory of scripts",s="Sync macros across all hackmud users",o="Retrieve a value from the config file",i="Assign a value to the config file",r="Remove a key and value from the config file",c="Pull a script a from a hackmud user's script directory",l="Skip minification to produce a readable script",f="Reduce character count further but lose function names in error call stacks",$="Force quine cheats even if the character count is higher";switch(console.log(R("Version")+D(": ")+E(y)),v[0]){case"config":switch(v[1]){case"get":console.log(`\n${_(o)}\n\n${q("Usage:")}\n${C("hsm")} ${I(`${v[0]} ${v[1]}`)} ${z("<key>")}`);break;case"set":console.log(`\n${_(i)}\n\n${q("Usage:")}\n${C("hsm")} ${I(`${v[0]} ${v[1]}`)} ${z("<key> <value>")}`);break;case"delete":console.log(`\n${_(r)}\n\n${q("Usage:")}\n${C("hsm")} ${I(`${v[0]} ${v[1]}`)} ${z("<key>")}`);break;default:console.log(D(`${R("Config path")}: ${E(k)}\n\n${_("Modify the config file")}\n\n${q("Usage:")}\n${C("hsm")} ${I(`${v[0]} get`)} ${z("<key>")}\n ${o}\n${C("hsm")} ${I(`${v[0]} set`)} ${z("<key> <value>")}\n ${i}\n${C("hsm")} ${I(`${v[0]} delete`)} ${z("<key>")}\n ${r}`))}break;case"push":console.log(D(`\n${_(e)}\n\n${q("Usage:")}\n${C("hsm")} ${I(v[0])} ${z("<directory> [<script user>.<script name>...]")}\n\n${q("Options:")}\n${R("--skip-minify")}\n ${l}\n${R("--mangle-names")}\n ${f}\n${R("--force-quine-cheats")}\n ${$}`));break;case"dev":case"watch":console.log(D(`${R("Aliases")}: ${E("watch, dev")}\n\n${_(t)}\n\n${q("Usage:")}\n${C("hsm")} ${I(v[0])} ${z("<directory> [<script user>.<script name>...]")}\n\n${q("Options:")}\n${R("--skip-minify")}\n ${l}\n${R("--mangle-names")}\n ${f}\n${R("--type-declaration-path")}=${z("<path>")}\n Path to generate a type declaration file for the scripts\n${R("--force-quine-cheats")}\n ${$}`));break;case"pull":console.log(D(`\n${_(c)}\n\n${q("Usage:")}\n${C("hsm")} ${I(v[0])} ${z("<script user>")}${E(".")}${z("<script name>")}`));break;case"minify":case"golf":console.log(D(`${R("Aliases")}: ${E("minify, golf")}\n\n${_(n)}\n\n${q("Usage:")}\n${C("hsm")} ${I(v[0])} ${z("<target> [output path]")}\n\n${q("Options:")}\n${R("--skip-minify")}\n ${l}\n${R("--mangle-names")}\n ${f}\n${R("--force-quine-cheats")}\n ${$}\n${R("--watch")}\n Watch for changes`));break;case"generate-type-declaration":case"gen-type-declaration":case"gen-dts":case"gen-types":console.log(D(`${R("Aliases")}: ${E("generate-type-declaration, gen-type-declaration, gen-types, gen-dts")}\n\n${_(a)}\n\n${q("Usage:")}\n${C("hsm")} ${I(v[0])} ${z("<directory> [output path]")}`));break;case"sync-macros":console.log(`\n${_(s)}`);break;default:console.log(D(`\n${_("Hackmud Script Manager")}\n\n${q("Commands:")}\n${I("push")}\n ${e}\n${I("watch")}, ${I("dev")}\n ${t}\n${I("minify")}, ${I("golf")}\n ${n}\n${I("generate-type-declaration")}, ${I("gen-type-declaration")}, ${I("gen-types")}, ${I("gen-dts")}\n ${a}\n${I("sync-macros")}\n ${s}\n${I("config")}\n Modify and view the config file\n${I("pull")}\n ${c}`))}},exploreObject=(e,t,n=!1)=>{for(const a of t)e=n?"object"==typeof e[a]?e[a]:e[a]={}:e?.[a];return e},logInfo=({file:e,users:t,minLength:n,error:a},s)=>{a?logError(`error "${T.bold(a.message)}" in ${T.bold(e)}`):console.log(`pushed ${T.bold(e)} to ${t.map((e=>T.bold(S.get(e)))).join(", ")} | ${T.bold(String(n))} chars | ${T.bold(`${m(s,t[0],"scripts",u(e,h(e)))}.js`)}`)},log=e=>{console.log(D(e))},logError=e=>{console.error(W(e)),process.exitCode=1};for(const e of process.argv.slice(2))if("-"==e[0]){const[t,n]=e.split("=");let a=n;if(a)if("true"==a)a=!0;else if("false"==a)a=!1;else{const e=Number(a);isFinite(e)&&(a=e)}else a=!0;if("-"==e[1])w.set(t.slice(2),a);else for(const e of t.slice(1))w.set(e,a)}else v.push(e);("v"==v[0]||"version"==v[0]||w.get("version")||w.get("v"))&&(console.log(y),process.exit());let P=!1;const j=s(k,{encoding:"utf-8"}).then((e=>{let t;try{t=JSON.parse(e)}catch{return log("Config file was corrupted, resetting"),{}}return t&&"object"==typeof t?("hackmudPath"in t&&"string"!=typeof t.hackmudPath&&(log('Property "hackmudPath" of config file was corrupted, removing'),delete t.hackmudPath),t):(log("Config file was corrupted, resetting"),{})}),(()=>(P=!0,{}))),N=import("../push.js"),O=import("../processScript/index.js"),M=import("../watch.js"),U=import("chokidar"),{default:T}=await import("chalk"),q=T.rgb(255,255,255),z=T.rgb(202,202,202),C=T.rgb(155,155,155),W=T.rgb(255,0,0),_=T.rgb(255,244,4),x=T.rgb(243,249,152),I=T.rgb(30,255,0),J=T.rgb(179,255,155),R=T.rgb(0,255,255),D=T.rgb(122,178,244),E=T.rgb(255,0,236),F=T.rgb(255,150,224);(w.get("help")||w.get("h"))&&(logHelp(),process.exit());let A=!0;switch(v[0]){case"push":{const{hackmudPath:e}=await j;if(!e){logNeedHackmudPathMessage();break}const t=v[1];if(!t){logError("Must provide the directory to push from\n"),logHelp();break}const n=v.slice(2);if(n.length){const e=n.find((e=>!/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(e)));if(e){logError(`Invalid script name: ${JSON.stringify(e)}\n`),logHelp();break}}else n.push("*.*");if(w.has("skip-minify")&&w.has("mangle-names")){logError(`Option ${R("--mangle-names")} is not compatible with ${R("--skip-minify")}\n`),logHelp();break}const a=w.get("skip-minify");let s;if(null!=a){if("boolean"!=typeof a){logError(`The value for ${R("--skip-minify")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}s=!a}const o=w.get("mangle-names");if(null!=o&&"boolean"!=typeof o){logError(`The value for ${R("--mangle-names")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}const i=w.get("force-quine-cheats");if(null!=i&&"boolean"!=typeof i){logError(`The value for ${R("--force-quine-cheats")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}const{push:r}=await N;(await r(t,e,{scripts:n,onPush:t=>logInfo(t,e),minify:s,mangleNames:o,forceQuineCheats:i})).length||logError("Could not find any scripts to push")}break;case"dev":case"watch":{const{hackmudPath:e}=await j;if(!e){logNeedHackmudPathMessage();break}const t=v[1];if(!t){logError("Must provide the directory to watch\n"),logHelp();break}const n=v.slice(2);if(n.length){const e=n.find((e=>!/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(e)));if(e){logError(`Invalid script name: ${JSON.stringify(e)}\n`),logHelp();break}}else n.push("*.*");if(w.has("skip-minify")&&w.has("mangle-names")){logError(`Option ${R("--mangle-names")} is not compatible with ${R("--skip-minify")}\n`),logHelp();break}const a=w.get("skip-minify");let s;if(null!=a){if("boolean"!=typeof a){logError(`The value for ${R("--skip-minify")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}s=!a}const o=w.get("mangle-names");if(null!=o&&"boolean"!=typeof o){logError(`The value for ${R("--mangle-names")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}const i=w.get("force-quine-cheats");if(null!=i&&"boolean"!=typeof i){logError(`The value for ${R("--force-quine-cheats")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}const{watch:r}=await M;r(t,e,{scripts:n,onPush:t=>logInfo(t,e),typeDeclarationPath:(w.get("type-declaration-path")||w.get("type-declaration")||w.get("dts")||w.get("gen-types"))?.toString(),minify:s,mangleNames:o,onReady:()=>log("Watching"),forceQuineCheats:i}),A=!1}break;case"pull":{const{hackmudPath:e}=await j;if(!e){logNeedHackmudPathMessage();break}const t=v[1];if(!t){logError("Must provide the script to pull\n"),logHelp();break}const n=v[2]||".";try{await $(n,e,t)}catch(e){console.error(e),logError(`Something went wrong, did you forget to ${C("#down")} the script?`)}}break;case"sync-macros":{const{hackmudPath:e}=await j;if(!e){logNeedHackmudPathMessage();break}const{macrosSynced:t,usersSynced:n}=await p(e);log(`Synced ${t} macros to ${n} users`)}break;case"generate-type-declaration":case"gen-type-declaration":case"gen-dts":case"gen-types":{const e=v[1];if(!e){logError("Must provide target directory\n"),logHelp();break}const n=m(e),a=v[2]||"./player.d.ts",s=await f(n,(await j).hackmudPath);let i=m(a);try{await o(i,s)}catch(e){if(t(e instanceof Error),"EISDIR"!=e.code)throw e;i=m(i,"player.d.ts"),await o(i,s)}log(`Wrote type declaration to ${T.bold(i)}`)}break;case"config":switch(v[1]){case"get":{const e=v[2];e?log(exploreObject(await j,e.split("."))):console.log(await j)}break;case"delete":{const e=v[2];if(!e){logError("Must provide a key to delete\n"),logHelp();break}const t=e.split("."),n=t.map((e=>/^[a-z_$][\w$]*$/i.test(e)?e:JSON.stringify(e))).join("."),a=t.pop(),s=await j;delete exploreObject(s,t)?.[a],log(`Removed ${E(n)} from config file`)}break;case"set":{const e=v[2],t=v[3];if(!e){logError("Must provide a key and value\n"),logHelp();break}const n=e.split("."),a=n.map((e=>/^[a-z_$][\w$]*$/i.test(e)?e:JSON.stringify(e))).join(".");if(!t){logError(`Must provide a value for the key ${a}\n`),logHelp();break}const s=n.pop(),l=await j;if(n.length||"hackmudPath"!=s){let e=l;for(const t of n)"object"==typeof e[t]||(e[t]={}),e=e[t];e[s]=t}else l.hackmudPath=m(t.startsWith("~/")?c()+t.slice(1):t);console.log(l),await(async e=>{const t=JSON.stringify(e,void 0,"\t");P&&log(`Creating config file at ${k}`),await o(k,t).catch((async e=>{switch(e.code){case"EISDIR":await r(k);break;case"ENOENT":await i(b);break;default:throw e}await o(k,t)}))})(l)}break;default:v[1]&&logError(`Unknown command: ${JSON.stringify(v[1])}\n`),logHelp()}break;case"help":case"h":logHelp();break;case"golf":case"minify":{const e=v[1];if(!e){logError("Must provide target\n"),logHelp();break}const t=h(e);if(!l.includes(t)){logError(`Unsupported file extension "${T.bold(t)}"\nSupported extensions are "${l.map((e=>T.bold(e))).join('", "')}"`);break}const{processScript:o}=await O,i=u(e,t),r=i.endsWith(".src"),c=r?i.slice(0,-4):i,f="scripts"==u(m(e,".."))&&"hackmud"==u(m(e,"../../.."))?u(m(e,"../..")):"UNKNOWN",$=!w.get("skip-minify");if(w.has("skip-minify")&&w.has("mangle-names")){logError(`Option ${R("--mangle-names")} would have no effect if minification is skipped\n`),logHelp();break}const p=w.get("mangle-names");if(null!=p&&"boolean"!=typeof p){logError(`The value for ${R("--mangle-names")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}const y=p,b=w.get("force-quine-cheats");if(null!=b&&"boolean"!=typeof b){logError(`the value for ${R("--force-quine-cheats")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}const k=b;let S=v[2]||m(g(e),r?`${c}.js`:".js"==t?`${i}.min.js`:`${i}.js`);const golfFile=()=>s(e,{encoding:"utf-8"}).then((async s=>{const i=performance.now(),{script:r,warnings:l}=await o(s,{minify:$,scriptUser:f,scriptName:c,filePath:e,mangleNames:y,forceQuineCheats:k}),p=performance.now()-i;for(const{message:e,line:t}of l)log(`Warning "${T.bold(e)}" on line ${T.bold(String(t))}`);await a(S,r).catch((async n=>{if(!v[2]||"EISDIR"!=n.code)throw n;S=m(S,`${u(e,t)}.js`),await a(S,r)})).then((()=>log(`Wrote ${T.bold(n(r))} chars to ${T.bold(d(".",S))} | took ${Math.round(100*p)/100}ms`)),(e=>logError(e.message)))}),(e=>logError(e.message)));if(w.get("watch")){const{watch:t}=await U;t(e,{awaitWriteFinish:{stabilityThreshold:100}}).on("ready",(()=>log(`Watching ${e}`))).on("change",golfFile),A=!1}else await golfFile()}break;default:v[0]&&logError(`Unknown command: ${JSON.stringify(v[0])}\n`),logHelp()}A&&process.exit();
2
+ import { Cache } from "@samual/lib/Cache"
3
+ import { assert } from "@samual/lib/assert"
4
+ import { countHackmudCharacters } from "@samual/lib/countHackmudCharacters"
5
+ import { writeFilePersistent } from "@samual/lib/writeFilePersistent"
6
+ import { readFile, writeFile, mkdir, rmdir } from "fs/promises"
7
+ import { homedir } from "os"
8
+ import { resolve, extname, basename, dirname, relative } from "path"
9
+ import { supportedExtensions } from "../constants.js"
10
+ import { generateTypeDeclaration } from "../generateTypeDeclaration.js"
11
+ import { pull } from "../pull.js"
12
+ import { syncMacros } from "../syncMacros.js"
13
+ import "@samual/lib/copyFilePersistent"
14
+ const configDirectoryPath = resolve(homedir(), ".config"),
15
+ configFilePath = resolve(configDirectoryPath, "hsm.json"),
16
+ options = new Map(),
17
+ commands = [],
18
+ userColours = new Cache(user => {
19
+ let hash = 0
20
+ for (const char of user) hash += (hash >> 1) + hash + "xi1_8ratvsw9hlbgm02y5zpdcn7uekof463qj".indexOf(char) + 1
21
+ return [colourJ, colourK, colourM, colourW, colourL, colourB][hash % 6](user)
22
+ }),
23
+ logNeedHackmudPathMessage = () =>
24
+ console.error(
25
+ colourS(
26
+ `${colourD("You need to set hackmudPath in config before you can use this command")}\n\n${colourA("To fix this:")}\nOpen hackmud and run "${colourC("#dir")}"\nThis will open a file browser and print your hackmud user's script directory\nGo up 2 directories and then copy the path\nThen in a terminal run "${colourC("hsm")} ${colourL("config set")} ${colourV("hackmudPath")} ${colourB("<the path you copied>")}"`
27
+ )
28
+ ),
29
+ logHelp = () => {
30
+ const pushCommandDescription = "Push scripts from a directory to hackmud user's scripts directories",
31
+ mangleNamesOptionDescription = "Reduce character count further but lose function names in error call stacks"
32
+ console.log(colourN("Version") + colourS(": ") + colourV("0.19.1-4bde221"))
33
+ switch (commands[0]) {
34
+ case "config":
35
+ switch (commands[1]) {
36
+ case "get":
37
+ console.log(
38
+ `\n${colourJ("Retrieve a value from the config file")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(`${commands[0]} ${commands[1]}`)} ${colourB("<key>")}`
39
+ )
40
+ break
41
+ case "set":
42
+ console.log(
43
+ `\n${colourJ("Assign a value to the config file")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(`${commands[0]} ${commands[1]}`)} ${colourB("<key> <value>")}`
44
+ )
45
+ break
46
+ case "delete":
47
+ console.log(
48
+ `\n${colourJ("Remove a key and value from the config file")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(`${commands[0]} ${commands[1]}`)} ${colourB("<key>")}`
49
+ )
50
+ break
51
+ default:
52
+ console.log(
53
+ colourS(
54
+ `${colourN("Config path")}: ${colourV(configFilePath)}\n\n${colourJ("Modify the config file")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(commands[0] + " get")} ${colourB("<key>")}\n Retrieve a value from the config file\n${colourC("hsm")} ${colourL(commands[0] + " set")} ${colourB("<key> <value>")}\n Assign a value to the config file\n${colourC("hsm")} ${colourL(commands[0] + " delete")} ${colourB("<key>")}\n Remove a key and value from the config file`
55
+ )
56
+ )
57
+ }
58
+ break
59
+ case "push":
60
+ console.log(
61
+ colourS(
62
+ `\n${colourJ(pushCommandDescription)}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourB("<directory> [<script user>.<script name>...]")}\n\n${colourA("Options:")}\n${colourN("--skip-minify")}\n Skip minification to produce a readable script\n${colourN("--mangle-names")}\n ${mangleNamesOptionDescription}\n${colourN("--force-quine-cheats")}\n Force quine cheats even if the character count is higher`
63
+ )
64
+ )
65
+ break
66
+ case "dev":
67
+ case "watch":
68
+ console.log(
69
+ colourS(
70
+ `${colourN("Aliases")}: ${colourV("watch, dev")}\n\n${colourJ("Watch a directory and push a script when modified")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourB("<directory> [<script user>.<script name>...]")}\n\n${colourA("Options:")}\n${colourN("--skip-minify")}\n Skip minification to produce a readable script\n${colourN("--mangle-names")}\n ${mangleNamesOptionDescription}\n${colourN("--type-declaration-path")}=${colourB("<path>")}\n Path to generate a type declaration file for the scripts\n${colourN("--force-quine-cheats")}\n Force quine cheats even if the character count is higher`
71
+ )
72
+ )
73
+ break
74
+ case "pull":
75
+ console.log(
76
+ colourS(
77
+ `\n${colourJ("Pull a script a from a hackmud user's script directory")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourB("<script user>")}${colourV(".")}${colourB("<script name>")}`
78
+ )
79
+ )
80
+ break
81
+ case "minify":
82
+ case "golf":
83
+ console.log(
84
+ colourS(
85
+ `${colourN("Aliases")}: ${colourV("minify, golf")}\n\n${colourJ("Minify a script file on the spot")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourB("<target> [output path]")}\n\n${colourA("Options:")}\n${colourN("--skip-minify")}\n Skip minification to produce a readable script\n${colourN("--mangle-names")}\n ${mangleNamesOptionDescription}\n${colourN("--force-quine-cheats")}\n Force quine cheats even if the character count is higher\n${colourN("--watch")}\n Watch for changes`
86
+ )
87
+ )
88
+ break
89
+ case "generate-type-declaration":
90
+ case "gen-type-declaration":
91
+ case "gen-dts":
92
+ case "gen-types":
93
+ console.log(
94
+ colourS(
95
+ `${colourN("Aliases")}: ${colourV("generate-type-declaration, gen-type-declaration, gen-types, gen-dts")}\n\n${colourJ("Generate a type declaration file for a directory of scripts")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourB("<directory> [output path]")}`
96
+ )
97
+ )
98
+ break
99
+ case "sync-macros":
100
+ console.log("\n" + colourJ("Sync macros across all hackmud users"))
101
+ break
102
+ default:
103
+ console.log(
104
+ colourS(
105
+ `\n${colourJ("Hackmud Script Manager")}\n\n${colourA("Commands:")}\n${colourL("push")}\n ${pushCommandDescription}\n${colourL("watch")}, ${colourL("dev")}\n Watch a directory and push a script when modified\n${colourL("minify")}, ${colourL("golf")}\n Minify a script file on the spot\n${colourL("generate-type-declaration")}, ${colourL("gen-type-declaration")}, ${colourL("gen-types")}, ${colourL("gen-dts")}\n Generate a type declaration file for a directory of scripts\n${colourL("sync-macros")}\n Sync macros across all hackmud users\n${colourL("config")}\n Modify and view the config file\n${colourL("pull")}\n Pull a script a from a hackmud user's script directory`
106
+ )
107
+ )
108
+ }
109
+ },
110
+ exploreObject = (object, keys, createPath = !1) => {
111
+ for (const key of keys)
112
+ object =
113
+ createPath ?
114
+ "object" == typeof object[key] ?
115
+ object[key]
116
+ : (object[key] = {})
117
+ : object?.[key]
118
+ return object
119
+ },
120
+ logInfo = ({ file, users, minLength, error }, hackmudPath) => {
121
+ error ?
122
+ logError(`error "${chalk.bold(error.message)}" in ${chalk.bold(file)}`)
123
+ : console.log(
124
+ `pushed ${chalk.bold(file)} to ${users.map(user => chalk.bold(userColours.get(user))).join(", ")} | ${chalk.bold(minLength + "")} chars | ${chalk.bold(resolve(hackmudPath, users[0], "scripts", basename(file, extname(file))) + ".js")}`
125
+ )
126
+ },
127
+ log = message => {
128
+ console.log(colourS(message))
129
+ },
130
+ logError = message => {
131
+ console.error(colourD(message))
132
+ process.exitCode = 1
133
+ }
134
+ for (const argument of process.argv.slice(2))
135
+ if ("-" == argument[0]) {
136
+ const [key, valueRaw] = argument.split("=")
137
+ let value = valueRaw
138
+ if (value)
139
+ if ("true" == value) value = !0
140
+ else if ("false" == value) value = !1
141
+ else {
142
+ const number = Number(value)
143
+ isFinite(number) && (value = number)
144
+ }
145
+ else value = !0
146
+ if ("-" == argument[1]) options.set(key.slice(2), value)
147
+ else for (const option of key.slice(1)) options.set(option, value)
148
+ } else commands.push(argument)
149
+ if ("v" == commands[0] || "version" == commands[0] || options.get("version") || options.get("v")) {
150
+ console.log("0.19.1-4bde221")
151
+ process.exit()
152
+ }
153
+ let configDidNotExist = !1
154
+ const configPromise = readFile(configFilePath, { encoding: "utf-8" }).then(
155
+ configFile => {
156
+ let temporaryConfig
157
+ try {
158
+ temporaryConfig = JSON.parse(configFile)
159
+ } catch {
160
+ log("Config file was corrupted, resetting")
161
+ return {}
162
+ }
163
+ if (!temporaryConfig || "object" != typeof temporaryConfig) {
164
+ log("Config file was corrupted, resetting")
165
+ return {}
166
+ }
167
+ if ("hackmudPath" in temporaryConfig && "string" != typeof temporaryConfig.hackmudPath) {
168
+ log('Property "hackmudPath" of config file was corrupted, removing')
169
+ delete temporaryConfig.hackmudPath
170
+ }
171
+ return temporaryConfig
172
+ },
173
+ () => {
174
+ configDidNotExist = !0
175
+ return {}
176
+ }
177
+ ),
178
+ pushModule = import("../push.js"),
179
+ processScriptModule = import("../processScript/index.js"),
180
+ watchModule = import("../watch.js"),
181
+ chokidarModule = import("chokidar"),
182
+ { default: chalk } = await import("chalk"),
183
+ colourA = chalk.rgb(255, 255, 255),
184
+ colourB = chalk.rgb(202, 202, 202),
185
+ colourC = chalk.rgb(155, 155, 155),
186
+ colourD = chalk.rgb(255, 0, 0),
187
+ colourJ = chalk.rgb(255, 244, 4),
188
+ colourK = chalk.rgb(243, 249, 152),
189
+ colourL = chalk.rgb(30, 255, 0),
190
+ colourM = chalk.rgb(179, 255, 155),
191
+ colourN = chalk.rgb(0, 255, 255),
192
+ colourS = chalk.rgb(122, 178, 244),
193
+ colourV = chalk.rgb(255, 0, 236),
194
+ colourW = chalk.rgb(255, 150, 224)
195
+ if (options.get("help") || options.get("h")) {
196
+ logHelp()
197
+ process.exit()
198
+ }
199
+ let autoExit = !0
200
+ switch (commands[0]) {
201
+ case "push":
202
+ {
203
+ const { hackmudPath } = await configPromise
204
+ if (!hackmudPath) {
205
+ logNeedHackmudPathMessage()
206
+ break
207
+ }
208
+ const sourcePath = commands[1]
209
+ if (!sourcePath) {
210
+ logError("Must provide the directory to push from\n")
211
+ logHelp()
212
+ break
213
+ }
214
+ const scripts = commands.slice(2)
215
+ if (scripts.length) {
216
+ const invalidScript = scripts.find(
217
+ script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script)
218
+ )
219
+ if (invalidScript) {
220
+ logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`)
221
+ logHelp()
222
+ break
223
+ }
224
+ } else scripts.push("*.*")
225
+ if (options.has("skip-minify") && options.has("mangle-names")) {
226
+ logError(`Option ${colourN("--mangle-names")} is not compatible with ${colourN("--skip-minify")}\n`)
227
+ logHelp()
228
+ break
229
+ }
230
+ const shouldSkipMinify = options.get("skip-minify")
231
+ let shouldMinify
232
+ if (null != shouldSkipMinify) {
233
+ if ("boolean" != typeof shouldSkipMinify) {
234
+ logError(
235
+ `The value for ${colourN("--skip-minify")} must be ${colourV("true")} or ${colourV("false")}\n`
236
+ )
237
+ logHelp()
238
+ break
239
+ }
240
+ shouldMinify = !shouldSkipMinify
241
+ }
242
+ const shouldMangleNames = options.get("mangle-names")
243
+ if (null != shouldMangleNames && "boolean" != typeof shouldMangleNames) {
244
+ logError(
245
+ `The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
246
+ )
247
+ logHelp()
248
+ break
249
+ }
250
+ const shouldforceQuineCheats = options.get("force-quine-cheats")
251
+ if (null != shouldforceQuineCheats && "boolean" != typeof shouldforceQuineCheats) {
252
+ logError(
253
+ `The value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
254
+ )
255
+ logHelp()
256
+ break
257
+ }
258
+ const { push } = await pushModule
259
+ ;(
260
+ await push(sourcePath, hackmudPath, {
261
+ scripts,
262
+ onPush: info => logInfo(info, hackmudPath),
263
+ minify: shouldMinify,
264
+ mangleNames: shouldMangleNames,
265
+ forceQuineCheats: shouldforceQuineCheats
266
+ })
267
+ ).length || logError("Could not find any scripts to push")
268
+ }
269
+ break
270
+ case "dev":
271
+ case "watch":
272
+ {
273
+ const { hackmudPath } = await configPromise
274
+ if (!hackmudPath) {
275
+ logNeedHackmudPathMessage()
276
+ break
277
+ }
278
+ const sourcePath = commands[1]
279
+ if (!sourcePath) {
280
+ logError("Must provide the directory to watch\n")
281
+ logHelp()
282
+ break
283
+ }
284
+ const scripts = commands.slice(2)
285
+ if (scripts.length) {
286
+ const invalidScript = scripts.find(
287
+ script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script)
288
+ )
289
+ if (invalidScript) {
290
+ logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`)
291
+ logHelp()
292
+ break
293
+ }
294
+ } else scripts.push("*.*")
295
+ if (options.has("skip-minify") && options.has("mangle-names")) {
296
+ logError(`Option ${colourN("--mangle-names")} is not compatible with ${colourN("--skip-minify")}\n`)
297
+ logHelp()
298
+ break
299
+ }
300
+ const shouldSkipMinify = options.get("skip-minify")
301
+ let shouldMinify
302
+ if (null != shouldSkipMinify) {
303
+ if ("boolean" != typeof shouldSkipMinify) {
304
+ logError(
305
+ `The value for ${colourN("--skip-minify")} must be ${colourV("true")} or ${colourV("false")}\n`
306
+ )
307
+ logHelp()
308
+ break
309
+ }
310
+ shouldMinify = !shouldSkipMinify
311
+ }
312
+ const shouldMangleNames = options.get("mangle-names")
313
+ if (null != shouldMangleNames && "boolean" != typeof shouldMangleNames) {
314
+ logError(
315
+ `The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
316
+ )
317
+ logHelp()
318
+ break
319
+ }
320
+ const shouldforceQuineCheats = options.get("force-quine-cheats")
321
+ if (null != shouldforceQuineCheats && "boolean" != typeof shouldforceQuineCheats) {
322
+ logError(
323
+ `The value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
324
+ )
325
+ logHelp()
326
+ break
327
+ }
328
+ const { watch } = await watchModule
329
+ watch(sourcePath, hackmudPath, {
330
+ scripts,
331
+ onPush: info => logInfo(info, hackmudPath),
332
+ typeDeclarationPath: (
333
+ options.get("type-declaration-path") ||
334
+ options.get("type-declaration") ||
335
+ options.get("dts") ||
336
+ options.get("gen-types")
337
+ )?.toString(),
338
+ minify: shouldMinify,
339
+ mangleNames: shouldMangleNames,
340
+ onReady: () => log("Watching"),
341
+ forceQuineCheats: shouldforceQuineCheats
342
+ })
343
+ autoExit = !1
344
+ }
345
+ break
346
+ case "pull":
347
+ {
348
+ const { hackmudPath } = await configPromise
349
+ if (!hackmudPath) {
350
+ logNeedHackmudPathMessage()
351
+ break
352
+ }
353
+ const script = commands[1]
354
+ if (!script) {
355
+ logError("Must provide the script to pull\n")
356
+ logHelp()
357
+ break
358
+ }
359
+ const sourcePath = commands[2] || "."
360
+ try {
361
+ await pull(sourcePath, hackmudPath, script)
362
+ } catch (error) {
363
+ console.error(error)
364
+ logError(`Something went wrong, did you forget to ${colourC("#down")} the script?`)
365
+ }
366
+ }
367
+ break
368
+ case "sync-macros":
369
+ {
370
+ const { hackmudPath } = await configPromise
371
+ if (!hackmudPath) {
372
+ logNeedHackmudPathMessage()
373
+ break
374
+ }
375
+ const { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
376
+ log(`Synced ${macrosSynced} macros to ${usersSynced} users`)
377
+ }
378
+ break
379
+ case "generate-type-declaration":
380
+ case "gen-type-declaration":
381
+ case "gen-dts":
382
+ case "gen-types":
383
+ {
384
+ const target = commands[1]
385
+ if (!target) {
386
+ logError("Must provide target directory\n")
387
+ logHelp()
388
+ break
389
+ }
390
+ const sourcePath = resolve(target),
391
+ outputPath = commands[2] || "./player.d.ts",
392
+ typeDeclaration = await generateTypeDeclaration(sourcePath, (await configPromise).hackmudPath)
393
+ let typeDeclarationPath = resolve(outputPath)
394
+ try {
395
+ await writeFile(typeDeclarationPath, typeDeclaration)
396
+ } catch (error) {
397
+ assert(error instanceof Error)
398
+ if ("EISDIR" != error.code) throw error
399
+ typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
400
+ await writeFile(typeDeclarationPath, typeDeclaration)
401
+ }
402
+ log("Wrote type declaration to " + chalk.bold(typeDeclarationPath))
403
+ }
404
+ break
405
+ case "config":
406
+ switch (commands[1]) {
407
+ case "get":
408
+ {
409
+ const key = commands[2]
410
+ key ? log(exploreObject(await configPromise, key.split("."))) : console.log(await configPromise)
411
+ }
412
+ break
413
+ case "delete":
414
+ {
415
+ const key = commands[2]
416
+ if (!key) {
417
+ logError("Must provide a key to delete\n")
418
+ logHelp()
419
+ break
420
+ }
421
+ const keyParts = key.split("."),
422
+ pathName = keyParts
423
+ .map(name => (/^[a-z_$][\w$]*$/i.test(name) ? name : JSON.stringify(name)))
424
+ .join("."),
425
+ lastKey = keyParts.pop(),
426
+ config = await configPromise
427
+ delete exploreObject(config, keyParts)?.[lastKey]
428
+ log(`Removed ${colourV(pathName)} from config file`)
429
+ }
430
+ break
431
+ case "set":
432
+ {
433
+ const key = commands[2],
434
+ value = commands[3]
435
+ if (!key) {
436
+ logError("Must provide a key and value\n")
437
+ logHelp()
438
+ break
439
+ }
440
+ const keys = key.split("."),
441
+ pathName = keys
442
+ .map(name => (/^[a-z_$][\w$]*$/i.test(name) ? name : JSON.stringify(name)))
443
+ .join(".")
444
+ if (!value) {
445
+ logError(`Must provide a value for the key ${pathName}\n`)
446
+ logHelp()
447
+ break
448
+ }
449
+ const lastKey = keys.pop(),
450
+ config = await configPromise
451
+ if (keys.length || "hackmudPath" != lastKey) {
452
+ let object = config
453
+ for (const key of keys)
454
+ if ("object" == typeof object[key]) object = object[key]
455
+ else {
456
+ object[key] = {}
457
+ object = object[key]
458
+ }
459
+ object[lastKey] = value
460
+ } else config.hackmudPath = resolve(value.startsWith("~/") ? homedir() + value.slice(1) : value)
461
+ console.log(config)
462
+ await (async config => {
463
+ const json = JSON.stringify(config, void 0, "\t")
464
+ configDidNotExist && log("Creating config file at " + configFilePath)
465
+ await writeFile(configFilePath, json).catch(async error => {
466
+ switch (error.code) {
467
+ case "EISDIR":
468
+ await rmdir(configFilePath)
469
+ break
470
+ case "ENOENT":
471
+ await mkdir(configDirectoryPath)
472
+ break
473
+ default:
474
+ throw error
475
+ }
476
+ await writeFile(configFilePath, json)
477
+ })
478
+ })(config)
479
+ }
480
+ break
481
+ default:
482
+ commands[1] && logError(`Unknown command: ${JSON.stringify(commands[1])}\n`)
483
+ logHelp()
484
+ }
485
+ break
486
+ case "help":
487
+ case "h":
488
+ logHelp()
489
+ break
490
+ case "golf":
491
+ case "minify":
492
+ {
493
+ const target = commands[1]
494
+ if (!target) {
495
+ logError("Must provide target\n")
496
+ logHelp()
497
+ break
498
+ }
499
+ const fileExtension = extname(target)
500
+ if (!supportedExtensions.includes(fileExtension)) {
501
+ logError(
502
+ `Unsupported file extension "${chalk.bold(fileExtension)}"\nSupported extensions are "${supportedExtensions.map(extension => chalk.bold(extension)).join('", "')}"`
503
+ )
504
+ break
505
+ }
506
+ const { processScript } = await processScriptModule,
507
+ fileBaseName = basename(target, fileExtension),
508
+ fileBaseNameEndsWithDotSrc = fileBaseName.endsWith(".src"),
509
+ scriptName = fileBaseNameEndsWithDotSrc ? fileBaseName.slice(0, -4) : fileBaseName,
510
+ scriptUser =
511
+ "scripts" == basename(resolve(target, "..")) && "hackmud" == basename(resolve(target, "../../..")) ?
512
+ basename(resolve(target, "../.."))
513
+ : "UNKNOWN",
514
+ minify = !options.get("skip-minify")
515
+ if (options.has("skip-minify") && options.has("mangle-names")) {
516
+ logError(`Option ${colourN("--mangle-names")} would have no effect if minification is skipped\n`)
517
+ logHelp()
518
+ break
519
+ }
520
+ const mangleNames_ = options.get("mangle-names")
521
+ if (null != mangleNames_ && "boolean" != typeof mangleNames_) {
522
+ logError(
523
+ `The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
524
+ )
525
+ logHelp()
526
+ break
527
+ }
528
+ const mangleNames = mangleNames_,
529
+ forceQuineCheats_ = options.get("force-quine-cheats")
530
+ if (null != forceQuineCheats_ && "boolean" != typeof forceQuineCheats_) {
531
+ logError(
532
+ `the value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
533
+ )
534
+ logHelp()
535
+ break
536
+ }
537
+ const forceQuineCheats = forceQuineCheats_
538
+ let outputPath =
539
+ commands[2] ||
540
+ resolve(
541
+ dirname(target),
542
+ fileBaseNameEndsWithDotSrc ? scriptName + ".js"
543
+ : ".js" == fileExtension ? fileBaseName + ".min.js"
544
+ : fileBaseName + ".js"
545
+ )
546
+ const golfFile = () =>
547
+ readFile(target, { encoding: "utf-8" }).then(
548
+ async source => {
549
+ const timeStart = performance.now(),
550
+ { script, warnings } = await processScript(source, {
551
+ minify,
552
+ scriptUser,
553
+ scriptName,
554
+ filePath: target,
555
+ mangleNames,
556
+ forceQuineCheats
557
+ }),
558
+ timeTook = performance.now() - timeStart
559
+ for (const { message, line } of warnings)
560
+ log(`Warning "${chalk.bold(message)}" on line ${chalk.bold(line + "")}`)
561
+ await writeFilePersistent(outputPath, script)
562
+ .catch(async error => {
563
+ if (!commands[2] || "EISDIR" != error.code) throw error
564
+ outputPath = resolve(outputPath, basename(target, fileExtension) + ".js")
565
+ await writeFilePersistent(outputPath, script)
566
+ })
567
+ .then(
568
+ () =>
569
+ log(
570
+ `Wrote ${chalk.bold(countHackmudCharacters(script))} chars to ${chalk.bold(relative(".", outputPath))} | took ${Math.round(100 * timeTook) / 100}ms`
571
+ ),
572
+ error => logError(error.message)
573
+ )
574
+ },
575
+ error => logError(error.message)
576
+ )
577
+ if (options.get("watch")) {
578
+ const { watch: watchFile } = await chokidarModule
579
+ watchFile(target, { awaitWriteFinish: { stabilityThreshold: 100 } })
580
+ .on("ready", () => log("Watching " + target))
581
+ .on("change", golfFile)
582
+ autoExit = !1
583
+ } else await golfFile()
584
+ }
585
+ break
586
+ default:
587
+ commands[0] && logError(`Unknown command: ${JSON.stringify(commands[0])}\n`)
588
+ logHelp()
589
+ }
590
+ autoExit && process.exit()
package/constants.js CHANGED
@@ -1 +1,3 @@
1
- const s=[".js",".ts"],t=["i","r","f","u","u1","us","ObjectId"];export{s as supportedExtensions,t as validDBMethods};
1
+ const supportedExtensions = [".js", ".ts"],
2
+ validDBMethods = ["i", "r", "f", "u", "u1", "us", "ObjectId"]
3
+ export { supportedExtensions, validDBMethods }