hackmud-script-manager 0.20.4-550e28d → 0.20.4-66e0e13

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
@@ -20,6 +20,10 @@ You can read about how HSM works [in my blog post](https://samual.uk/blog/js-cod
20
20
  > ```
21
21
  > You will need to run `Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser` in PowerShell as an administrator. For more information, see [Microsoft's page about Execution Policies](https://learn.microsoft.com/en-gb/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.4).
22
22
 
23
+ ![image](https://github.com/samualtnorman/hackmud-script-manager/assets/18307063/69a371fe-f8c8-43fe-b3c7-39f3735ce6fb)
24
+ ![image](https://github.com/samualtnorman/hackmud-script-manager/assets/18307063/08103f9e-74fa-4a56-a739-94858ba8c139)
25
+ ![image](https://github.com/samualtnorman/hackmud-script-manager/assets/18307063/25ccb86d-1fe3-4632-b703-ac47f5b32c9c)
26
+
23
27
  ## Features
24
28
  - Minification
25
29
  - This includes auto quine cheating.
package/bin/hsm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { Cache } from "@samual/lib/Cache"
2
+ import { AutoMap } from "@samual/lib/AutoMap"
3
3
  import { assert } from "@samual/lib/assert"
4
4
  import { countHackmudCharacters } from "@samual/lib/countHackmudCharacters"
5
5
  import { writeFilePersistent } from "@samual/lib/writeFilePersistent"
@@ -13,10 +13,10 @@ import { syncMacros } from "../syncMacros.js"
13
13
  import "@samual/lib/readDirectoryWithStats"
14
14
  import "path/posix"
15
15
  import "@samual/lib/copyFilePersistent"
16
- const version = "0.20.4-550e28d",
16
+ const formatOption = name => colourN(`-${1 == name.length ? "" : "-"}${name}`),
17
17
  options = new Map(),
18
18
  commands = [],
19
- userColours = new Cache(user => {
19
+ userColours = new AutoMap(user => {
20
20
  let hash = 0
21
21
  for (const char of user) hash += (hash >> 1) + hash + "xi1_8ratvsw9hlbgm02y5zpdcn7uekof463qj".indexOf(char) + 1
22
22
  return [colourJ, colourK, colourM, colourW, colourL, colourB][hash % 6](user)
@@ -24,16 +24,16 @@ const version = "0.20.4-550e28d",
24
24
  log = message => console.log(colourS(message))
25
25
  for (const argument of process.argv.slice(2))
26
26
  if ("-" == argument[0]) {
27
- const [key, valueRaw] = argument.split("=")
28
- let value = valueRaw
29
- if (value)
30
- if ("true" == value) value = !0
31
- else if ("false" == value) value = !1
32
- else {
33
- const number = Number(value)
34
- isFinite(number) && (value = number)
35
- }
36
- else value = !0
27
+ const argumentEqualsIndex = argument.indexOf("=")
28
+ let key, value
29
+ if (-1 == argumentEqualsIndex) {
30
+ key = argument
31
+ value = !0
32
+ } else {
33
+ key = argument.slice(0, argumentEqualsIndex)
34
+ value = argument.slice(argumentEqualsIndex + 1)
35
+ "true" == value ? (value = !0) : "false" == value && (value = !1)
36
+ }
37
37
  if ("-" == argument[1]) options.set(key.slice(2), value)
38
38
  else for (const option of key.slice(1)) options.set(option, value)
39
39
  } else commands.push(argument)
@@ -58,13 +58,14 @@ const pushModule = import("../push.js"),
58
58
  process.version.startsWith("v21.") &&
59
59
  console.warn(
60
60
  colourF(
61
- "Warning: Support for Node.js 21 will be dropped in the next minor version of HSM\n You should update your version of Node.js\n https://nodejs.org/en/download/package-manager"
61
+ `Warning: Support for Node.js 21 will be dropped in the next minor version of HSM\n Your current version of Node.js is ${chalk.bold(process.version)}\n You should update your version of Node.js\n https://nodejs.org/en/download/package-manager\n`
62
62
  )
