hackmud-script-manager 0.19.0 → 0.19.1-01c1752

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,9 +1,7 @@
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
- Install with `npm install hackmud-script-manager -g` to make the `hsm` command available everywhere.
4
+ Install with `npm install -g hackmud-script-manager` to make the `hsm` command available everywhere.
7
5
 
8
6
  ## Features
9
7
  - Minification
package/bin/hsm.d.ts CHANGED
File without changes
package/bin/hsm.js CHANGED
@@ -1,2 +1,437 @@
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 { writeFile, readFile } from "fs/promises"
7
+ import { homedir } from "os"
8
+ import { extname, basename, resolve, 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 version = "0.19.1-01c1752",
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
+ log = message => console.log(colourS(message))
24
+ for (const argument of process.argv.slice(2))
25
+ if ("-" == argument[0]) {
26
+ const [key, valueRaw] = argument.split("=")
27
+ let value = valueRaw
28
+ if (value)
29
+ if ("true" == value) value = !0
30
+ else if ("false" == value) value = !1
31
+ else {
32
+ const number = Number(value)
33
+ isFinite(number) && (value = number)
34
+ }
35
+ else value = !0
36
+ if ("-" == argument[1]) options.set(key.slice(2), value)
37
+ else for (const option of key.slice(1)) options.set(option, value)
38
+ } else commands.push(argument)
39
+ if ("v" == commands[0] || "version" == commands[0] || options.get("version") || options.get("v")) {
40
+ console.log(version)
41
+ process.exit()
42
+ }
43
+ const pushModule = import("../push.js"),
44
+ processScriptModule = import("../processScript/index.js"),
45
+ watchModule = import("../watch.js"),
46
+ chokidarModule = import("chokidar"),
47
+ { default: chalk } = await import("chalk"),
48
+ colourA = chalk.rgb(255, 255, 255),
49
+ colourB = chalk.rgb(202, 202, 202),
50
+ colourC = chalk.rgb(155, 155, 155),
51
+ colourD = chalk.rgb(255, 0, 0),
52
+ colourJ = chalk.rgb(255, 244, 4),
53
+ colourK = chalk.rgb(243, 249, 152),
54
+ colourL = chalk.rgb(30, 255, 0),
55
+ colourM = chalk.rgb(179, 255, 155),
56
+ colourN = chalk.rgb(0, 255, 255),
57
+ colourS = chalk.rgb(122, 178, 244),
58
+ colourV = chalk.rgb(255, 0, 236),
59
+ colourW = chalk.rgb(255, 150, 224)
60
+ if (options.get("help") || options.get("h")) {
61
+ logHelp()
62
+ process.exit()
63
+ }
64
+ let autoExit = !0
65
+ switch (commands[0]) {
66
+ case "push":
67
+ {
68
+ const hackmudPath = getHackmudPath(),
69
+ sourcePath = commands[1]
70
+ if (!sourcePath) {
71
+ logError("Must provide the directory to push from\n")
72
+ logHelp()
73
+ break
74
+ }
75
+ const scripts = commands.slice(2)
76
+ if (scripts.length) {
77
+ const invalidScript = scripts.find(
78
+ script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script)
79
+ )
80
+ if (invalidScript) {
81
+ logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`)
82
+ logHelp()
83
+ break
84
+ }
85
+ } else scripts.push("*.*")
86
+ const optionsHasNoMinify = options.has("no-minify")
87
+ if ((optionsHasNoMinify || options.has("skip-minify")) && options.has("mangle-names")) {
88
+ logError(
89
+ `Options ${colourN("--mangle-names")} and ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} are incompatible\n`
90
+ )
91
+ logHelp()
92
+ break
93
+ }
94
+ const shouldSkipMinify = options.get("no-minify") || options.get("skip-minify")
95
+ let shouldMinify
96
+ if (null != shouldSkipMinify) {
97
+ if ("boolean" != typeof shouldSkipMinify) {
98
+ logError(
99
+ `The value for ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} must be ${colourV("true")} or ${colourV("false")}\n`
100
+ )
101
+ logHelp()
102
+ break
103
+ }
104
+ shouldMinify = !shouldSkipMinify
105
+ }
106
+ const shouldMangleNames = options.get("mangle-names")
107
+ if (null != shouldMangleNames && "boolean" != typeof shouldMangleNames) {
108
+ logError(
109
+ `The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
110
+ )
111
+ logHelp()
112
+ break
113
+ }
114
+ const shouldforceQuineCheats = options.get("force-quine-cheats")
115
+ if (null != shouldforceQuineCheats && "boolean" != typeof shouldforceQuineCheats) {
116
+ logError(
117
+ `The value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
118
+ )
119
+ logHelp()
120
+ break
121
+ }
122
+ const { push } = await pushModule
123
+ ;(
124
+ await push(sourcePath, hackmudPath, {
125
+ scripts,
126
+ onPush: info => logInfo(info, hackmudPath),
127
+ minify: shouldMinify,
128
+ mangleNames: shouldMangleNames,
129
+ forceQuineCheats: shouldforceQuineCheats
130
+ })
131
+ ).length || logError("Could not find any scripts to push")
132
+ }
133
+ break
134
+ case "dev":
135
+ case "watch":
136
+ {
137
+ const hackmudPath = getHackmudPath(),
138
+ sourcePath = commands[1]
139
+ if (!sourcePath) {
140
+ logError("Must provide the directory to watch\n")
141
+ logHelp()
142
+ break
143
+ }
144
+ const scripts = commands.slice(2)
145
+ if (scripts.length) {
146
+ const invalidScript = scripts.find(
147
+ script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script)
148
+ )
149
+ if (invalidScript) {
150
+ logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`)
151
+ logHelp()
152
+ break
153
+ }
154
+ } else scripts.push("*.*")
155
+ const optionsHasNoMinify = options.has("no-minify")
156
+ if ((optionsHasNoMinify || options.has("skip-minify")) && options.has("mangle-names")) {
157
+ logError(
158
+ `Options ${colourN("--mangle-names")} and ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} are incompatible\n`
159
+ )
160
+ logHelp()
161
+ break
162
+ }
163
+ const shouldSkipMinify = options.get("no-minify") || options.get("skip-minify")
164
+ let shouldMinify
165
+ if (null != shouldSkipMinify) {
166
+ if ("boolean" != typeof shouldSkipMinify) {
167
+ logError(
168
+ `The value for ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} must be ${colourV("true")} or ${colourV("false")}\n`
169
+ )
170
+ logHelp()
171
+ break
172
+ }
173
+ shouldMinify = !shouldSkipMinify
174
+ }
175
+ const shouldMangleNames = options.get("mangle-names")
176
+ if (null != shouldMangleNames && "boolean" != typeof shouldMangleNames) {
177
+ logError(
178
+ `The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
179
+ )
180
+ logHelp()
181
+ break
182
+ }
183
+ const shouldforceQuineCheats = options.get("force-quine-cheats")
184
+ if (null != shouldforceQuineCheats && "boolean" != typeof shouldforceQuineCheats) {
185
+ logError(
186
+ `The value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
187
+ )
188
+ logHelp()
189
+ break
190
+ }
191
+ const { watch } = await watchModule
192
+ watch(sourcePath, hackmudPath, {
193
+ scripts,
194
+ onPush: info => logInfo(info, hackmudPath),
195
+ typeDeclarationPath: (
196
+ options.get("type-declaration-path") ||
197
+ options.get("type-declaration") ||
198
+ options.get("dts") ||
199
+ options.get("gen-types")
200
+ )?.toString(),
201
+ minify: shouldMinify,
202
+ mangleNames: shouldMangleNames,
203
+ onReady: () => log("Watching"),
204
+ forceQuineCheats: shouldforceQuineCheats
205
+ })
206
+ autoExit = !1
207
+ }
208
+ break
209
+ case "pull":
210
+ {
211
+ const hackmudPath = getHackmudPath(),
212
+ script = commands[1]
213
+ if (!script) {
214
+ logError("Must provide the script to pull\n")
215
+ logHelp()
216
+ break
217
+ }
218
+ const sourcePath = commands[2] || "."
219
+ await pull(sourcePath, hackmudPath, script).catch(error => {
220
+ console.error(error)
221
+ logError(`Something went wrong, did you forget to ${colourC("#down")} the script?`)
222
+ })
223
+ }
224
+ break
225
+ case "sync-macros":
226
+ {
227
+ const hackmudPath = getHackmudPath(),
228
+ { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
229
+ log(`Synced ${macrosSynced} macros to ${usersSynced} users`)
230
+ }
231
+ break
232
+ case "generate-type-declaration":
233
+ case "gen-type-declaration":
234
+ case "gen-dts":
235
+ case "gen-types":
236
+ {
237
+ const target = commands[1]
238
+ if (!target) {
239
+ logError("Must provide target directory\n")
240
+ logHelp()
241
+ break
242
+ }
243
+ const sourcePath = resolve(target),
244
+ outputPath = commands[2] || "./player.d.ts",
245
+ typeDeclaration = await generateTypeDeclaration(sourcePath, getHackmudPath())
246
+ let typeDeclarationPath = resolve(outputPath)
247
+ await writeFile(typeDeclarationPath, typeDeclaration).catch(error => {
248
+ assert(error instanceof Error, "src/bin/hsm.ts:327:35")
249
+ if ("EISDIR" != error.code) throw error
250
+ typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
251
+ return writeFile(typeDeclarationPath, typeDeclaration)
252
+ })
253
+ log("Wrote type declaration to " + chalk.bold(typeDeclarationPath))
254
+ }
255
+ break
256
+ case "help":
257
+ case "h":
258
+ logHelp()
259
+ break
260
+ case "golf":
261
+ case "minify":
262
+ {
263
+ const target = commands[1]
264
+ if (!target) {
265
+ logError("Must provide target\n")
266
+ logHelp()
267
+ break
268
+ }
269
+ const fileExtension = extname(target)
270
+ if (!supportedExtensions.includes(fileExtension)) {
271
+ logError(
272
+ `Unsupported file extension "${chalk.bold(fileExtension)}"\nSupported extensions are "${supportedExtensions.map(extension => chalk.bold(extension)).join('", "')}"`
273
+ )
274
+ break
275
+ }
276
+ const { processScript } = await processScriptModule,
277
+ fileBaseName = basename(target, fileExtension),
278
+ fileBaseNameEndsWithDotSrc = fileBaseName.endsWith(".src"),
279
+ scriptName = fileBaseNameEndsWithDotSrc ? fileBaseName.slice(0, -4) : fileBaseName,
280
+ scriptUser =
281
+ "scripts" == basename(resolve(target, "..")) && "hackmud" == basename(resolve(target, "../../..")) ?
282
+ basename(resolve(target, "../.."))
283
+ : void 0,
284
+ optionsHasNoMinify = options.has("no-minify")
285
+ if ((optionsHasNoMinify || options.has("skip-minify")) && options.has("mangle-names")) {
286
+ logError(
287
+ `Options ${colourN("--mangle-names")} and ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} are incompatible\n`
288
+ )
289
+ logHelp()
290
+ break
291
+ }
292
+ const mangleNames_ = options.get("mangle-names")
293
+ if (null != mangleNames_ && "boolean" != typeof mangleNames_) {
294
+ logError(
295
+ `The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
296
+ )
297
+ logHelp()
298
+ break
299
+ }
300
+ const mangleNames = mangleNames_,
301
+ forceQuineCheats_ = options.get("force-quine-cheats")
302
+ if (null != forceQuineCheats_ && "boolean" != typeof forceQuineCheats_) {
303
+ logError(
304
+ `the value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
305
+ )
306
+ logHelp()
307
+ break
308
+ }
309
+ const forceQuineCheats = forceQuineCheats_
310
+ let outputPath =
311
+ commands[2] ||
312
+ resolve(
313
+ dirname(target),
314
+ fileBaseNameEndsWithDotSrc ? scriptName + ".js"
315
+ : ".js" == fileExtension ? fileBaseName + ".min.js"
316
+ : fileBaseName + ".js"
317
+ )
318
+ const golfFile = () =>
319
+ readFile(target, { encoding: "utf8" }).then(async source => {
320
+ const timeStart = performance.now(),
321
+ { script, warnings } = await processScript(source, {
322
+ minify: !(options.get("no-minify") || options.get("skip-minify")),
323
+ scriptUser,
324
+ scriptName,
325
+ filePath: target,
326
+ mangleNames,
327
+ forceQuineCheats
328
+ }),
329
+ timeTook = performance.now() - timeStart
330
+ for (const { message, line } of warnings)
331
+ log(`Warning "${chalk.bold(message)}" on line ${chalk.bold(line + "")}`)
332
+ await writeFilePersistent(outputPath, script)
333
+ .catch(error => {
334
+ if (!commands[2] || "EISDIR" != error.code) throw error
335
+ outputPath = resolve(outputPath, basename(target, fileExtension) + ".js")
336
+ return writeFilePersistent(outputPath, script)
337
+ })
338
+ .then(() =>
339
+ log(
340
+ `Wrote ${chalk.bold(countHackmudCharacters(script))} chars to ${chalk.bold(relative(".", outputPath))} | took ${Math.round(100 * timeTook) / 100}ms`
341
+ )
342
+ )
343
+ })
344
+ if (options.get("watch")) {
345
+ const { watch: watchFile } = await chokidarModule
346
+ watchFile(target, { awaitWriteFinish: { stabilityThreshold: 100 } })
347
+ .on("ready", () => log("Watching " + target))
348
+ .on("change", golfFile)
349
+ autoExit = !1
350
+ } else await golfFile()
351
+ }
352
+ break
353
+ default:
354
+ commands[0] && logError(`Unknown command: ${colourL(commands[0])}\n`)
355
+ logHelp()
356
+ }
357
+ autoExit && process.exit()
358
+ function logHelp() {
359
+ const pushCommandDescription = "Push scripts from a directory to hackmud user's scripts directories",
360
+ forceQuineCheatsOptionDescription = `Force quine cheats on. Use ${colourN("--force-quine-cheats")}=${colourV("false")} to force off`,
361
+ hackmudPathOption = `${colourN("--hackmud-path")}=${colourB("<path>")}\n Override hackmud path`
362
+ console.log(colourN("Version") + colourS(": ") + colourV(version))
363
+ switch (commands[0]) {
364
+ case "dev":
365
+ case "watch":
366
+ case "push":
367
+ console.log(
368
+ colourS(
369
+ `\n${colourJ("push" == commands[0] ? pushCommandDescription : "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("Arguments:")}\n${colourB("<directory>")}\n The source directory containing your scripts\n${colourB("<script user>")}\n A user to push script(s) to. Can be set to wild card (${colourV("*")}) which will try\n and discover users to push to\n${colourB("<script name>")}\n Name of a script to push. Can be set to wild card (${colourV("*")}) to find all scripts\n\n${colourA("Options:")}\n${colourN("--no-minify")}\n Skip minification to produce a "readable" script\n${colourN("--mangle-names")}\n Reduce character count further but lose function names in error call stacks\n${colourN("--force-quine-cheats")}\n ${forceQuineCheatsOptionDescription}\n${hackmudPathOption}\n${"push" == commands[0] ? "" : `${colourN("--type-declaration-path")}=${colourB("<path>")}\n Path to generate a type declaration file for the scripts\n`}\n${colourA("Examples:")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")}\n\tPushes all scripts found in ${colourV("src")} folder to all users\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")} ${colourC("foo")}${colourV(".")}${colourL("bar")}\n Pushes a script named ${colourL("bar")} found in ${colourV("src")} folder to user ${userColours.get("foo")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")} ${colourC("foo")}${colourV(".")}${colourL("bar")} ${colourC("baz")}${colourV(".")}${colourL("qux")}\n Multiple can be specified\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")} ${colourC("foo")}${colourV(".")}${colourL("*")}\n\tPushes all scripts found in ${colourV("src")} folder to user ${userColours.get("foo")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")} ${colourC("*")}${colourV(".")}${colourL("foo")}\n\tPushes all scripts named ${colourL("foo")} found in ${colourV("src")} folder to all user\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")} ${colourC("*")}${colourV(".")}${colourL("*")}\n\tPushes all scripts found in ${colourV("src")} folder to all users`
370
+ )
371
+ )
372
+ break
373
+ case "pull":
374
+ console.log(
375
+ colourS(
376
+ `\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>")}\n\n${colourA("Options:")}\n${hackmudPathOption}`
377
+ )
378
+ )
379
+ break
380
+ case "minify":
381
+ case "golf":
382
+ console.log(
383
+ colourS(
384
+ `\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 Reduce character count further but lose function names in error call stacks\n${colourN("--force-quine-cheats")}\n ${forceQuineCheatsOptionDescription}\n${colourN("--watch")}\n Watch for changes`
385
+ )
386
+ )
387
+ break
388
+ case "generate-type-declaration":
389
+ case "gen-type-declaration":
390
+ case "gen-dts":
391
+ case "gen-types":
392
+ console.log(
393
+ colourS(
394
+ `${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]")}\n\n${colourA("Options:")}\n${hackmudPathOption}`
395
+ )
396
+ )
397
+ break
398
+ case "sync-macros":
399
+ console.log(
400
+ colourS(
401
+ `\n${colourJ("Sync macros across all hackmud users")}\n\n${colourA("Options:")}\n${hackmudPathOption}`
402
+ )
403
+ )
404
+ break
405
+ default:
406
+ console.log(
407
+ colourS(
408
+ `\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("pull")}\n Pull a script a from a hackmud user's script directory`
409
+ )
410
+ )
411
+ }
412
+ }
413
+ function logInfo({ path, users, characterCount, error }, hackmudPath) {
414
+ path = relative(".", path)
415
+ error ?
416
+ logError(`Error "${chalk.bold(error.message)}" in ${chalk.bold(path)}`)
417
+ : log(
418
+ `Pushed ${chalk.bold(path)} to ${users.map(user => chalk.bold(userColours.get(user))).join(", ")} | ${chalk.bold(characterCount + "")} chars | ${chalk.bold(resolve(hackmudPath, users[0], "scripts", basename(path, extname(path))) + ".js")}`
419
+ )
420
+ }
421
+ function logError(message) {
422
+ console.error(colourD(message))
423
+ process.exitCode = 1
424
+ }
425
+ function getHackmudPath() {
426
+ const hackmudPathOption = options.get("hackmud-path")
427
+ if (null != hackmudPathOption && "string" != typeof hackmudPathOption) {
428
+ logError(`Option ${colourN("--hackmud-path")} must be a string, got ${colourV(hackmudPathOption)}\n`)
429
+ logHelp()
430
+ process.exit(1)
431
+ }
432
+ return (
433
+ hackmudPathOption ||
434
+ process.env.HSM_HACKMUD_PATH ||
435
+ ("win32" == process.platform ? resolve(process.env.APPDATA, "hackmud") : resolve(homedir(), ".config/hackmud"))
436
+ )
437
+ }
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 }