hackmud-script-manager 0.20.4-a7d8309 → 0.20.4-ae3052c

Sign up to get free protection for your applications and to get access to all the features.
package/bin/hsm.js CHANGED
@@ -24,16 +24,16 @@ const formatOption = name => colourN(`-${1 == name.length ? "" : "-"}${name}`),
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)
@@ -62,9 +62,10 @@ process.version.startsWith("v21.") &&
62
62
  )
63
63
  )
64
64
  if ("v" == commands[0] || "version" == commands[0] || popOption("version", "v")?.value) {
65
- console.log("0.20.4-a7d8309")
65
+ console.log("0.20.4-ae3052c")
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,10 +78,18 @@ 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
95
  `Options ${formatOption(noMinifyOption.name)} and ${formatOption(noMinifyIncompatibleOption.name)} are incompatible\n`
@@ -88,9 +97,17 @@ switch (commands[0]) {
88
97
  logHelp()
89
98
  process.exit(1)
90
99
  }
100
+ if (forceQuineCheatsOption && noQuineCheatsOptions) {
101
+ logError(
102
+ `Options ${formatOption(forceQuineCheatsOption.name)} and ${formatOption(noQuineCheatsOptions.name)} are incompatible\n`
103
+ )
104
+ logHelp()
105
+ process.exit(1)
106
+ }
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]
@@ -135,11 +152,10 @@ switch (commands[0]) {
135
152
  scriptName,
136
153
  filePath: target,
137
154
  mangleNames: mangleNamesOption?.value,
138
- forceQuineCheats: forceQuineCheatsOption?.value
155
+ forceQuineCheats: forceQuineCheatsOption?.value ?? !noQuineCheatsOptions?.value
139
156
  }),
140
157
  timeTook = performance.now() - timeStart
141
- for (const { message, line } of warnings)
142
- log(`Warning "${chalk.bold(message)}" on line ${chalk.bold(line + "")}`)
158
+ for (const { message } of warnings) log("Warning: " + chalk.bold(message))
143
159
  await writeFilePersistent(outputPath, script)
