hackmud-script-manager 0.19.1-98e81f8 → 0.19.1-b040eb5

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,7 +1,7 @@
1
1
  # Hackmud Script Manager
2
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.
3
3
 
4
- 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.
5
5
 
6
6
  ## Features
7
7
  - Minification
package/bin/hsm.d.ts CHANGED
File without changes
package/bin/hsm.js CHANGED
@@ -3,16 +3,16 @@ import { Cache } from "@samual/lib/Cache"
3
3
  import { assert } from "@samual/lib/assert"
4
4
  import { countHackmudCharacters } from "@samual/lib/countHackmudCharacters"
5
5
  import { writeFilePersistent } from "@samual/lib/writeFilePersistent"
6
- import { readFile, writeFile, mkdir, rmdir } from "fs/promises"
6
+ import { writeFile, readFile } from "fs/promises"
7
7
  import { homedir } from "os"
8
- import { resolve, extname, basename, dirname, relative } from "path"
8
+ import { extname, basename, resolve, dirname, relative } from "path"
9
9
  import { supportedExtensions } from "../constants.js"
10
10
  import { generateTypeDeclaration } from "../generateTypeDeclaration.js"
11
11
  import { pull } from "../pull.js"
12
12
  import { syncMacros } from "../syncMacros.js"
13
+ import "@samual/lib/readDirectoryWithStats"
13
14
  import "@samual/lib/copyFilePersistent"
14
- const configDirectoryPath = resolve(homedir(), ".config"),
15
- configFilePath = resolve(configDirectoryPath, "hsm.json"),
15
+ const version = "0.19.1-b040eb5",
16
16
  options = new Map(),
17
17
  commands = [],
18
18
  userColours = new Cache(user => {
@@ -20,117 +20,7 @@ const configDirectoryPath = resolve(homedir(), ".config"),
20
20
  for (const char of user) hash += (hash >> 1) + hash + "xi1_8ratvsw9hlbgm02y5zpdcn7uekof463qj".indexOf(char) + 1
21
21
  return [colourJ, colourK, colourM, colourW, colourL, colourB][hash % 6](user)
22
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-98e81f8"))
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
- }
23
+ log = message => console.log(colourS(message))
134
24
  for (const argument of process.argv.slice(2))
135
25
  if ("-" == argument[0]) {
136
26
  const [key, valueRaw] = argument.split("=")
@@ -147,35 +37,10 @@ for (const argument of process.argv.slice(2))
147
37
  else for (const option of key.slice(1)) options.set(option, value)
148
38
  } else commands.push(argument)
149
39
  if ("v" == commands[0] || "version" == commands[0] || options.get("version") || options.get("v")) {
150
- console.log("0.19.1-98e81f8")
40
+ console.log(version)
151
41
  process.exit()
152
42
  }
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"),
43
+ const pushModule = import("../push.js"),
179
44
  processScriptModule = import("../processScript/index.js"),
180
45
  watchModule = import("../watch.js"),
181
46
  chokidarModule = import("chokidar"),
@@ -200,12 +65,8 @@ let autoExit = !0
200
65
  switch (commands[0]) {
201
66
  case "push":
202
67
  {
203
- const { hackmudPath } = await configPromise
204
- if (!hackmudPath) {
205
- logNeedHackmudPathMessage()
206
- break
207
- }
208
- const sourcePath = commands[1]
68
+ const hackmudPath = getHackmudPath(),
69
+ sourcePath = commands[1]
209
70
  if (!sourcePath) {
210
71
  logError("Must provide the directory to push from\n")
211
72
  logHelp()
@@ -222,17 +83,20 @@ switch (commands[0]) {
222
83
  break
223
84
  }
224
85
  } 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`)
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
+ )
227
91
  logHelp()
228
92
  break
229
93
  }
230
- const shouldSkipMinify = options.get("skip-minify")
94
+ const shouldSkipMinify = options.get("no-minify") || options.get("skip-minify")
231
95
  let shouldMinify
232
96
  if (null != shouldSkipMinify) {
233
97
  if ("boolean" != typeof shouldSkipMinify) {
234
98
  logError(
235
- `The value for ${colourN("--skip-minify")} must be ${colourV("true")} or ${colourV("false")}\n`
99
+ `The value for ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} must be ${colourV("true")} or ${colourV("false")}\n`
236
100
  )
237
101
  logHelp()
238
102
  break
@@ -270,12 +134,8 @@ switch (commands[0]) {
270
134
  case "dev":
271
135
  case "watch":
272
136
  {
273
- const { hackmudPath } = await configPromise
274
- if (!hackmudPath) {
275
- logNeedHackmudPathMessage()
276
- break
277
- }
278
- const sourcePath = commands[1]
137
+ const hackmudPath = getHackmudPath(),
138
+ sourcePath = commands[1]
279
139
  if (!sourcePath) {
280
140
  logError("Must provide the directory to watch\n")
281
141
  logHelp()
@@ -292,17 +152,20 @@ switch (commands[0]) {
292
152
  break
293
153
  }
294
154
  } 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`)
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
+ )
297
160
  logHelp()
