hackmud-script-manager 0.19.1-bd545f5 → 0.19.1-cb8d65f

Sign up to get free protection for your applications and to get access to all the features.
package/bin/hsm.js CHANGED
@@ -1,7 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { Cache } from "@samual/lib/Cache"
3
3
  import { assert } from "@samual/lib/assert"
4
+ import { catchError } from "@samual/lib/catchError"
4
5
  import { countHackmudCharacters } from "@samual/lib/countHackmudCharacters"
6
+ import { getDeepObjectProperty } from "@samual/lib/getDeepObjectProperty"
7
+ import { isRecord } from "@samual/lib/isRecord"
8
+ import { setDeepObjectProperty } from "@samual/lib/setDeepObjectProperty"
5
9
  import { writeFilePersistent } from "@samual/lib/writeFilePersistent"
6
10
  import { readFile, writeFile, mkdir, rmdir } from "fs/promises"
7
11
  import { homedir } from "os"
@@ -21,119 +25,7 @@ const configDirectoryPath = resolve(homedir(), ".config"),
21
25
  for (const char of user) hash += (hash >> 1) + hash + "xi1_8ratvsw9hlbgm02y5zpdcn7uekof463qj".indexOf(char) + 1
22
26
  return [colourJ, colourK, colourM, colourW, colourL, colourB][hash % 6](user)
23
27
  }),
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-bd545f5"))
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
- }
28
+ log = message => console.log(colourS(message))
137
29
  for (const argument of process.argv.slice(2))
138
30
  if ("-" == argument[0]) {
139
31
  const [key, valueRaw] = argument.split("=")
@@ -150,20 +42,14 @@ for (const argument of process.argv.slice(2))
150
42
  else for (const option of key.slice(1)) options.set(option, value)
151
43
  } else commands.push(argument)
152
44
  if ("v" == commands[0] || "version" == commands[0] || options.get("version") || options.get("v")) {
153
- console.log("0.19.1-bd545f5")
45
+ console.log("0.19.1-cb8d65f")
154
46
  process.exit()
155
47
  }
156
48
  let configDidNotExist = !1