144
160
  .catch(error => {
145
161
  if (!commands[2] || "EISDIR" != error.code) throw error
@@ -178,28 +194,8 @@ switch (commands[0]) {
178
194
  process.exit(1)
179
195
  }
180
196
  } else scripts.push("*.*")
181
- if ("push" == commands[0]) {
182
- const { push, MissingSourceFolderError, MissingHackmudFolderError, NoUsersError } = await pushModule
183
- complainAboutUnrecognisedOptions()
184
- const infos = await push(sourcePath, hackmudPath, {
185
- scripts,
186
- onPush: info => logInfo(info, hackmudPath),
187
- minify: noMinifyOption && !noMinifyOption.value,
188
- mangleNames: mangleNamesOption?.value,
189
- forceQuineCheats: forceQuineCheatsOption?.value
190
- })
191
- if (infos instanceof Error) {
192
- logError(infos.message)
193
- if (infos instanceof MissingSourceFolderError || infos instanceof NoUsersError) {
194
- console.log()
195
- logHelp()
196
- } else
197
- infos instanceof MissingHackmudFolderError &&
198
- log(
199
- `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`
200
- )
201
- } else infos.length || logError("Could not find any scripts to push")
202
- } else {
197
+ const watchOption = popOption("watch")
198
+ if ("push" != commands[0] || watchOption?.value) {
203
199
  const dtsPathOption = popOption(
204
200
  "dts-path",
205
201
  "type-declaration-path",
@@ -208,11 +204,11 @@ switch (commands[0]) {
208
204
  "gen-types"
209
205
  )
210
206
  dtsPathOption &&
211
- "emit-dts" != dtsPathOption.name &&
212
- "gen-dts" != dtsPathOption.name &&
207
+ "dts-path" != dtsPathOption.name &&
208
+ "type-declaration-path" != dtsPathOption.name &&
213
209
  console.warn(
214
210
  colourF(
215
- `Warning: ${colourN(dtsPathOption.name)} is being 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`
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`
216
212
  )
217
213
  )
218
214
  complainAboutUnrecognisedOptions()
@@ -224,9 +220,54 @@ switch (commands[0]) {
224
220
  minify: noMinifyOption && !noMinifyOption.value,
225
221
  mangleNames: mangleNamesOption?.value,
226
222
  onReady: () => log("Watching"),
227
- forceQuineCheats: forceQuineCheatsOption?.value
223
+ forceQuineCheats: forceQuineCheatsOption?.value ?? !noQuineCheatsOptions?.value
228
224
  })
229
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
+ }
249
+ const { push, MissingSourceFolderError, MissingHackmudFolderError, NoUsersError } =
250
+ await pushModule,
251
+ infos = await push(sourcePath, hackmudPath, {
252
+ scripts,
253
+ onPush: info => logInfo(info, hackmudPath),
254
+ minify: noMinifyOption && !noMinifyOption.value,
255
+ mangleNames: mangleNamesOption?.value,
256
+ forceQuineCheats: forceQuineCheatsOption?.value ?? !noQuineCheatsOptions?.value
257
+ })
258
+ if (infos instanceof Error) {
259
+ logError(infos.message)
260
+ if (infos instanceof MissingSourceFolderError || infos instanceof NoUsersError) {
261
+ console.log()
262
+ logHelp()
263
+ } else
264
+ infos instanceof MissingHackmudFolderError &&
265
+ log(
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`
267
+ )
268
+ } else infos.length || logError("Could not find any scripts to push")
269
+ declarationPathPromise &&
270
+ log("Wrote type declaration to " + chalk.bold(await declarationPathPromise))
230
271
  }
231
272
  }
232
273
  }
@@ -262,13 +303,14 @@ switch (commands[0]) {
262
303
  case "gen-types":
263
304
  case "emit-dts":
264
305
  {
265
- "emit-dts" != commands[0] &&
266
- "gen-dts" != commands[0] &&
306
+ if ("emit-dts" != commands[0] && "gen-dts" != commands[0]) {
307
+ warnedDeprecatedEmitDtsAlias = !0
267
308
  console.warn(
268
309
  colourF(
269
- `Warning: ${colourC("hsm")} ${colourL(commands[0])} is being 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`
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`
270
311
  )
271
312
  )
313
+ }
272
314
  const hackmudPath = getHackmudPath(),
273
315
  target = commands[1]
274
316
  if (!target) {
@@ -282,7 +324,7 @@ switch (commands[0]) {
282
324
  typeDeclaration = await generateTypeDeclaration(sourcePath, hackmudPath)
283
325
  let typeDeclarationPath = resolve(outputPath)
284
326
  await writeFile(typeDeclarationPath, typeDeclaration).catch(error => {
285
- assert(error instanceof Error, "src/bin/hsm.ts:361:35")
327
+ assert(error instanceof Error, "src/bin/hsm.ts:422:35")
286
328
  if ("EISDIR" != error.code) throw error
287
329
  typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
288
330
  return writeFile(typeDeclarationPath, typeDeclaration)
@@ -300,7 +342,6 @@ switch (commands[0]) {
300
342
  autoExit && process.exit()
301
343
  function logHelp() {
302
344
  const pushCommandDescription = "Push scripts from a directory to hackmud user's scripts directories",
303
- forceQuineCheatsOptionDescription = `Force quine cheats on. Use ${colourN("--force-quine-cheats")}=${colourV("false")} to force off`,
304
345
  hackmudPathOption = `${colourN("--hackmud-path")}=${colourB("<path>")}\n Override hackmud path`
305
346
  switch (commands[0]) {
306
347
  case "dev":
@@ -308,7 +349,7 @@ function logHelp() {
308
349
  case "push":
309
350
  console.log(
310
351
  colourS(
311
- `${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("--dts-path")}=${colourB("<path>")}\n Path to generate a type declaration (.d.ts) 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`
312
353
  )
313
354
  )
314
355
  break
@@ -323,7 +364,7 @@ function logHelp() {
323
364
  case "golf":
324
365
  console.log(
325
366
  colourS(
326
- `${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`
327
368
  )
328
369
  )
329
370
  break
@@ -332,11 +373,12 @@ function logHelp() {
332
373
  case "gen-dts":
333
374
  case "gen-types":
334
375
  case "emit-dts":
335
- "emit-dts" != commands[0] &&
336
- "gen-dts" != commands[0] &&
376
+ warnedDeprecatedEmitDtsAlias ||
377
+ "emit-dts" == commands[0] ||
378
+ "gen-dts" == commands[0] ||
337
379
  console.warn(
338
380
  colourF(
339
- `Warning: ${colourC("hsm")} ${colourL(commands[0])} is being 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`
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`
340
382
  )
341
383
  )
342
384
  console.log(
@@ -355,35 +397,49 @@ function logHelp() {
355
397
  default:
356
398
  console.log(
357
399
  colourS(
358
- `${colourJ("Hackmud Script Manager")}\n${colourN("Version") + colourS(": ") + colourV("0.20.4-a7d8309")}\n\n${colourA("Commands:")}\n${colourL("push")}\n ${pushCommandDescription}\n${colourL("dev")}\n Watch a directory and push a script when modified\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`
400
+ `${colourJ("Hackmud Script Manager")}\n${colourN("Version") + colourS(": ") + colourV("0.20.4-ae3052c")}\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`
359
401
  )
360
402
  )
361
403
  }
362
404
  }
363
- function logInfo({ path, users, characterCount, error }, hackmudPath) {
405
+ function logInfo({ path, users, characterCount, error, warnings }, hackmudPath) {
364
406
  path = relative(".", path)
365
- error ?
366
- logError(`Error "${chalk.bold(error.message)}" in ${chalk.bold(path)}`)
367
- : 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(
368
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")}`
369
412
  )
413
+ }
370
414
  }
371
415
  function logError(message) {
372
416
  console.error(colourD(message))
373
417
  process.exitCode = 1
374
418
  }
375
419
  function getHackmudPath() {
376
- const hackmudPathOption = popOption("hackmud-path")?.value
377
- if (null != hackmudPathOption && "string" != typeof hackmudPathOption) {
378
- logError(`Option ${colourN("--hackmud-path")} must be a string, got ${colourV(hackmudPathOption)}\n`)
379
- logHelp()
380
- process.exit(1)
420
+ const hackmudPathOption = popOption("hackmud-path")
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
381
433
  }
382
- return (
383
- hackmudPathOption ||
384
- process.env.HSM_HACKMUD_PATH ||
385
- ("win32" == process.platform ? resolve(process.env.APPDATA, "hackmud") : resolve(homedir(), ".config/hackmud"))
386
- )
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")
387
443
  }
388
444
  function assertOptionIsBoolean(option) {
389
445
  if ("boolean" != typeof option.value) {
@@ -395,16 +451,15 @@ function assertOptionIsBoolean(option) {
395
451
  function popOption(...names) {
396
452
  const presentOptionNames = names.filter(name => options.has(name))
397
453
  if (!presentOptionNames.length) return
398
- const presentOptionNamesWithDashDash = presentOptionNames.map(formatOption)
399
454
  if (presentOptionNames.length > 1) {
400
455
  logError(
401
- `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`
402
457
  )
403
458
  process.exit(1)
404
459
  }
405
460
  const value = options.get(presentOptionNames[0])
406
461
  options.delete(presentOptionNames[0])
407
- return { name: presentOptionNamesWithDashDash[0], value }
462
+ return { name: presentOptionNames[0], value }
408
463
  }
409
464
  function complainAboutUnrecognisedOptions() {
410
465
  if (options.size) {
package/env.d.ts CHANGED
@@ -1046,6 +1046,9 @@ declare global {
1046
1046
  * In rare cases where it's not known at build time, it's `"UNKNOWN"`. */
1047
1047
  const _SCRIPT_USER: string
1048
1048
 
1049
+ /** @deprecated Use `_SCRIPT_SUBNAME` instead. */
1050
+ const _SCRIPT_NAME: string
1051
+
1049
1052
  /** The name of this script excluding the user and `.`.
1050
1053
  *
1051
1054
  * e.g. in the script `foo.bar`, `_SCRIPT_NAME` is `bar`.
@@ -1053,7 +1056,7 @@ declare global {
1053
1056
  * Shorter alternative to `context.this_script.split(".")[1].
1054
1057
  *
1055
1058
  * In rare cases where it's not known at build time, it's `"UNKNOWN"`. */
1056
- const _SCRIPT_NAME: string
1059
+ const _SCRIPT_SUBNAME: string
1057
1060
 
1058
1061
  /** The full name of this script equivilent to `context.this_script` but should use less characters.
1059
1062
  *
package/index.d.ts CHANGED
@@ -10,4 +10,7 @@ export type Info = {
10
10
  users: string[];
11
11
  characterCount: number;
12
12
  error: Error | undefined;
13
+ warnings: {
14
+ message: string;
15
+ }[];
13
16
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hackmud-script-manager",
3
- "version": "0.20.4-a7d8309",
3
+ "version": "0.20.4-ae3052c",
4
4
  "description": "Script manager for game hackmud, with minification, TypeScript support, and player script type definition generation.",
5
5
  "keywords": [
6
6
  "api",
@@ -26,6 +26,5 @@ export declare function processScript(code: string, { minify: shouldMinify, uniq
26
26
  script: string;
27
27
  warnings: {
28
28
  message: string;
29
- line: number;
30
29
  }[];
31
30
  }>;
@@ -234,7 +234,7 @@ async function processScript(
234
234
  }),
235
235
  seclevelNames = ["NULLSEC", "LOWSEC", "MIDSEC", "HIGHSEC", "FULLSEC"]
236
236
  code = (await bundle.generate({})).output[0].code
237
- const { file, seclevel } = transform(parse(code, { sourceType: "module" }), sourceCode, {
237
+ const { file, seclevel, warnings } = transform(parse(code, { sourceType: "module" }), sourceCode, {
238
238
  uniqueId,
239
239
  scriptUser,
240
240
  scriptName
@@ -328,6 +328,6 @@ async function processScript(
328
328
  throw Error(
329
329
  'you found a weird edge case where I wasn\'t able to replace illegal strings like "SC$", please report thx'
330
330
  )
331
- return { script: code, warnings: [] }
331
+ return { script: code, warnings }
332
332
  }
333
333
  export { minify, postprocess, preprocess, processScript, transform }
@@ -16,4 +16,7 @@ export type TransformOptions = LaxPartial<{
16
16
  export declare function transform(file: File, sourceCode: string, { uniqueId, scriptUser, scriptName, seclevel }: TransformOptions): {
17
17
  file: File;
18
18
  seclevel: number;
19
+ warnings: {
20
+ message: string;
21
+ }[];
19
22
  };
@@ -22,7 +22,8 @@ const { default: traverse } = babelTraverse,
22
22
  "BigInt"
23
23
  ]
24
24
  function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scriptName, seclevel = 4 }) {
25
- const topFunctionName = `_${uniqueId}_SCRIPT_`
25
+ const warnings = [],
26
+ topFunctionName = `_${uniqueId}_SCRIPT_`
26
27
  let program
27
28
  traverse(file, {
28
29
  Program(path) {
@@ -44,9 +45,17 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
44
45
  referencePath.replaceWith(t.identifier(`_${uniqueId}_SCRIPT_USER_`))
45
46
  } else
46
47
  referencePath.replaceWith(t.stringLiteral(1 == scriptUser ? `$${uniqueId}$SCRIPT_USER$` : scriptUser))
47
- if (program.scope.hasGlobal("_SCRIPT_NAME"))
48
+ if (program.scope.hasGlobal("_SCRIPT_NAME")) {
49
+ warnings.push({
50
+ message:
51
+ "Global _SCRIPT_NAME is deprecated and will be removed in the next minor release of HSM, use _SCRIPT_SUBNAME instead"
52
+ })
48
53
  for (const referencePath of getReferencePathsToGlobal("_SCRIPT_NAME", program))
49
54
  referencePath.replaceWith(t.stringLiteral(1 == scriptName ? `$${uniqueId}$SCRIPT_NAME$` : scriptName))
55
+ }
56
+ if (program.scope.hasGlobal("_SCRIPT_SUBNAME"))
57
+ for (const referencePath of getReferencePathsToGlobal("_SCRIPT_SUBNAME", program))
58
+ referencePath.replaceWith(t.stringLiteral(1 == scriptName ? `$${uniqueId}$SCRIPT_NAME$` : scriptName))
50
59
  if (program.scope.hasGlobal("_FULL_SCRIPT_NAME"))
51
60
  for (const referencePath of getReferencePathsToGlobal("_FULL_SCRIPT_NAME", program))
52
61
  if (1 == scriptUser || 1 == scriptName)
@@ -68,30 +77,30 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
68
77
  const referencePath = FunctionReferencePaths[0]
69
78
  assert(
70
79
  "MemberExpression" == referencePath.parent.type,
71
- "src/processScript/transform.ts:103:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
80
+ "src/processScript/transform.ts:111:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
72
81
  )
73
82
  assert(
74
83
  "Identifier" == referencePath.parent.property.type,
75
- "src/processScript/transform.ts:108:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
84
+ "src/processScript/transform.ts:116:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
76
85
  )
77
86
  assert(
78
87
  "prototype" == referencePath.parent.property.name,
79
- "src/processScript/transform.ts:113:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
88
+ "src/processScript/transform.ts:121:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
80
89
  )
81
90
  referencePath.parentPath.replaceWith(createGetFunctionPrototypeNode())
82
91
  } else {
83
92
  for (const referencePath of FunctionReferencePaths) {
84
93
  assert(
85
94
  "MemberExpression" == referencePath.parent.type,
86
- "src/processScript/transform.ts:121:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
95
+ "src/processScript/transform.ts:129:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
87
96
  )
88
97
  assert(
89
98
  "Identifier" == referencePath.parent.property.type,
90
- "src/processScript/transform.ts:126:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
99
+ "src/processScript/transform.ts:134:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
91
100
  )
92
101
  assert(
93
102
  "prototype" == referencePath.parent.property.name,
94
- "src/processScript/transform.ts:131:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
103
+ "src/processScript/transform.ts:139:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
95
104
  )
96
105
  functionDotPrototypeIsReferencedMultipleTimes = !0
97
106
  referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_FUNCTION_DOT_PROTOTYPE_`))
@@ -127,12 +136,12 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
127
136
  const neededDbMethodLets = new Set()
128
137
  if (program.scope.hasGlobal("$db"))
129
138
  for (const referencePath of getReferencePathsToGlobal("$db", program)) {
130
- assert("MemberExpression" == referencePath.parentPath.node.type, "src/processScript/transform.ts:185:69")
131
- assert("Identifier" == referencePath.parentPath.node.property.type, "src/processScript/transform.ts:186:72")
139
+ assert("MemberExpression" == referencePath.parentPath.node.type, "src/processScript/transform.ts:193:69")
140
+ assert("Identifier" == referencePath.parentPath.node.property.type, "src/processScript/transform.ts:194:72")
132
141
  const databaseOpMethodName = referencePath.parentPath.node.property.name
133
142
  assert(
134
143
  validDBMethods.includes(databaseOpMethodName),
135
- `src/processScript/transform.ts:192:8 invalid db method "${databaseOpMethodName}", valid db methods are "${validDBMethods.join('", "')}"`
144
+ `src/processScript/transform.ts:200:8 invalid db method "${databaseOpMethodName}", valid db methods are "${validDBMethods.join('", "')}"`
136
145
  )
137
146
  if ("CallExpression" == referencePath.parentPath.parentPath?.type)
138
147
  referencePath.parentPath.replaceWith(t.identifier(`$${uniqueId}$DB$${databaseOpMethodName}$`))
@@ -167,7 +176,7 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
167
176
  if (program.scope.hasGlobal("Object"))
168
177
  for (const referencePath of getReferencePathsToGlobal("Object", program))
169
178
  if ("MemberExpression" == referencePath.parent.type && !referencePath.parent.computed) {
170
- assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:242:64")
179
+ assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:250:64")
171
180
  if ("getPrototypeOf" == referencePath.parent.property.name) {
172
181
  referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_GET_PROTOTYPE_OF_`))
173
182
  needGetPrototypeOf = !0
@@ -180,7 +189,7 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
180
189
  if (program.scope.hasGlobal("console"))
181
190
  for (const referencePath of getReferencePathsToGlobal("console", program))
182
191
  if ("MemberExpression" == referencePath.parent.type && !referencePath.parent.computed) {
183
- assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:260:64")
192
+ assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:268:64")
184
193
  referencePath.parentPath.replaceWith(
185
194
  t.identifier(`_${uniqueId}_CONSOLE_METHOD_${referencePath.parent.property.name}_`)
186
195
  )
@@ -188,13 +197,13 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
188
197
  }
189
198
  const lastStatement = program.node.body.at(-1)
190
199
  let exportDefaultName
191
- assert(lastStatement, "src/processScript/transform.ts:274:27 program is empty")
200
+ assert(lastStatement, "src/processScript/transform.ts:282:27 program is empty")
192
201
  if ("ExportNamedDeclaration" == lastStatement.type) {
193
202
  program.node.body.pop()
194
203
  for (const specifier of lastStatement.specifiers) {
195
204
  assert(
196
205
  "ExportSpecifier" == specifier.type,
197
- `src/processScript/transform.ts:280:51 ${specifier.type} is currently unsupported`
206
+ `src/processScript/transform.ts:288:51 ${specifier.type} is currently unsupported`
198
207
  )
199
208
  if (
200
209
  "default" !=
@@ -296,11 +305,11 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
296
305
  let hoistedGlobalBlockFunctions = 0
297
306
  for (const [globalBlockIndex, globalBlockStatement] of [...globalBlock.body.entries()].reverse())
298
307
  if ("VariableDeclaration" == globalBlockStatement.type) {
299
- assert(1 == globalBlockStatement.declarations.length, "src/processScript/transform.ts:394:59")
308
+ assert(1 == globalBlockStatement.declarations.length, "src/processScript/transform.ts:402:59")
300
309
  const declarator = globalBlockStatement.declarations[0]
301
310
  assert(
302
311
  "Identifier" == declarator.id.type,
303
- `src/processScript/transform.ts:398:51 declarator.id.type was "${declarator.id.type}"`
312
+ `src/processScript/transform.ts:406:51 declarator.id.type was "${declarator.id.type}"`
304
313
  )
305
314
  program.scope.crawl()
306
315
  if (program.scope.hasGlobal(declarator.id.name)) {
@@ -315,9 +324,9 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
315
324
  Object.keys(program.scope.globals).some(global => globalBlockVariables.has(global))
316
325
  ) {
317
326
  const binding = program.scope.getBinding(declarator.id.name)
318
- assert(binding, "src/processScript/transform.ts:417:23")
327
+ assert(binding, "src/processScript/transform.ts:425:23")
319
328
  for (const referencePath of binding.referencePaths) {
320
- assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:420:56")
329
+ assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:428:56")
321
330
  referencePath.replaceWith(
322
331
  t.memberExpression(
323
332
  t.identifier(`_${uniqueId}_G_`),
@@ -365,16 +374,16 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
365
374
  } else globalBlockVariables.add(declarator.id.name)
366
375
  } else if ("ClassDeclaration" == globalBlockStatement.type) {
367
376
  program.scope.crawl()
368
- assert(globalBlockStatement.id, "src/processScript/transform.ts:477:37")
377
+ assert(globalBlockStatement.id, "src/processScript/transform.ts:485:37")
369
378
  if (program.scope.hasGlobal(globalBlockStatement.id.name)) {
370
379
  globalBlock.body.splice(globalBlockIndex, 1)
371
380
  const [globalBlockPath] = program.unshiftContainer("body", globalBlock),
372
381
  [globalBlockStatementPath] = program.unshiftContainer("body", globalBlockStatement)
373
382
  program.scope.crawl()
374
383
  const binding = program.scope.getBinding(globalBlockStatement.id.name)
375
- assert(binding, "src/processScript/transform.ts:489:22")
384
+ assert(binding, "src/processScript/transform.ts:497:22")
376
385
  for (const referencePath of binding.referencePaths) {
377
- assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:492:55")
386
+ assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:500:55")
378
387
  referencePath.replaceWith(
379
388
  t.memberExpression(t.identifier(`_${uniqueId}_G_`), t.identifier(referencePath.node.name))
380
389
  )
@@ -566,7 +575,7 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
566
575
  }
567
576
  },
568
577
  ClassBody({ node: classBody, scope, parent }) {
569
- assert(t.isClass(parent), "src/processScript/transform.ts:687:30")
578
+ assert(t.isClass(parent), "src/processScript/transform.ts:695:30")
570
579
  let thisIsReferenced = !1
571
580
  for (const classMethod of classBody.body) {
572
581
  if ("ClassMethod" != classMethod.type) continue
@@ -656,7 +665,7 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
656
665
  )
657
666
  }
658
667
  })
659
- return { file, seclevel }
668
+ return { file, seclevel, warnings }
660
669
  function createGetFunctionPrototypeNode() {
661
670
  const name = globalFunctionsUnder7Characters.find(name => !program.scope.hasOwnBinding(name))
662
671
  return t.memberExpression(
@@ -666,23 +675,23 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
666
675
  }
667
676
  function processFakeSubscriptObject(fakeSubscriptObjectName, seclevel) {
668
677
  for (const referencePath of getReferencePathsToGlobal(fakeSubscriptObjectName, program)) {
669
- assert("MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:793:60")
678
+ assert("MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:801:60")
670
679
  assert("Identifier" == referencePath.parent.property.type)
671
680
  assert(
672
681
  "MemberExpression" == referencePath.parentPath.parentPath?.node.type,
673
- "src/processScript/transform.ts:795:81"
682
+ "src/processScript/transform.ts:803:81"
674
683
  )
675
684
  assert(
676
685
  "Identifier" == referencePath.parentPath.parentPath.node.property.type,
677
- "src/processScript/transform.ts:796:83"
686
+ "src/processScript/transform.ts:804:83"
678
687
  )
679
688
  assert(
680
689
  /^[_a-z][\d_a-z]{0,24}$/.test(referencePath.parent.property.name),
681
- `src/processScript/transform.ts:800:8 invalid user "${referencePath.parent.property.name}" in subscript`
690
+ `src/processScript/transform.ts:808:8 invalid user "${referencePath.parent.property.name}" in subscript`
682
691
  )
683
692
  assert(
684
693
  /^[_a-z][\d_a-z]{0,24}$/.test(referencePath.parentPath.parentPath.node.property.name),
685
- `src/processScript/transform.ts:805:8 invalid script name "${referencePath.parentPath.parentPath.node.property.name}" in subscript`
694
+ `src/processScript/transform.ts:813:8 invalid script name "${referencePath.parentPath.parentPath.node.property.name}" in subscript`
686
695
  )
687
696
  if ("CallExpression" == referencePath.parentPath.parentPath.parentPath?.type)
688
697
  referencePath.parentPath.parentPath.replaceWith(
package/push.js CHANGED
@@ -131,7 +131,7 @@ async function push(
131
131
  uniqueId = Math.floor(Math.random() * 2 ** 52)
132
132
  .toString(36)
133
133
  .padStart(11, "0"),
134
- { script: minifiedCode } = await processScript(await readFile(path, { encoding: "utf8" }), {
134
+ { script: minifiedCode, warnings } = await processScript(await readFile(path, { encoding: "utf8" }), {
135
135
  minify,
136
136
  scriptUser: !0,
137
137
  scriptName,
@@ -140,7 +140,7 @@ async function push(
140
140
  mangleNames,
141
141
  forceQuineCheats
142
142
  }),
143
- info = { path, users, characterCount: countHackmudCharacters(minifiedCode), error: void 0 }
143
+ info = { path, users, characterCount: countHackmudCharacters(minifiedCode), error: void 0, warnings }
144
144
  await Promise.all(
145
145
  users.map(user =>
146
146
  writeFilePersistent(
package/watch.js CHANGED
@@ -73,10 +73,11 @@ async function watch(
73
73
  : scriptName && "*" != scriptName ? wildUserScripts.add(scriptName)
74
74
  : (pushEverything = !0)
75
75
  }
76
- const watcher = watch$1(["*.ts", "*.js", "*/*.ts", "*/*.js"], {
76
+ const watcher = watch$1(".", {
77
77
  cwd: sourceDirectory,
78
78
  awaitWriteFinish: { stabilityThreshold: 100 },
79
- ignored: "*.d.ts"
79
+ ignored: (path, stats) =>
80
+ !!stats?.isFile() && !(path.endsWith(".js") || (path.endsWith(".ts") && !path.endsWith(".d.ts")))
80
81
  }).on("change", async path => {
81
82
  if (path.endsWith(".d.ts")) return
82
83
  const extension = extname(path)
@@ -118,27 +119,22 @@ async function watch(
118
119
  for (const user of scriptNamesToUsers.get(scriptName)) usersToPushToSet.add(user)
119
120
  const usersToPushTo = [...usersToPushToSet].filter(user => !scriptNamesToUsersToSkip.has(user))
120
121
  if (!usersToPushTo.length) {
121
- onPush?.({ path, users: [], characterCount: 0, error: Error("no users to push to") })
122
+ onPush?.({ path, users: [], characterCount: 0, error: Error("no users to push to"), warnings: [] })
122
123
  return
123
124
  }
124
125
  const uniqueId = Math.floor(Math.random() * 2 ** 52)
125
126
  .toString(36)
126
127
  .padStart(11, "0"),
127
128
  filePath = resolve(sourceDirectory, path)
128
- let minifiedCode
129
+ let minifiedCode, warnings
129
130
  try {
130
- ;({ script: minifiedCode } = await processScript(await readFile(filePath, { encoding: "utf8" }), {
131
- minify,
132
- scriptUser: !0,
133
- scriptName,
134
- uniqueId,
135
- filePath,
136
- mangleNames,
137
- forceQuineCheats
138
- }))
131
+ ;({ script: minifiedCode, warnings } = await processScript(
132
+ await readFile(filePath, { encoding: "utf8" }),
133
+ { minify, scriptUser: !0, scriptName, uniqueId, filePath, mangleNames, forceQuineCheats }
134
+ ))
139
135
  } catch (error) {
140
- assert(error instanceof Error, "src/watch.ts:146:36")
141
- onPush?.({ path, users: [], characterCount: 0, error })
136
+ assert(error instanceof Error, "src/watch.ts:149:36")
137
+ onPush?.({ path, users: [], characterCount: 0, error, warnings: [] })
142
138
  return
143
139
  }
144
140
  await Promise.all(
@@ -155,7 +151,8 @@ async function watch(
155
151
  path,
156
152
  users: usersToPushTo,
157
153
  characterCount: countHackmudCharacters(minifiedCode),
158
- error: void 0
154
+ error: void 0,
155
+ warnings
159
156
  })
160
157
  return
161
158
  }
@@ -171,9 +168,9 @@ async function watch(
171
168
  return
172
169
  const filePath = resolve(sourceDirectory, path),
173
170
  sourceCode = await readFile(filePath, { encoding: "utf8" })
174
- let script
171
+ let script, warnings
175
172
  try {
176
- ;({ script } = await processScript(sourceCode, {
173
+ ;({ script, warnings } = await processScript(sourceCode, {
177
174
  minify,
178
175
  scriptUser: user,
179
176
  scriptName,
@@ -182,12 +179,12 @@ async function watch(
182
179
  forceQuineCheats
183
180
  }))
184
181
  } catch (error) {
185
- assert(error instanceof Error, "src/watch.ts:182:35")
186
- onPush?.({ path, users: [], characterCount: 0, error })
182
+ assert(error instanceof Error, "src/watch.ts:190:35")
183
+ onPush?.({ path, users: [], characterCount: 0, error, warnings: [] })
187
184
  return
188
185
  }
189
186
  await writeFilePersistent(resolve(hackmudDirectory, user, "scripts", scriptName + ".js"), script)
190
- onPush?.({ path, users: [user], characterCount: countHackmudCharacters(script), error: void 0 })
187
+ onPush?.({ path, users: [user], characterCount: countHackmudCharacters(script), error: void 0, warnings })
191
188
  })
192
189
  onReady && watcher.on("ready", onReady)
193
190
  if (!typeDeclarationPath_) return
@@ -197,7 +194,7 @@ async function watch(
197
194
  try {
198
195
  await writeFile(typeDeclarationPath, typeDeclaration)
199
196
  } catch (error) {
200
- assert(error instanceof Error, "src/watch.ts:215:35")
197
+ assert(error instanceof Error, "src/watch.ts:223:35")
201
198
  if ("EISDIR" != error.code) throw error
202
199
  typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
203
200
  await writeFile(typeDeclarationPath, typeDeclaration)