63
63
  )
64
64
  if ("v" == commands[0] || "version" == commands[0] || popOption("version", "v")?.value) {
65
- console.log(version)
65
+ console.log("0.20.4-66e0e13")
66
66
  process.exit()
67
67
  }
68
+ let warnedDeprecatedEmitDtsAlias = !1
68
69
  if (popOption("help", "h")?.value) {
69
70
  logHelp()
70
71
  process.exit()
@@ -77,13 +78,28 @@ switch (commands[0]) {
77
78
  case "golf":
78
79
  case "minify":
79
80
  {
80
- const noMinifyOption = popOption("no-minify", "skip-minify"),
81
- mangleNamesOption = popOption("mangle-names"),
81
+ const noMinifyOption = popOption("no-minify", "skip-minify")
82
+ noMinifyOption &&
83
+ "no-minify" != noMinifyOption.name &&
84
+ console.warn(
85
+ colourF(
86
+ `Warning: ${formatOption(noMinifyOption.name)} is deprecated and will be removed in the next minor\n release of HSM\n You should switch to using its alias ${colourN("--no-minify")}\n`
87
+ )
88
+ )
89
+ const mangleNamesOption = popOption("mangle-names"),
82
90
  forceQuineCheatsOption = popOption("force-quine-cheats"),
83
- noMinifyIncompatibleOption = mangleNamesOption || forceQuineCheatsOption
91
+ noQuineCheatsOptions = popOption("no-quine-cheats"),
92
+ noMinifyIncompatibleOption = mangleNamesOption || forceQuineCheatsOption || noQuineCheatsOptions
84
93
  if (noMinifyOption && noMinifyIncompatibleOption) {
85
94
  logError(
86
- `Options ${colourN(noMinifyOption.name)} and ${colourN(noMinifyIncompatibleOption.name)} are incompatible\n`
95
+ `Options ${formatOption(noMinifyOption.name)} and ${formatOption(noMinifyIncompatibleOption.name)} are incompatible\n`
96
+ )
97
+ logHelp()
98
+ process.exit(1)
99
+ }
100
+ if (forceQuineCheatsOption && noQuineCheatsOptions) {
101
+ logError(
102
+ `Options ${formatOption(forceQuineCheatsOption.name)} and ${formatOption(noQuineCheatsOptions.name)} are incompatible\n`
87
103
  )
88
104
  logHelp()
89
105
  process.exit(1)
@@ -91,6 +107,7 @@ switch (commands[0]) {
91
107
  noMinifyOption && assertOptionIsBoolean(noMinifyOption)
92
108
  mangleNamesOption && assertOptionIsBoolean(mangleNamesOption)
93
109
  forceQuineCheatsOption && assertOptionIsBoolean(forceQuineCheatsOption)
110
+ noQuineCheatsOptions && assertOptionIsBoolean(noQuineCheatsOptions)
94
111
  if ("golf" == commands[0] || "minify" == commands[0]) {
95
112
  const watchOption = popOption("watch"),
96
113
  target = commands[1]
@@ -106,6 +123,7 @@ switch (commands[0]) {
106
123
  )
107
124
  process.exit(1)
108
125
  }
126
+ complainAboutUnrecognisedOptions()
109
127
  const { processScript } = await processScriptModule,
110
128
  fileBaseName = basename(target, fileExtension),
111
129
  fileBaseNameEndsWithDotSrc = fileBaseName.endsWith(".src"),
@@ -134,11 +152,10 @@ switch (commands[0]) {
134
152
  scriptName,
135
153
  filePath: target,
136
154
  mangleNames: mangleNamesOption?.value,
137
- forceQuineCheats: forceQuineCheatsOption?.value
155
+ forceQuineCheats: forceQuineCheatsOption?.value ?? !noQuineCheatsOptions?.value
138
156
  }),
139
157
  timeTook = performance.now() - timeStart
140
- for (const { message, line } of warnings)
141
- log(`Warning "${chalk.bold(message)}" on line ${chalk.bold(line + "")}`)
158
+ for (const { message } of warnings) log("Warning: " + chalk.bold(message))
142
159
  await writeFilePersistent(outputPath, script)
143
160
  .catch(error => {
144
161
  if (!commands[2] || "EISDIR" != error.code) throw error
@@ -177,7 +194,58 @@ switch (commands[0]) {
177
194
  process.exit(1)
178
195
  }
179
196
  } else scripts.push("*.*")
180
- if ("push" == commands[0]) {
197
+ const watchOption = popOption("watch")
198
+ if ("push" != commands[0] || watchOption?.value) {
199
+ const dtsPathOption = popOption(
200
+ "dts-path",
201
+ "type-declaration-path",
202
+ "type-declaration",
203
+ "dts",
204
+ "gen-types"
205
+ )
206
+ dtsPathOption &&
207
+ "dts-path" != dtsPathOption.name &&
208
+ "type-declaration-path" != dtsPathOption.name &&
209
+ console.warn(
210
+ colourF(
211
+ `Warning: ${formatOption(dtsPathOption.name)} is deprecated and will be removed in the\n next minor release of HSM\n You should switch to using its alias ${colourN("--dts-path")}\n`
212
+ )
213
+ )
214
+ complainAboutUnrecognisedOptions()
215
+ const { watch } = await watchModule
216
+ watch(sourcePath, hackmudPath, {
217
+ scripts,
218
+ onPush: info => logInfo(info, hackmudPath),
219
+ typeDeclarationPath: dtsPathOption?.value.toString(),
220
+ minify: noMinifyOption && !noMinifyOption.value,
221
+ mangleNames: mangleNamesOption?.value,
222
+ onReady: () => log("Watching"),
223
+ forceQuineCheats: forceQuineCheatsOption?.value ?? !noQuineCheatsOptions?.value
224
+ })
225
+ autoExit = !1
226
+ } else {
227
+ const dtsPathOption = popOption("dts-path")
228
+ complainAboutUnrecognisedOptions()
229
+ let declarationPathPromise
230
+ if (dtsPathOption) {
231
+ if ("string" != typeof dtsPathOption.value) {
232
+ logError(
233
+ `Option ${formatOption(dtsPathOption.name)} must be a string, got ${colourV(dtsPathOption.value)}\n`
234
+ )
235
+ logHelp()
236
+ process.exit(1)
237
+ }
238
+ let typeDeclarationPath = resolve(dtsPathOption.value)
239
+ const typeDeclaration = await generateTypeDeclaration(sourcePath, hackmudPath)
240
+ declarationPathPromise = writeFile(typeDeclarationPath, typeDeclaration)
241
+ .catch(error => {
242
+ assert(error instanceof Error, "src/bin/hsm.ts:288:38")
243
+ if ("EISDIR" != error.code) throw error
244
+ typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
245
+ return writeFile(typeDeclarationPath, typeDeclaration)
246
+ })
247
+ .then(() => typeDeclarationPath)
248
+ }
181
249
  const { push, MissingSourceFolderError, MissingHackmudFolderError, NoUsersError } =
182
250
  await pushModule,
183
251
  infos = await push(sourcePath, hackmudPath, {
@@ -185,7 +253,7 @@ switch (commands[0]) {
185
253
  onPush: info => logInfo(info, hackmudPath),
186
254
  minify: noMinifyOption && !noMinifyOption.value,
187
255
  mangleNames: mangleNamesOption?.value,
188
- forceQuineCheats: forceQuineCheatsOption?.value
256
+ forceQuineCheats: forceQuineCheatsOption?.value ?? !noQuineCheatsOptions?.value
189
257
  })
190
258
  if (infos instanceof Error) {
191
259
  logError(infos.message)
@@ -198,24 +266,8 @@ switch (commands[0]) {
198
266
  `If this is not where your hackmud folder is, you can specify it with the\n${colourN("--hackmud-path")}=${colourB("<path>")} option or ${colourN("HSM_HACKMUD_PATH")} environment variable`
199
267
  )
200
268
  } else infos.length || logError("Could not find any scripts to push")
201
- } else {
202
- const typeDeclarationPathOption = popOption(
203
- "type-declaration-path",
204
- "type-declaration",
205
- "dts",
206
- "gen-types"
207
- ),
208
- { watch } = await watchModule
209
- watch(sourcePath, hackmudPath, {
210
- scripts,
211
- onPush: info => logInfo(info, hackmudPath),
212
- typeDeclarationPath: typeDeclarationPathOption?.value.toString(),
213
- minify: noMinifyOption && !noMinifyOption.value,
214
- mangleNames: mangleNamesOption?.value,
215
- onReady: () => log("Watching"),
216
- forceQuineCheats: forceQuineCheatsOption?.value
217
- })
218
- autoExit = !1
269
+ declarationPathPromise &&
270
+ log("Wrote type declaration to " + chalk.bold(await declarationPathPromise))
219
271
  }
220
272
  }
221
273
  }
@@ -229,6 +281,7 @@ switch (commands[0]) {
229
281
  logHelp()
230
282
  process.exit(1)
231
283
  }
284
+ complainAboutUnrecognisedOptions()
232
285
  const sourcePath = commands[2] || "."
233
286
  await pull(sourcePath, hackmudPath, script).catch(error => {
234
287
  console.error(error)
@@ -238,8 +291,9 @@ switch (commands[0]) {
238
291
  break
239
292
  case "sync-macros":
240
293
  {
241
- const hackmudPath = getHackmudPath(),
242
- { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
294
+ const hackmudPath = getHackmudPath()
295
+ complainAboutUnrecognisedOptions()
296
+ const { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
243
297
  log(`Synced ${macrosSynced} macros to ${usersSynced} users`)
244
298
  }
245
299
  break
@@ -247,7 +301,16 @@ switch (commands[0]) {
247
301
  case "gen-type-declaration":
248
302
  case "gen-dts":
249
303
  case "gen-types":
304
+ case "emit-dts":
250
305
  {
306
+ if ("emit-dts" != commands[0] && "gen-dts" != commands[0]) {
307
+ warnedDeprecatedEmitDtsAlias = !0
308
+ console.warn(
309
+ colourF(
310
+ `Warning: ${colourC("hsm")} ${colourL(commands[0])} is deprecated and will be removed\n in the next minor release of HSM\n You should switch to using its alias ${colourC("hsm")} ${colourL("emit-dts")}\n`
311
+ )
312
+ )
313
+ }
251
314
  const hackmudPath = getHackmudPath(),
252
315
  target = commands[1]
253
316
  if (!target) {
@@ -255,12 +318,13 @@ switch (commands[0]) {
255
318
  logHelp()
256
319
  process.exit(1)
257
320
  }
321
+ complainAboutUnrecognisedOptions()
258
322
  const sourcePath = resolve(target),
259
323
  outputPath = commands[2] || "./player.d.ts",
260
324
  typeDeclaration = await generateTypeDeclaration(sourcePath, hackmudPath)
261
325
  let typeDeclarationPath = resolve(outputPath)
262
326
  await writeFile(typeDeclarationPath, typeDeclaration).catch(error => {
263
- assert(error instanceof Error, "src/bin/hsm.ts:330:35")
327
+ assert(error instanceof Error, "src/bin/hsm.ts:422:35")
264
328
  if ("EISDIR" != error.code) throw error
265
329
  typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
266
330
  return writeFile(typeDeclarationPath, typeDeclaration)
@@ -269,7 +333,6 @@ switch (commands[0]) {
269
333
  }
270
334
  break
271
335
  case "help":
272
- case "h":
273
336
  logHelp()
274
337
  break
275
338
  default:
@@ -279,23 +342,21 @@ switch (commands[0]) {
279
342
  autoExit && process.exit()
280
343
  function logHelp() {
281
344
  const pushCommandDescription = "Push scripts from a directory to hackmud user's scripts directories",
282
- forceQuineCheatsOptionDescription = `Force quine cheats on. Use ${colourN("--force-quine-cheats")}=${colourV("false")} to force off`,
283
345
  hackmudPathOption = `${colourN("--hackmud-path")}=${colourB("<path>")}\n Override hackmud path`
284
- console.log(colourN("Version") + colourS(": ") + colourV(version))
285
346
  switch (commands[0]) {
286
347
  case "dev":
287
348
  case "watch":
288
349
  case "push":
289
350
  console.log(
290
351
  colourS(
291
- `\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 Pushes 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 Pushes 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 Pushes 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 Pushes all scripts found in ${colourV("src")} folder to all users`
352
+ `${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")}, ${colourN("--no-quine-cheats")}\n Force quine cheats on or off\n${hackmudPathOption}\n${colourN("--dts-path")}=${colourB("<path>")}\n Path to generate a type declaration (.d.ts) file for the scripts\n${colourN("--watch")}\n Watch for changes\n\n${colourA("Examples:")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")}\n Pushes 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 Pushes 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 Pushes 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 Pushes all scripts found in ${colourV("src")} folder to all users`
292
353
  )
293
354
  )
294
355
  break
295
356
  case "pull":
296
357
  console.log(
297
358
  colourS(
298
- `\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}`
359
+ `${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}`
299
360
  )
300
361
  )
301
362
  break
@@ -303,7 +364,7 @@ function logHelp() {
303
364
  case "golf":
304
365
  console.log(
305
366
  colourS(
306
- `\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`
367
+ `${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")}, ${colourN("--no-quine-cheats")}\n Force quine cheats on or off\n${colourN("--watch")}\n Watch for changes`
307
368
  )
308
369
  )
309
370
  break
@@ -311,6 +372,15 @@ function logHelp() {
311
372
  case "gen-type-declaration":
312
373
  case "gen-dts":
313
374
  case "gen-types":
375
+ case "emit-dts":
376
+ warnedDeprecatedEmitDtsAlias ||
377
+ "emit-dts" == commands[0] ||
378
+ "gen-dts" == commands[0] ||
379
+ console.warn(
380
+ colourF(
381
+ `Warning: ${colourC("hsm")} ${colourL(commands[0])} is deprecated and will be removed\n in the next minor release of HSM\n You should switch to using its alias ${colourC("hsm")} ${colourL("emit-dts")}\n`
382
+ )
383
+ )
314
384
  console.log(
315
385
  colourS(
316
386
  `${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}`
@@ -320,25 +390,27 @@ function logHelp() {
320
390
  case "sync-macros":
321
391
  console.log(
322
392
  colourS(
323
- `\n${colourJ("Sync macros across all hackmud users")}\n\n${colourA("Options:")}\n${hackmudPathOption}`
393
+ `${colourJ("Sync macros across all hackmud users")}\n\n${colourA("Options:")}\n${hackmudPathOption}`
324
394
  )
325
395
  )
326
396
  break
327
397
  default:
328
398
  console.log(
329
399
  colourS(
330
- `\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`
400
+ `${colourJ("Hackmud Script Manager")}\n${colourN("Version") + colourS(": ") + colourV("0.20.4-66e0e13")}\n\n${colourA("Commands:")}\n${colourL("push")}\n ${pushCommandDescription}\n${colourL("minify")}\n Minify a script file on the spot\n${colourL("emit-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\n\n${colourA("Options:")}\n${colourN("--help")}\n Can be used on any command e.g. ${colourC("hsm")} ${colourL("push")} ${colourN("--help")} to show helpful information`
331
401
  )
332
402
  )
333
403
  }
334
404
  }
335
- function logInfo({ path, users, characterCount, error }, hackmudPath) {
405
+ function logInfo({ path, users, characterCount, error, warnings }, hackmudPath) {
336
406
  path = relative(".", path)
337
- error ?
338
- logError(`Error "${chalk.bold(error.message)}" in ${chalk.bold(path)}`)
339
- : log(
407
+ if (error) logError(`Error "${chalk.bold(error.message)}" in ${chalk.bold(path)}`)
408
+ else {
409
+ for (const warning of warnings) console.warn(colourF("Warning: " + warning.message))
410
+ log(
340
411
  `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")}`
341
412
  )
413
+ }
342
414
  }
343
415
  function logError(message) {
344
416
  console.error(colourD(message))
@@ -346,20 +418,32 @@ function logError(message) {
346
418
  }
347
419
  function getHackmudPath() {
348
420
  const hackmudPathOption = popOption("hackmud-path")
349
- if (null != hackmudPathOption && "string" != typeof hackmudPathOption) {
350
- logError(`Option ${colourN("--hackmud-path")} must be a string, got ${colourV(hackmudPathOption)}\n`)
351
- logHelp()
352
- process.exit(1)
421
+ if (hackmudPathOption) {
422
+ if ("string" != typeof hackmudPathOption.value) {
423
+ logError(`Option ${colourN("--hackmud-path")} must be a string, got ${colourV(hackmudPathOption.value)}\n`)
424
+ logHelp()
425
+ process.exit(1)
426
+ }
427
+ if (!hackmudPathOption.value) {
428
+ logError(`Option ${colourN("--hackmud-path")} was specified but empty\n`)
429
+ logHelp()
430
+ process.exit(1)
431
+ }
432
+ return hackmudPathOption.value
353
433
  }
354
- return (
355
- hackmudPathOption ||
356
- process.env.HSM_HACKMUD_PATH ||
357
- ("win32" == process.platform ? resolve(process.env.APPDATA, "hackmud") : resolve(homedir(), ".config/hackmud"))
358
- )
434
+ if (null != process.env.HSM_HACKMUD_PATH) {
435
+ if (!process.env.HSM_HACKMUD_PATH) {
436
+ logError(`Environment variable ${colourN("HSM_HACKMUD_PATH")} was specified but empty\n`)
437
+ logHelp()
438
+ process.exit(1)
439
+ }
440
+ return process.env.HSM_HACKMUD_PATH
441
+ }
442
+ return "win32" == process.platform ? resolve(process.env.APPDATA, "hackmud") : resolve(homedir(), ".config/hackmud")
359
443
  }
360
444
  function assertOptionIsBoolean(option) {
361
445
  if ("boolean" != typeof option.value) {
362
- logError(`The value for ${colourN(option.name)} must be ${colourV("true")} or ${colourV("false")}\n`)
446
+ logError(`The value for ${formatOption(option.name)} must be ${colourV("true")} or ${colourV("false")}\n`)
363
447
  logHelp()
364
448
  process.exit(1)
365
449
  }
@@ -367,16 +451,21 @@ function assertOptionIsBoolean(option) {
367
451
  function popOption(...names) {
368
452
  const presentOptionNames = names.filter(name => options.has(name))
369
453
  if (!presentOptionNames.length) return
370
- const presentOptionNamesWithDashDash = presentOptionNames.map(name =>
371
- colourN(`-${1 == name.length ? "" : "-"}${name}`)
372
- )
373
454
  if (presentOptionNames.length > 1) {
374
455
  logError(
375
- `The options ${presentOptionNamesWithDashDash.join(", ")} are aliases for each other. Please only specify one`
456
+ `The options ${presentOptionNames.map(formatOption).join(", ")} are aliases for each other. Please only specify one`
376
457
  )
377
458
  process.exit(1)
378
459
  }
379
460
  const value = options.get(presentOptionNames[0])
380
461
  options.delete(presentOptionNames[0])
381
- return { name: presentOptionNamesWithDashDash[0], value }
462
+ return { name: presentOptionNames[0], value }
463
+ }
464
+ function complainAboutUnrecognisedOptions() {
465
+ if (options.size) {
466
+ logError(
467
+ `Unrecognised option${options.size > 1 ? "s" : ""}: ${[...options.keys()].map(formatOption).join(", ")}`
468
+ )
469
+ process.exit(1)
470
+ }
382
471
  }