157
49
  const configPromise = readFile(configFilePath, { encoding: "utf-8" }).then(
158
50
  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) {
51
+ const [temporaryConfig, error] = catchError(() => JSON.parse(configFile))
52
+ if (error || !isRecord(temporaryConfig)) {
167
53
  log("Config file was corrupted, resetting")
168
54
  return {}
169
55
  }
@@ -200,15 +86,13 @@ if (options.get("help") || options.get("h")) {
200
86
  process.exit()
201
87
  }
202
88
  let autoExit = !0
89
+ const getDefaultHackmudPath = () =>
90
+ "win32" == process.platform ? resolve(process.env.APPDATA, "hackmud") : resolve(homedir(), ".config/hackmud")
203
91
  switch (commands[0]) {
204
92
  case "push":
205
93
  {
206
- const { hackmudPath } = await configPromise
207
- if (!hackmudPath) {
208
- logNeedHackmudPathMessage()
209
- break
210
- }
211
- const sourcePath = commands[1]
94
+ const { hackmudPath = getDefaultHackmudPath() } = await configPromise,
95
+ sourcePath = commands[1]
212
96
  if (!sourcePath) {
213
97
  logError("Must provide the directory to push from\n")
214
98
  logHelp()
@@ -276,12 +160,8 @@ switch (commands[0]) {
276
160
  case "dev":
277
161
  case "watch":
278
162
  {
279
- const { hackmudPath } = await configPromise
280
- if (!hackmudPath) {
281
- logNeedHackmudPathMessage()
282
- break
283
- }
284
- const sourcePath = commands[1]
163
+ const { hackmudPath = getDefaultHackmudPath() } = await configPromise,
164
+ sourcePath = commands[1]
285
165
  if (!sourcePath) {
286
166
  logError("Must provide the directory to watch\n")
287
167
  logHelp()
@@ -354,34 +234,24 @@ switch (commands[0]) {
354
234
  break
355
235
  case "pull":
356
236
  {
357
- const { hackmudPath } = await configPromise
358
- if (!hackmudPath) {
359
- logNeedHackmudPathMessage()
360
- break
361
- }
362
- const script = commands[1]
237
+ const { hackmudPath = getDefaultHackmudPath() } = await configPromise,
238
+ script = commands[1]
363
239
  if (!script) {
364
240
  logError("Must provide the script to pull\n")
365
241
  logHelp()
366
242
  break
367
243
  }
368
244
  const sourcePath = commands[2] || "."
369
- try {
370
- await pull(sourcePath, hackmudPath, script)
371
- } catch (error) {
245
+ await pull(sourcePath, hackmudPath, script).catch(error => {
372
246
  console.error(error)
373
247
  logError(`Something went wrong, did you forget to ${colourC("#down")} the script?`)
374
- }
248
+ })
375
249
  }
376
250
  break
377
251
  case "sync-macros":
378
252
  {
379
- const { hackmudPath } = await configPromise
380
- if (!hackmudPath) {
381
- logNeedHackmudPathMessage()
382
- break
383
- }
384
- const { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
253
+ const { hackmudPath = getDefaultHackmudPath() } = await configPromise,
254
+ { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
385
255
  log(`Synced ${macrosSynced} macros to ${usersSynced} users`)
386
256
  }
387
257
  break
@@ -398,16 +268,17 @@ switch (commands[0]) {
398
268
  }
399
269
  const sourcePath = resolve(target),
400
270
  outputPath = commands[2] || "./player.d.ts",
401
- typeDeclaration = await generateTypeDeclaration(sourcePath, (await configPromise).hackmudPath)
271
+ typeDeclaration = await generateTypeDeclaration(
272
+ sourcePath,
273
+ (await configPromise).hackmudPath || getDefaultHackmudPath()
274
+ )
402
275
  let typeDeclarationPath = resolve(outputPath)
403
- try {
404
- await writeFile(typeDeclarationPath, typeDeclaration)
405
- } catch (error) {
406
- assert(error instanceof Error)
276
+ await writeFile(typeDeclarationPath, typeDeclaration).catch(error => {
277
+ assert(error instanceof Error, "src/bin/hsm.ts:365:35")
407
278
  if ("EISDIR" != error.code) throw error
408
279
  typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
409
- await writeFile(typeDeclarationPath, typeDeclaration)
410
- }
280
+ return writeFile(typeDeclarationPath, typeDeclaration)
281
+ })
411
282
  log("Wrote type declaration to " + chalk.bold(typeDeclarationPath))
412
283
  }
413
284
  break
@@ -415,8 +286,14 @@ switch (commands[0]) {
415
286
  switch (commands[1]) {
416
287
  case "get":
417
288
  {
418
- const key = commands[2]
419
- key ? log(exploreObject(await configPromise, key.split("."))) : console.log(await configPromise)
289
+ const key = commands[2],
290
+ config = await configPromise
291
+ if (key) {
292
+ const [value, error] = catchError(() => getDeepObjectProperty(config, key.split(".")))
293
+ error ? logError("Could not get key " + colourV(key))
294
+ : "string" == typeof value ? log(value)
295
+ : console.log(value)
296
+ } else console.log(config)
420
297
  }
421
298
  break
422
299
  case "delete":
@@ -427,14 +304,16 @@ switch (commands[0]) {
427
304
  logHelp()
428
305
  break
429
306
  }
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`)
307
+ const keys = key.split("."),
308
+ lastKey = keys.pop(),
309
+ config = await configPromise,
310
+ object = getDeepObjectProperty(config, keys)
311
+ if (isRecord(object)) {
312
+ delete object[lastKey]
313
+ await updateConfig(config)
314
+ log(`Removed ${colourV(key)} from config file:`)
315
+ console.log(config)
316
+ } else log("Could not delete " + colourV(key))
438
317
  }
439
318
  break
440
319
  case "set":
@@ -446,49 +325,20 @@ switch (commands[0]) {
446
325
  logHelp()
447
326
  break
448
327
  }
449
- const keys = key.split("."),
450
- pathName = keys
451
- .map(name => (/^[a-z_$][\w$]*$/i.test(name) ? name : JSON.stringify(name)))
452
- .join(".")
453
328
  if (!value) {
454
- logError(`Must provide a value for the key ${pathName}\n`)
329
+ logError(`Must provide a value for the key ${colourV(key)}\n`)
455
330
  logHelp()
456
331
  break
457
332
  }
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)
333
+ const config = await configPromise
334
+ setDeepObjectProperty(config, key.split("."), value)
335
+ log(`Set ${colourV(key)} to ${colourV(value)}:`)
470
336
  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)
337
+ await updateConfig(config)
488
338
  }
489
339
  break
490
340
  default:
491
- commands[1] && logError(`Unknown command: ${JSON.stringify(commands[1])}\n`)
341
+ commands[1] && logError(`Unknown command: ${colourL(commands[1])}\n`)
492
342
  logHelp()
493
343
  }
494
344
  break
@@ -555,36 +405,31 @@ switch (commands[0]) {
555
405
  : fileBaseName + ".js"
556
406
  )
557
407
  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)
408
+ readFile(target, { encoding: "utf-8" }).then(async source => {
409
+ const timeStart = performance.now(),
410
+ { script, warnings } = await processScript(source, {
411
+ minify: !(options.get("no-minify") || options.get("skip-minify")),
412
+ scriptUser,
413
+ scriptName,
414
+ filePath: target,
415
+ mangleNames,
416
+ forceQuineCheats
417
+ }),
418
+ timeTook = performance.now() - timeStart
419
+ for (const { message, line } of warnings)
420
+ log(`Warning "${chalk.bold(message)}" on line ${chalk.bold(line + "")}`)
421
+ await writeFilePersistent(outputPath, script)
422
+ .catch(error => {
423
+ if (!commands[2] || "EISDIR" != error.code) throw error
424
+ outputPath = resolve(outputPath, basename(target, fileExtension) + ".js")
425
+ return writeFilePersistent(outputPath, script)
426
+ })
427
+ .then(() =>
428
+ log(
429
+ `Wrote ${chalk.bold(countHackmudCharacters(script))} chars to ${chalk.bold(relative(".", outputPath))} | took ${Math.round(100 * timeTook) / 100}ms`
584
430
  )
585
- },
586
- error => logError(error.message)
587
- )
431
+ )
432
+ })
588
433
  if (options.get("watch")) {
589
434
  const { watch: watchFile } = await chokidarModule
590
435
  watchFile(target, { awaitWriteFinish: { stabilityThreshold: 100 } })
@@ -595,7 +440,110 @@ switch (commands[0]) {
595
440
  }
596
441
  break
597
442
  default:
598
- commands[0] && logError(`Unknown command: ${JSON.stringify(commands[0])}\n`)
443
+ commands[0] && logError(`Unknown command: ${colourL(commands[0])}\n`)
599
444
  logHelp()
600
445
  }
601
446
  autoExit && process.exit()
447
+ function logHelp() {
448
+ const pushCommandDescription = "Push scripts from a directory to hackmud user's scripts directories",
449
+ forceQuineCheatsOptionDescription = `Force quine cheats on. Use ${colourN("--force-quine-cheats")}=${colourV("false")} to force off`
450
+ console.log(colourN("Version") + colourS(": ") + colourV("0.19.1-cb8d65f"))
451
+ switch (commands[0]) {
452
+ case "config":
453
+ switch (commands[1]) {
454
+ case "get":
455
+ console.log(
456
+ `\n${colourJ("Retrieve a value from the config file")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(`${commands[0]} ${commands[1]}`)} ${colourB("<key>")}`
457
+ )
458
+ break
459
+ case "set":
460
+ console.log(
461
+ `\n${colourJ("Assign a value to the config file")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(`${commands[0]} ${commands[1]}`)} ${colourB("<key> <value>")}`
462
+ )
463
+ break
464
+ case "delete":
465
+ console.log(
466
+ `\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>")}`
467
+ )
468
+ break
469
+ default:
470
+ console.log(
471
+ colourS(
472
+ `${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`
473
+ )
474
+ )
475
+ }
476
+ break
477
+ case "dev":
478
+ case "watch":
479
+ case "push":
480
+ console.log(
481
+ colourS(
482
+ `\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${"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`
483
+ )
484
+ )
485
+ break
486
+ case "pull":
487
+ console.log(
488
+ colourS(
489
+ `\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>")}`
490
+ )
491
+ )
492
+ break
493
+ case "minify":
494
+ case "golf":
495
+ console.log(
496
+ colourS(
497
+ `\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`
498
+ )
499
+ )
500
+ break
501
+ case "generate-type-declaration":
502
+ case "gen-type-declaration":
503
+ case "gen-dts":
504
+ case "gen-types":
505
+ console.log(
506
+ colourS(
507
+ `${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]")}`
508
+ )
509
+ )
510
+ break
511
+ case "sync-macros":
512
+ console.log("\n" + colourJ("Sync macros across all hackmud users"))
513
+ break
514
+ default:
515
+ console.log(
516
+ colourS(
517
+ `\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`
518
+ )
519
+ )
520
+ }
521
+ }
522
+ async function updateConfig(config) {
523
+ const json = JSON.stringify(config, void 0, "\t")
524
+ configDidNotExist && log("Creating config file at " + configFilePath)
525
+ await writeFile(configFilePath, json).catch(async error => {
526
+ switch (error.code) {
527
+ case "EISDIR":
528
+ await rmdir(configFilePath)
529
+ break
530
+ case "ENOENT":
531
+ await mkdir(configDirectoryPath)
532
+ break
533
+ default:
534
+ throw error
535
+ }
536
+ await writeFile(configFilePath, json)
537
+ })
538
+ }
539
+ function logInfo({ file, users, minLength, error }, hackmudPath) {
540
+ error ?
541
+ logError(`error "${chalk.bold(error.message)}" in ${chalk.bold(file)}`)
542
+ : console.log(
543
+ `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")}`
544
+ )
545
+ }
546
+ function logError(message) {
547
+ console.error(colourD(message))
548
+ process.exitCode = 1
549
+ }
@@ -1,6 +1,6 @@
1
1
  import { readDirectoryWithStats } from "@samual/lib/readDirectoryWithStats"
2
2
  import { basename, resolve } from "path"
3
- const generateTypeDeclaration = async (sourceDirectory, hackmudPath) => {
3
+ async function generateTypeDeclaration(sourceDirectory, hackmudPath) {
4
4
  const users = new Set()
5
5
  if (hackmudPath)
6
6
  for (const { stats, name } of await readDirectoryWithStats(hackmudPath))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hackmud-script-manager",
3
- "version": "0.19.1-bd545f5",
3
+ "version": "0.19.1-cb8d65f",
4
4
  "description": "Script manager for game hackmud, with minification, TypeScript support, and player script type definition generation.",
5
5
  "keywords": [
6
6
  "api",
@@ -59,7 +59,7 @@
59
59
  "@rollup/plugin-commonjs": "^25.0.7",
60
60
  "@rollup/plugin-json": "^6.1.0",
61
61
  "@rollup/plugin-node-resolve": "^15.2.3",
62
- "@samual/lib": "0.10.2-5919775",
62
+ "@samual/lib": "0.10.2-e64c5bc",
63
63
  "acorn": "^8.11.3",
64
64
  "chalk": "^5.3.0",
65
65
  "chokidar": "^3.6.0",
@@ -69,17 +69,12 @@
69
69
  "rollup": "^4.14.2",
70
70
  "terser": "^5.30.3"
71
71
  },
72
- "engines": {
73
- "node": "^18 || >=20",
74
- "pnpm": "^9.0.1"
75
- },
76
72
  "type": "module",
77
73
  "exports": {
78
74
  "./*": "./*.js",
79
75
  "./*.js": "./*.js"
80
76
  },
81
- "bin": {
82
- "hsm.d": "bin/hsm.d.ts",
83
- "hsm": "bin/hsm.js"
77
+ "engines": {
78
+ "node": "^18 || >=20"
84
79
  }
85
80
  }