298
161
  break
299
162
  }
300
- const shouldSkipMinify = options.get("skip-minify")
163
+ const shouldSkipMinify = options.get("no-minify") || options.get("skip-minify")
301
164
  let shouldMinify
302
165
  if (null != shouldSkipMinify) {
303
166
  if ("boolean" != typeof shouldSkipMinify) {
304
167
  logError(
305
- `The value for ${colourN("--skip-minify")} must be ${colourV("true")} or ${colourV("false")}\n`
168
+ `The value for ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} must be ${colourV("true")} or ${colourV("false")}\n`
306
169
  )
307
170
  logHelp()
308
171
  break
@@ -345,34 +208,24 @@ switch (commands[0]) {
345
208
  break
346
209
  case "pull":
347
210
  {
348
- const { hackmudPath } = await configPromise
349
- if (!hackmudPath) {
350
- logNeedHackmudPathMessage()
351
- break
352
- }
353
- const script = commands[1]
211
+ const hackmudPath = getHackmudPath(),
212
+ script = commands[1]
354
213
  if (!script) {
355
214
  logError("Must provide the script to pull\n")
356
215
  logHelp()
357
216
  break
358
217
  }
359
218
  const sourcePath = commands[2] || "."
360
- try {
361
- await pull(sourcePath, hackmudPath, script)
362
- } catch (error) {
219
+ await pull(sourcePath, hackmudPath, script).catch(error => {
363
220
  console.error(error)
364
221
  logError(`Something went wrong, did you forget to ${colourC("#down")} the script?`)
365
- }
222
+ })
366
223
  }
367
224
  break
368
225
  case "sync-macros":
369
226
  {
370
- const { hackmudPath } = await configPromise
371
- if (!hackmudPath) {
372
- logNeedHackmudPathMessage()
373
- break
374
- }
375
- const { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
227
+ const hackmudPath = getHackmudPath(),
228
+ { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
376
229
  log(`Synced ${macrosSynced} macros to ${usersSynced} users`)
377
230
  }
378
231
  break
@@ -389,100 +242,17 @@ switch (commands[0]) {
389
242
  }
390
243
  const sourcePath = resolve(target),
391
244
  outputPath = commands[2] || "./player.d.ts",
392
- typeDeclaration = await generateTypeDeclaration(sourcePath, (await configPromise).hackmudPath)
245
+ typeDeclaration = await generateTypeDeclaration(sourcePath, getHackmudPath())
393
246
  let typeDeclarationPath = resolve(outputPath)
394
- try {
395
- await writeFile(typeDeclarationPath, typeDeclaration)
396
- } catch (error) {
397
- assert(error instanceof Error)
247
+ await writeFile(typeDeclarationPath, typeDeclaration).catch(error => {
248
+ assert(error instanceof Error, "src/bin/hsm.ts:327:35")
398
249
  if ("EISDIR" != error.code) throw error
399
250
  typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
400
- await writeFile(typeDeclarationPath, typeDeclaration)
401
- }
251
+ return writeFile(typeDeclarationPath, typeDeclaration)
252
+ })
402
253
  log("Wrote type declaration to " + chalk.bold(typeDeclarationPath))
403
254
  }
404
255
  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
256
  case "help":
487
257
  case "h":
488
258
  logHelp()
@@ -510,10 +280,12 @@ switch (commands[0]) {
510
280
  scriptUser =
511
281
  "scripts" == basename(resolve(target, "..")) && "hackmud" == basename(resolve(target, "../../..")) ?
512
282
  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`)
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
+ )
517
289
  logHelp()
518
290
  break
519
291
  }
@@ -544,36 +316,31 @@ switch (commands[0]) {
544
316
  : fileBaseName + ".js"
545
317
  )
546
318
  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)
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`
573
341
  )
574
- },
575
- error => logError(error.message)
576
- )
342
+ )
343
+ })
577
344
  if (options.get("watch")) {
578
345
  const { watch: watchFile } = await chokidarModule
579
346
  watchFile(target, { awaitWriteFinish: { stabilityThreshold: 100 } })
@@ -584,7 +351,87 @@ switch (commands[0]) {
584
351
  }
585
352
  break
586
353
  default:
587
- commands[0] && logError(`Unknown command: ${JSON.stringify(commands[0])}\n`)
354
+ commands[0] && logError(`Unknown command: ${colourL(commands[0])}\n`)
588
355
  logHelp()
589
356
  }
590
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
+ }