hackmud-script-manager 0.19.0-fa82f73 → 0.19.1-003b022

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