hackmud-script-manager 0.20.4-67aeb81 → 0.20.4-6a2a079

Sign up to get free protection for your applications and to get access to all the features.
package/bin/hsm.js CHANGED
@@ -5,14 +5,16 @@ import { countHackmudCharacters } from "@samual/lib/countHackmudCharacters"
5
5
  import { writeFilePersistent } from "@samual/lib/writeFilePersistent"
6
6
  import { writeFile, readFile } from "fs/promises"
7
7
  import { homedir } from "os"
8
- import { extname, basename, resolve, dirname, relative } from "path"
8
+ import { resolve, extname, basename, dirname, relative } from "path"
9
9
  import { supportedExtensions } from "../constants.js"
10
10
  import { generateTypeDeclaration } from "../generateTypeDeclaration.js"
11
11
  import { pull } from "../pull.js"
12
12
  import { syncMacros } from "../syncMacros.js"
13
13
  import "@samual/lib/readDirectoryWithStats"
14
+ import "path/posix"
14
15
  import "@samual/lib/copyFilePersistent"
15
- const version = "0.20.4-67aeb81",
16
+ const version = "0.20.4-6a2a079",
17
+ formatOption = name => colourN(`-${1 == name.length ? "" : "-"}${name}`),
16
18
  options = new Map(),
17
19
  commands = [],
18
20
  userColours = new Cache(user => {
@@ -36,10 +38,6 @@ for (const argument of process.argv.slice(2))
36
38
  if ("-" == argument[1]) options.set(key.slice(2), value)
37
39
  else for (const option of key.slice(1)) options.set(option, value)
38
40
  } else commands.push(argument)
39
- if ("v" == commands[0] || "version" == commands[0] || options.get("version") || options.get("v")) {
40
- console.log(version)
41
- process.exit()
42
- }
43
41
  const pushModule = import("../push.js"),
44
42
  processScriptModule = import("../processScript/index.js"),
45
43
  watchModule = import("../watch.js"),
@@ -49,6 +47,7 @@ const pushModule = import("../push.js"),
49
47
  colourB = chalk.rgb(202, 202, 202),
50
48
  colourC = chalk.rgb(155, 155, 155),
51
49
  colourD = chalk.rgb(255, 0, 0),
50
+ colourF = chalk.rgb(255, 128, 0),
52
51
  colourJ = chalk.rgb(255, 244, 4),
53
52
  colourK = chalk.rgb(243, 249, 152),
54
53
  colourL = chalk.rgb(30, 255, 0),
@@ -57,162 +56,171 @@ const pushModule = import("../push.js"),
57
56
  colourS = chalk.rgb(122, 178, 244),
58
57
  colourV = chalk.rgb(255, 0, 236),
59
58
  colourW = chalk.rgb(255, 150, 224)
60
- if (options.get("help") || options.get("h")) {
59
+ process.version.startsWith("v21.") &&
60
+ console.warn(
61
+ colourF(
62
+ "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"
63
+ )
64
+ )
65
+ if ("v" == commands[0] || "version" == commands[0] || popOption("version", "v")?.value) {
66
+ console.log(version)
67
+ process.exit()
68
+ }
69
+ if (popOption("help", "h")?.value) {
61
70
  logHelp()
62
71
  process.exit()
63
72
  }
64
73
  let autoExit = !0
65
74
  switch (commands[0]) {
66
75
  case "push":
76
+ case "dev":
77
+ case "watch":
78
+ case "golf":
79
+ case "minify":
67
80
  {
68
- const hackmudPath = getHackmudPath(),
69
- sourcePath = commands[1]
70
- if (!sourcePath) {
71
- logError("Must provide the directory to push from\n")
72
- logHelp()
73
- break
74
- }
75
- const scripts = commands.slice(2)
76
- if (scripts.length) {
77
- const invalidScript = scripts.find(
78
- script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script)
79
- )
80
- if (invalidScript) {
81
- logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`)
82
- logHelp()
83
- break
84
- }
85
- } else scripts.push("*.*")
86
- const optionsHasNoMinify = options.has("no-minify")
87
- if ((optionsHasNoMinify || options.has("skip-minify")) && options.has("mangle-names")) {
81
+ const noMinifyOption = popOption("no-minify", "skip-minify"),
82
+ mangleNamesOption = popOption("mangle-names"),
83
+ forceQuineCheatsOption = popOption("force-quine-cheats"),
84
+ noMinifyIncompatibleOption = mangleNamesOption || forceQuineCheatsOption
85
+ if (noMinifyOption && noMinifyIncompatibleOption) {
88
86
  logError(
89
- `Options ${colourN("--mangle-names")} and ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} are incompatible\n`
87
+ `Options ${formatOption(noMinifyOption.name)} and ${formatOption(noMinifyIncompatibleOption.name)} are incompatible\n`
90
88
  )
91
89
  logHelp()
92
- break
90
+ process.exit(1)
93
91
  }
94
- const shouldSkipMinify = options.get("no-minify") || options.get("skip-minify")
95
- let shouldMinify
96
- if (null != shouldSkipMinify) {
97
- if ("boolean" != typeof shouldSkipMinify) {
92
+ noMinifyOption && assertOptionIsBoolean(noMinifyOption)
93
+ mangleNamesOption && assertOptionIsBoolean(mangleNamesOption)
94
+ forceQuineCheatsOption && assertOptionIsBoolean(forceQuineCheatsOption)
95
+ if ("golf" == commands[0] || "minify" == commands[0]) {
96
+ const watchOption = popOption("watch"),
97
+ target = commands[1]
98
+ if (!target) {
99
+ logError("Must provide target\n")
100
+ logHelp()
101
+ process.exit(1)
102
+ }
103
+ const fileExtension = extname(target)
104
+ if (!supportedExtensions.includes(fileExtension)) {
98
105
  logError(
99
- `The value for ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} must be ${colourV("true")} or ${colourV("false")}\n`
106
+ `Unsupported file extension "${chalk.bold(fileExtension)}"\nSupported extensions are "${supportedExtensions.map(extension => chalk.bold(extension)).join('", "')}"`
100
107
  )
101
- logHelp()
102
- break
108
+ process.exit(1)
103
109
  }
104
- shouldMinify = !shouldSkipMinify
105
- }
106
- const shouldMangleNames = options.get("mangle-names")
107
- if (null != shouldMangleNames && "boolean" != typeof shouldMangleNames) {
108
- logError(
109
- `The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
110
- )
111
- logHelp()
112
- break
113
- }
114
- const shouldforceQuineCheats = options.get("force-quine-cheats")
115
- if (null != shouldforceQuineCheats && "boolean" != typeof shouldforceQuineCheats) {
116
- logError(
117
- `The value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
118
- )
119
- logHelp()
120
- break
121
- }
122
- const { push, MissingSourceFolderError, MissingHackmudFolderError, NoUsersError } = await pushModule,
123
- infos = await push(sourcePath, hackmudPath, {
124
- scripts,
125
- onPush: info => logInfo(info, hackmudPath),
126
- minify: shouldMinify,
127
- mangleNames: shouldMangleNames,
128
- forceQuineCheats: shouldforceQuineCheats
129
- })
130
- if (infos instanceof Error) {
131
- logError(infos.message)
132
- if (infos instanceof MissingSourceFolderError || infos instanceof NoUsersError) {
133
- console.log()
134
- logHelp()
135
- } else
136
- infos instanceof MissingHackmudFolderError &&
137
- log(
138
- `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`
139
- )
140
- } else infos.length || logError("Could not find any scripts to push")
141
- }
142
- break
143
- case "dev":
144
- case "watch":
145
- {
146
- const hackmudPath = getHackmudPath(),
147
- sourcePath = commands[1]
148
- if (!sourcePath) {
149
- logError("Must provide the directory to watch\n")
150
- logHelp()
151
- break
152
- }
153
- const scripts = commands.slice(2)
154
- if (scripts.length) {
155
- const invalidScript = scripts.find(
156
- script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script)
157
- )
158
- if (invalidScript) {
159
- logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`)
110
+ complainAboutUnrecognisedOptions()
111
+ const { processScript } = await processScriptModule,
112
+ fileBaseName = basename(target, fileExtension),
113
+ fileBaseNameEndsWithDotSrc = fileBaseName.endsWith(".src"),
114
+ scriptName = fileBaseNameEndsWithDotSrc ? fileBaseName.slice(0, -4) : fileBaseName,
115
+ scriptUser =
116
+ (
117
+ "scripts" == basename(resolve(target, "..")) &&
118
+ "hackmud" == basename(resolve(target, "../../.."))
119
+ ) ?
120
+ basename(resolve(target, "../.."))
121
+ : void 0
122
+ let outputPath =
123
+ commands[2] ||
124
+ resolve(
125
+ dirname(target),
126
+ fileBaseNameEndsWithDotSrc ? scriptName + ".js"
127
+ : ".js" == fileExtension ? fileBaseName + ".min.js"
128
+ : fileBaseName + ".js"
129
+ )
130
+ const golfFile = () =>
131
+ readFile(target, { encoding: "utf8" }).then(async source => {
132
+ const timeStart = performance.now(),
133
+ { script, warnings } = await processScript(source, {
134
+ minify: noMinifyOption && !noMinifyOption.value,
135
+ scriptUser,
136
+ scriptName,
137
+ filePath: target,
138
+ mangleNames: mangleNamesOption?.value,
139
+ forceQuineCheats: forceQuineCheatsOption?.value
140
+ }),
141
+ timeTook = performance.now() - timeStart
142
+ for (const { message, line } of warnings)
143
+ log(`Warning "${chalk.bold(message)}" on line ${chalk.bold(line + "")}`)
144
+ await writeFilePersistent(outputPath, script)
145
+ .catch(error => {
146
+ if (!commands[2] || "EISDIR" != error.code) throw error
147
+ outputPath = resolve(outputPath, basename(target, fileExtension) + ".js")
148
+ return writeFilePersistent(outputPath, script)
149
+ })
150
+ .then(() =>
151
+ log(
152
+ `Wrote ${chalk.bold(countHackmudCharacters(script))} chars to ${chalk.bold(relative(".", outputPath))} | took ${Math.round(100 * timeTook) / 100}ms`
153
+ )
154
+ )
155
+ })
156
+ if (watchOption) {
157
+ const { watch: watchFile } = await chokidarModule
158
+ watchFile(target, { awaitWriteFinish: { stabilityThreshold: 100 } })
159
+ .on("ready", () => log("Watching " + target))
160
+ .on("change", golfFile)
161
+ autoExit = !1
162
+ } else await golfFile()
163
+ } else {
164
+ const hackmudPath = getHackmudPath(),
165
+ sourcePath = commands[1]
166
+ if (!sourcePath) {
167
+ logError(`Must provide the directory to ${"push" == commands[0] ? "push from" : "watch"}\n`)
160
168
  logHelp()
161
- break
169
+ process.exit(1)
162
170
  }
163
- } else scripts.push("*.*")
164
- const optionsHasNoMinify = options.has("no-minify")
165
- if ((optionsHasNoMinify || options.has("skip-minify")) && options.has("mangle-names")) {
166
- logError(
167
- `Options ${colourN("--mangle-names")} and ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} are incompatible\n`
168
- )
169
- logHelp()
170
- break
171
- }
172
- const shouldSkipMinify = options.get("no-minify") || options.get("skip-minify")
173
- let shouldMinify
174
- if (null != shouldSkipMinify) {
175
- if ("boolean" != typeof shouldSkipMinify) {
176
- logError(
177
- `The value for ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} must be ${colourV("true")} or ${colourV("false")}\n`
171
+ const scripts = commands.slice(2)
172
+ if (scripts.length) {
173
+ const invalidScript = scripts.find(
174
+ script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script)
178
175
  )
179
- logHelp()
180
- break
176
+ if (invalidScript) {
177
+ logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`)
178
+ logHelp()
179
+ process.exit(1)
180
+ }
181
+ } else scripts.push("*.*")
182
+ if ("push" == commands[0]) {
183
+ const { push, MissingSourceFolderError, MissingHackmudFolderError, NoUsersError } = await pushModule
184
+ complainAboutUnrecognisedOptions()
185
+ const infos = await push(sourcePath, hackmudPath, {
186
+ scripts,
187
+ onPush: info => logInfo(info, hackmudPath),
188
+ minify: noMinifyOption && !noMinifyOption.value,
189
+ mangleNames: mangleNamesOption?.value,
190
+ forceQuineCheats: forceQuineCheatsOption?.value
191
+ })
192
+ if (infos instanceof Error) {
193
+ logError(infos.message)
194
+ if (infos instanceof MissingSourceFolderError || infos instanceof NoUsersError) {
195
+ console.log()
196
+ logHelp()
197
+ } else
198
+ infos instanceof MissingHackmudFolderError &&
199
+ log(
200
+ `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`
201
+ )
202
+ } else infos.length || logError("Could not find any scripts to push")
203
+ } else {
204
+ const typeDeclarationPathOption = popOption(
205
+ "type-declaration-path",
206
+ "type-declaration",
207
+ "dts",
208
+ "gen-types"
209
+ )
210
+ complainAboutUnrecognisedOptions()
211
+ const { watch } = await watchModule
212
+ watch(sourcePath, hackmudPath, {
213
+ scripts,
214
+ onPush: info => logInfo(info, hackmudPath),
215
+ typeDeclarationPath: typeDeclarationPathOption?.value.toString(),
216
+ minify: noMinifyOption && !noMinifyOption.value,
217
+ mangleNames: mangleNamesOption?.value,
218
+ onReady: () => log("Watching"),
219
+ forceQuineCheats: forceQuineCheatsOption?.value
220
+ })
221
+ autoExit = !1
181
222
  }
182
- shouldMinify = !shouldSkipMinify
183
223
  }
184
- const shouldMangleNames = options.get("mangle-names")
185
- if (null != shouldMangleNames && "boolean" != typeof shouldMangleNames) {
186
- logError(
187
- `The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
188
- )
189
- logHelp()
190
- break
191
- }
192
- const shouldforceQuineCheats = options.get("force-quine-cheats")
193
- if (null != shouldforceQuineCheats && "boolean" != typeof shouldforceQuineCheats) {
194
- logError(
195
- `The value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
196
- )
197
- logHelp()
198
- break
199
- }
200
- const { watch } = await watchModule
201
- watch(sourcePath, hackmudPath, {
202
- scripts,
203
- onPush: info => logInfo(info, hackmudPath),
204
- typeDeclarationPath: (
205
- options.get("type-declaration-path") ||
206
- options.get("type-declaration") ||
207
- options.get("dts") ||
208
- options.get("gen-types")
209
- )?.toString(),
210
- minify: shouldMinify,
211
- mangleNames: shouldMangleNames,
212
- onReady: () => log("Watching"),
213
- forceQuineCheats: shouldforceQuineCheats
214
- })
215
- autoExit = !1
216
224
  }
217
225
  break
218
226
  case "pull":
@@ -222,8 +230,9 @@ switch (commands[0]) {
222
230
  if (!script) {
223
231
  logError("Must provide the script to pull\n")
224
232
  logHelp()
225
- break
233
+ process.exit(1)
226
234
  }
235
+ complainAboutUnrecognisedOptions()
227
236
  const sourcePath = commands[2] || "."
228
237
  await pull(sourcePath, hackmudPath, script).catch(error => {
229
238
  console.error(error)
@@ -233,8 +242,9 @@ switch (commands[0]) {
233
242
  break
234
243
  case "sync-macros":
235
244
  {
236
- const hackmudPath = getHackmudPath(),
237
- { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
245
+ const hackmudPath = getHackmudPath()
246
+ complainAboutUnrecognisedOptions()
247
+ const { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
238
248
  log(`Synced ${macrosSynced} macros to ${usersSynced} users`)
239
249
  }
240
250
  break
@@ -243,18 +253,20 @@ switch (commands[0]) {
243
253
  case "gen-dts":
244
254
  case "gen-types":
245
255
  {
246
- const target = commands[1]
256
+ const hackmudPath = getHackmudPath(),
257
+ target = commands[1]
247
258
  if (!target) {
248
259
  logError("Must provide target directory\n")
249
260
  logHelp()
250
- break
261
+ process.exit(1)
251
262
  }
263
+ complainAboutUnrecognisedOptions()
252
264
  const sourcePath = resolve(target),
253
265
  outputPath = commands[2] || "./player.d.ts",
254
- typeDeclaration = await generateTypeDeclaration(sourcePath, getHackmudPath())
266
+ typeDeclaration = await generateTypeDeclaration(sourcePath, hackmudPath)
255
267
  let typeDeclarationPath = resolve(outputPath)
256
268
  await writeFile(typeDeclarationPath, typeDeclaration).catch(error => {
257
- assert(error instanceof Error, "src/bin/hsm.ts:340:35")
269
+ assert(error instanceof Error, "src/bin/hsm.ts:343:35")
258
270
  if ("EISDIR" != error.code) throw error
259
271
  typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
260
272
  return writeFile(typeDeclarationPath, typeDeclaration)
@@ -266,99 +278,6 @@ switch (commands[0]) {
266
278
  case "h":
267
279
  logHelp()
268
280
  break
269
- case "golf":
270
- case "minify":
271
- {
272
- const target = commands[1]
273
- if (!target) {
274
- logError("Must provide target\n")
275
- logHelp()
276
- break
277
- }
278
- const fileExtension = extname(target)
279
- if (!supportedExtensions.includes(fileExtension)) {
280
- logError(
281
- `Unsupported file extension "${chalk.bold(fileExtension)}"\nSupported extensions are "${supportedExtensions.map(extension => chalk.bold(extension)).join('", "')}"`
282
- )
283
- break
284
- }
285
- const { processScript } = await processScriptModule,
286
- fileBaseName = basename(target, fileExtension),
287
- fileBaseNameEndsWithDotSrc = fileBaseName.endsWith(".src"),
288
- scriptName = fileBaseNameEndsWithDotSrc ? fileBaseName.slice(0, -4) : fileBaseName,
289
- scriptUser =
290
- "scripts" == basename(resolve(target, "..")) && "hackmud" == basename(resolve(target, "../../..")) ?
291
- basename(resolve(target, "../.."))
292
- : void 0,
293
- optionsHasNoMinify = options.has("no-minify")
294
- if ((optionsHasNoMinify || options.has("skip-minify")) && options.has("mangle-names")) {
295
- logError(
296
- `Options ${colourN("--mangle-names")} and ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} are incompatible\n`
297
- )
298
- logHelp()
299
- break
300
- }
301
- const mangleNames_ = options.get("mangle-names")
302
- if (null != mangleNames_ && "boolean" != typeof mangleNames_) {
303
- logError(
304
- `The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
305
- )
306
- logHelp()
307
- break
308
- }
309
- const mangleNames = mangleNames_,
310
- forceQuineCheats_ = options.get("force-quine-cheats")
311
- if (null != forceQuineCheats_ && "boolean" != typeof forceQuineCheats_) {
312
- logError(
313
- `the value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
314
- )
315
- logHelp()
316
- break
317
- }
318
- const forceQuineCheats = forceQuineCheats_
319
- let outputPath =
320
- commands[2] ||
321
- resolve(
322
- dirname(target),
323
- fileBaseNameEndsWithDotSrc ? scriptName + ".js"
324
- : ".js" == fileExtension ? fileBaseName + ".min.js"
325
- : fileBaseName + ".js"
326
- )
327
- const golfFile = () =>
328
- readFile(target, { encoding: "utf8" }).then(async source => {
329
- const timeStart = performance.now(),
330
- { script, warnings } = await processScript(source, {
331
- minify: !(options.get("no-minify") || options.get("skip-minify")),
332
- scriptUser,
333
- scriptName,
334
- filePath: target,
335
- mangleNames,
336
- forceQuineCheats
337
- }),
338
- timeTook = performance.now() - timeStart
339
- for (const { message, line } of warnings)
340
- log(`Warning "${chalk.bold(message)}" on line ${chalk.bold(line + "")}`)
341
- await writeFilePersistent(outputPath, script)
342
- .catch(error => {
343
- if (!commands[2] || "EISDIR" != error.code) throw error
344
- outputPath = resolve(outputPath, basename(target, fileExtension) + ".js")
345
- return writeFilePersistent(outputPath, script)
346
- })
347
- .then(() =>
348
- log(
349
- `Wrote ${chalk.bold(countHackmudCharacters(script))} chars to ${chalk.bold(relative(".", outputPath))} | took ${Math.round(100 * timeTook) / 100}ms`
350
- )
351
- )
352
- })
353
- if (options.get("watch")) {
354
- const { watch: watchFile } = await chokidarModule
355
- watchFile(target, { awaitWriteFinish: { stabilityThreshold: 100 } })
356
- .on("ready", () => log("Watching " + target))
357
- .on("change", golfFile)
358
- autoExit = !1
359
- } else await golfFile()
360
- }
361
- break
362
281
  default:
363
282
  commands[0] && logError(`Unknown command: ${colourL(commands[0])}\n`)
364
283
  logHelp()
@@ -432,7 +351,7 @@ function logError(message) {
432
351
  process.exitCode = 1
433
352
  }
434
353
  function getHackmudPath() {
435
- const hackmudPathOption = options.get("hackmud-path")
354
+ const hackmudPathOption = popOption("hackmud-path")
436
355
  if (null != hackmudPathOption && "string" != typeof hackmudPathOption) {
437
356
  logError(`Option ${colourN("--hackmud-path")} must be a string, got ${colourV(hackmudPathOption)}\n`)
438
357
  logHelp()
@@ -444,3 +363,32 @@ function getHackmudPath() {
444
363
  ("win32" == process.platform ? resolve(process.env.APPDATA, "hackmud") : resolve(homedir(), ".config/hackmud"))
445
364
  )
446
365
  }
366
+ function assertOptionIsBoolean(option) {
367
+ if ("boolean" != typeof option.value) {
368
+ logError(`The value for ${formatOption(option.name)} must be ${colourV("true")} or ${colourV("false")}\n`)
369
+ logHelp()
370
+ process.exit(1)
371
+ }
372
+ }
373
+ function popOption(...names) {
374
+ const presentOptionNames = names.filter(name => options.has(name))
375
+ if (!presentOptionNames.length) return
376
+ const presentOptionNamesWithDashDash = presentOptionNames.map(formatOption)
377
+ if (presentOptionNames.length > 1) {
378
+ logError(
379
+ `The options ${presentOptionNamesWithDashDash.join(", ")} are aliases for each other. Please only specify one`
380
+ )
381
+ process.exit(1)
382
+ }
383
+ const value = options.get(presentOptionNames[0])
384
+ options.delete(presentOptionNames[0])
385
+ return { name: presentOptionNamesWithDashDash[0], value }
386
+ }
387
+ function complainAboutUnrecognisedOptions() {
388
+ if (options.size) {
389
+ logError(
390
+ `Unrecognised option${options.size > 1 ? "s" : ""}: ${[...options.keys()].map(formatOption).join(", ")}`
391
+ )
392
+ process.exit(1)
393
+ }
394
+ }
package/env.d.ts CHANGED
@@ -151,7 +151,16 @@ type Fullsec = Subscripts & PlayerFullsec & {
151
151
  market: {
152
152
  /** **FULLSEC** */ browse: {
153
153
  (args:
154
- Partial<{ seller: string, listed_before: number, listed_after: number, cost: number | string } & Omit<CliUpgrade, "rarity">>
154
+ Partial<{
155
+ seller: string | MongoQuerySelector<string>,
156
+ listed_before: number | MongoQuerySelector<number>,
157
+ listed_after: number,
158
+ cost: number | MongoQuerySelector<number> | string,
159
+ rarity: UpgradeRarityNumber | MongoQuerySelector<UpgradeRarityNumber>,
160
+ name: string | MongoQuerySelector<string>
161
+ } & Omit<{
162
+ [k in keyof CliUpgrade]: CliUpgrade[k] | MongoQuerySelector<CliUpgrade[k]>
163
+ }, "rarity">>
155
164
  ): { i: string, name: string, rarity: Upgrade["rarity"], cost: number }[] | ScriptFailure
156
165
 
157
166
  <I extends string>(args: { i: I }): {
@@ -710,10 +719,50 @@ type Nullsec = Lowsec & PlayerNullsec & {
710
719
  }
711
720
  }
712
721
 
722
+ type MongoTypeString = "minKey" | "double" | "string" | "object" | "array" | "binData" | "undefined" | "objectId" |
723
+ "bool" | "date" | "null" | "regex" | "dbPointer" | "javascript" | "symbol" | "int" | "timestamp" | "long" | "decimal" | "maxKey";
724
+ type MongoTypeNumber = -1 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 127;
725
+
713
726
  type MongoValue = string | number | boolean | Date | MongoValue[] | { [key: string]: MongoValue } | null
714
727
 
715
728
  type MongoCommandValue = string | number | boolean | Date | MongoCommandValue[] | { [key: string]: MongoCommandValue } |
716
- null | undefined
729
+ null | undefined
730
+
731
+ /**
732
+ * Currently unused
733
+ */
734
+ type MongoLogicalSelectors<T extends MongoValue = MongoValue> = {
735
+ $not: T | MongoComparisonSelectors<T> | MongoLogicalSelectors<T>
736
+ $nor: T[]
737
+ $or: T[]
738
+ $and: T[]
739
+ }
740
+
741
+ type MongoArraySelectors<T extends Array<MongoValue> = Array<MongoValue>> = {
742
+ $all: T
743
+ $elemMatch: T
744
+ $size: number
745
+ }
746
+
747
+ type MongoComparisonSelectors<T extends MongoValue = MongoValue> = {
748
+ $eq: T
749
+ $gt: T
750
+ $gte: T
751
+ $in: T[]
752
+ $lt: T
753
+ $lte: T
754
+ $ne: T
755
+ $nin: T[]
756
+ }
757
+
758
+ type MongoElementSelectors = {
759
+ $exists: boolean
760
+ $type: MongoTypeNumber | MongoTypeString
761
+ }
762
+
763
+ type MongoQuerySelector<T extends MongoValue = MongoValue> = Partial<T extends MongoValue[] ?
764
+ (MongoArraySelectors<T> & MongoElementSelectors & MongoComparisonSelectors<T>) :
765
+ (MongoElementSelectors & MongoComparisonSelectors<T>)>
717
766
 
718
767
  type Query = { [key: string]: MongoValue | Query } & { _id?: Id, $in?: MongoValue[] }
719
768
  type Projection = Record<string, boolean | 0 | 1>
@@ -1,5 +1,6 @@
1
1
  import { readDirectoryWithStats } from "@samual/lib/readDirectoryWithStats"
2
2
  import { basename, resolve } from "path"
3
+ import * as PathPosix from "path/posix"
3
4
  async function generateTypeDeclaration(sourceDirectory, hackmudPath) {
4
5
  const users = new Set()
5
6
  if (hackmudPath)
@@ -29,7 +30,7 @@ async function generateTypeDeclaration(sourceDirectory, hackmudPath) {
29
30
  }
30
31
  })
31
32
  )
32
- sourceDirectory = resolve(sourceDirectory)
33
+ sourceDirectory = PathPosix.resolve(sourceDirectory)
33
34
  let o = ""
34
35
  for (const script of wildScripts) o += `type $${script}$ = typeof import("${sourceDirectory}/${script}").default\n`
35
36
  o += "\n"
package/index.js CHANGED
@@ -7,6 +7,7 @@ export { syncMacros } from "./syncMacros.js"
7
7
  export { watch } from "./watch.js"
8
8
  import "@samual/lib/readDirectoryWithStats"
9
9
  import "path"
10
+ import "path/posix"
10
11
  import "@babel/generator"
11
12
  import "@babel/parser"
12
13
  import "@babel/plugin-proposal-decorators"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hackmud-script-manager",
3
- "version": "0.20.4-67aeb81",
3
+ "version": "0.20.4-6a2a079",
4
4
  "description": "Script manager for game hackmud, with minification, TypeScript support, and player script type definition generation.",
5
5
  "keywords": [
6
6
  "api",
@@ -323,7 +323,7 @@ async function processScript(
323
323
  trailingComma: "none"
324
324
  })
325
325
  }
326
- code = postprocess(code, seclevel, uniqueId)
326
+ code = postprocess(code, uniqueId)
327
327
  if (includesIllegalString(code))
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'
@@ -43,15 +43,6 @@ async function minify(file, { uniqueId = "00000000000", mangleNames = !1, forceQ
43
43
  )
44
44
  }
45
45
  }
46
- const hashGReferencePaths = getReferencePathsToGlobal(`$${uniqueId}$GLOBAL$`, program)
47
- if (hashGReferencePaths.length > 3) {
48
- for (const path of hashGReferencePaths) path.replaceWith(t.identifier(`_${uniqueId}_G_`))
49
- mainFunctionPath.node.body.body.unshift(
50
- t.variableDeclaration("let", [
51
- t.variableDeclarator(t.identifier(`_${uniqueId}_G_`), t.identifier(`$${uniqueId}$GLOBAL$`))
52
- ])
53
- )
54
- }
55
46
  const jsonValues = []
56
47
  let scriptBeforeJSONValueReplacement,
57
48
  comment,
@@ -61,7 +52,7 @@ async function minify(file, { uniqueId = "00000000000", mangleNames = !1, forceQ
61
52
  traverse(fileBeforeJSONValueReplacement, {
62
53
  MemberExpression({ node: memberExpression }) {
63
54
  if (!memberExpression.computed) {
64
- assert("Identifier" == memberExpression.property.type, "src/processScript/minify.ts:127:60")
55
+ assert("Identifier" == memberExpression.property.type, "src/processScript/minify.ts:115:60")
65
56
  if ("prototype" == memberExpression.property.name) {
66
57
  memberExpression.computed = !0
67
58
  memberExpression.property = t.identifier(`_${uniqueId}_PROTOTYPE_PROPERTY_`)
@@ -173,7 +164,7 @@ async function minify(file, { uniqueId = "00000000000", mangleNames = !1, forceQ
173
164
  },
174
165
  MemberExpression({ node: memberExpression }) {
175
166
  if (!memberExpression.computed) {
176
- assert("Identifier" == memberExpression.property.type, "src/processScript/minify.ts:261:62")
167
+ assert("Identifier" == memberExpression.property.type, "src/processScript/minify.ts:249:62")
177
168
  if (!(memberExpression.property.name.length < 3)) {
178
169
  memberExpression.computed = !0
179
170
  memberExpression.property = t.stringLiteral(memberExpression.property.name)
@@ -247,7 +238,7 @@ async function minify(file, { uniqueId = "00000000000", mangleNames = !1, forceQ
247
238
  })
248
239
  await Promise.all(promises)
249
240
  const functionDeclaration = file.program.body[0]
250
- assert("FunctionDeclaration" == functionDeclaration.type, "src/processScript/minify.ts:366:61")
241
+ assert("FunctionDeclaration" == functionDeclaration.type, "src/processScript/minify.ts:354:61")
251
242
  if (jsonValues.length) {
252
243
  hasComment = !0
253
244
  if (1 == jsonValues.length)
@@ -259,7 +250,10 @@ async function minify(file, { uniqueId = "00000000000", mangleNames = !1, forceQ
259
250
  t.memberExpression(
260
251
  t.taggedTemplateExpression(
261
252
  t.memberExpression(
262
- t.callExpression(t.identifier(`$${uniqueId}$SUBSCRIPT$scripts$quine$`), []),
253
+ t.callExpression(
254
+ t.identifier(`$${uniqueId}$4$SUBSCRIPT$scripts$quine$`),
255
+ []
256
+ ),
263
257
  t.identifier("split")
264
258
  ),
265
259
  t.templateLiteral([t.templateElement({ raw: "\t", cooked: "\t" }, !0)], [])
@@ -283,7 +277,7 @@ async function minify(file, { uniqueId = "00000000000", mangleNames = !1, forceQ
283
277
  t.memberExpression(
284
278
  t.taggedTemplateExpression(
285
279
  t.memberExpression(
286
- t.callExpression(t.identifier(`$${uniqueId}$SUBSCRIPT$scripts$quine$`), []),
280
+ t.callExpression(t.identifier(`$${uniqueId}$4$SUBSCRIPT$scripts$quine$`), []),
287
281
  t.identifier("split")
288
282
  ),
289
283
  t.templateLiteral([t.templateElement({ raw: "\t", cooked: "\t" }, !0)], [])
@@ -308,7 +302,7 @@ async function minify(file, { uniqueId = "00000000000", mangleNames = !1, forceQ
308
302
  t.memberExpression(
309
303
  t.taggedTemplateExpression(
310
304
  t.memberExpression(
311
- t.callExpression(t.identifier(`$${uniqueId}$SUBSCRIPT$scripts$quine$`), []),
305
+ t.callExpression(t.identifier(`$${uniqueId}$4$SUBSCRIPT$scripts$quine$`), []),
312
306
  t.identifier("split")
313
307
  ),
314
308
  t.templateLiteral([t.templateElement({ raw: "\t", cooked: "\t" }, !0)], [])
@@ -364,7 +358,7 @@ async function minify(file, { uniqueId = "00000000000", mangleNames = !1, forceQ
364
358
  )
365
359
  }
366
360
  if (1 == forceQuineCheats) return code
367
- assert(scriptBeforeJSONValueReplacement, "src/processScript/minify.ts:497:43")
361
+ assert(scriptBeforeJSONValueReplacement, "src/processScript/minify.ts:485:43")
368
362
  return (
369
363
  countHackmudCharacters(scriptBeforeJSONValueReplacement) <=
370
364
  countHackmudCharacters(code) + Number(hasComment)
@@ -380,7 +374,7 @@ function parseObjectExpression(node, o) {
380
374
  "Identifier" == property.key.type ||
381
375
  "NumericLiteral" == property.key.type ||
382
376
  "StringLiteral" == property.key.type,
383
- "src/processScript/minify.ts:519:4"
377
+ "src/processScript/minify.ts:507:4"
384
378
  )
385
379
  if ("ArrayExpression" == property.value.type) {
386
380
  const childArray = []
@@ -1 +1 @@
1
- export declare const postprocess: (code: string, seclevel: number, uniqueId: string) => string;
1
+ export declare const postprocess: (code: string, uniqueId: string) => string;
@@ -1,12 +1,12 @@
1
- const postprocess = (code, seclevel, uniqueId) =>
1
+ const postprocess = (code, uniqueId) =>
2
2
  code
3
- .replace(/^function\s*\w+\(/, "function(")
3
+ .replace(/^function\s*[\w$]+\(/, "function(")
4
4
  .replace(RegExp(`\\$${uniqueId}\\$\\\\(?:\\\\)?\\$SC_DOLLAR\\$`, "g"), "S\\C$")
5
5
  .replace(RegExp(`\\$${uniqueId}\\$\\\\(?:\\\\)?\\$DB_DOLLAR\\$`, "g"), "D\\B$")
6
6
  .replace(RegExp(`\\$${uniqueId}\\$\\\\(?:\\\\)?\\$D\\$`, "g"), "_\\_D_S")
7
7
  .replace(RegExp(`\\$${uniqueId}\\$\\\\(?:\\\\)?\\$FMCL\\$`, "g"), "_\\_FMCL_")
8
8
  .replace(RegExp(`\\$${uniqueId}\\$\\\\(?:\\\\)?\\$G\\$`, "g"), "_\\_G_")
9
- .replace(RegExp(`\\$${uniqueId}\\$SUBSCRIPT\\$(\\w+)\\$(\\w+)\\$`, "g"), `#${"nlmhf"[seclevel]}s.$1.$2`)
9
+ .replace(RegExp(`\\$${uniqueId}\\$(\\d)\\$SUBSCRIPT\\$(\\w+)\\$(\\w+)\\$`, "g"), "#$1s.$2.$3")
10
10
  .replace(RegExp(`\\$${uniqueId}\\$DEBUG\\$`, "g"), "#D")
11
11
  .replace(RegExp(`\\$${uniqueId}\\$FMCL\\$`, "g"), "#FMCL")
12
12
  .replace(RegExp(`\\$${uniqueId}\\$GLOBAL\\$`, "g"), "#G")
@@ -98,8 +98,10 @@ async function preprocess(code, { uniqueId = "00000000000" } = {}) {
98
98
  t.stringLiteral(resolve("proxy-polyfill/src/proxy.js", import.meta.url).slice(7))
99
99
  )
100
100
  )
101
- return 1 == program.node.body.length && "FunctionDeclaration" == program.node.body[0].type ?
102
- { code: "export default " + generate(file).code }
103
- : { code: generate(file).code }
101
+ if (1 == program.node.body.length && "FunctionDeclaration" == program.node.body[0].type)
102
+ throw Error(
103
+ "Scripts that only contain a single function declaration are no longer supported.\nPrefix the function declaration with `export default`."
104
+ )
105
+ return { code: generate(file).code }
104
106
  }
105
107
  export { preprocess }
@@ -22,9 +22,7 @@ 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_`,
26
- exports = new Map(),
27
- liveExports = new Map()
25
+ const topFunctionName = `_${uniqueId}_SCRIPT_`
28
26
  let program
29
27
  traverse(file, {
30
28
  Program(path) {
@@ -70,30 +68,30 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
70
68
  const referencePath = FunctionReferencePaths[0]
71
69
  assert(
72
70
  "MemberExpression" == referencePath.parent.type,
73
- "src/processScript/transform.ts:105:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
71
+ "src/processScript/transform.ts:103:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
74
72
  )
75
73
  assert(
76
74
  "Identifier" == referencePath.parent.property.type,
77
- "src/processScript/transform.ts:110:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
75
+ "src/processScript/transform.ts:108:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
78
76
  )
79
77
  assert(
80
78
  "prototype" == referencePath.parent.property.name,
81
- "src/processScript/transform.ts:115:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
79
+ "src/processScript/transform.ts:113:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
82
80
  )
83
81
  referencePath.parentPath.replaceWith(createGetFunctionPrototypeNode())
84
82
  } else {
85
83
  for (const referencePath of FunctionReferencePaths) {
86
84
  assert(
87
85
  "MemberExpression" == referencePath.parent.type,
88
- "src/processScript/transform.ts:123:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
86
+ "src/processScript/transform.ts:121:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
89
87
  )
90
88
  assert(
91
89
  "Identifier" == referencePath.parent.property.type,
92
- "src/processScript/transform.ts:128:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
90
+ "src/processScript/transform.ts:126:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
93
91
  )
94
92
  assert(
95
93
  "prototype" == referencePath.parent.property.name,
96
- "src/processScript/transform.ts:133:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
94
+ "src/processScript/transform.ts:131:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
97
95
  )
98
96
  functionDotPrototypeIsReferencedMultipleTimes = !0
99
97
  referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_FUNCTION_DOT_PROTOTYPE_`))
@@ -101,40 +99,40 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
101
99
  functionDotPrototypeIsReferencedMultipleTimes = !0
102
100
  }
103
101
  }
104
- const neededSubscriptLets = new Set()
102
+ const neededSubscriptLets = new Map()
105
103
  let detectedSeclevel = 4
106
104
  for (const fakeSubscriptObjectName of ["$fs", "$4s", "$s"])
107
- program.scope.hasGlobal(fakeSubscriptObjectName) && processFakeSubscriptObject(fakeSubscriptObjectName)
105
+ program.scope.hasGlobal(fakeSubscriptObjectName) && processFakeSubscriptObject(fakeSubscriptObjectName, 4)
108
106
  for (const fakeSubscriptObjectName of ["$hs", "$3s"])
109
107
  if (program.scope.hasGlobal(fakeSubscriptObjectName)) {
110
108
  detectedSeclevel = 3
111
- processFakeSubscriptObject(fakeSubscriptObjectName)
109
+ processFakeSubscriptObject(fakeSubscriptObjectName, 3)
112
110
  }
113
111
  for (const fakeSubscriptObjectName of ["$ms", "$2s"])
114
112
  if (program.scope.hasGlobal(fakeSubscriptObjectName)) {
115
113
  detectedSeclevel = 2
116
- processFakeSubscriptObject(fakeSubscriptObjectName)
114
+ processFakeSubscriptObject(fakeSubscriptObjectName, 2)
117
115
  }
118
116
  for (const fakeSubscriptObjectName of ["$ls", "$1s"])
119
117
  if (program.scope.hasGlobal(fakeSubscriptObjectName)) {
120
118
  detectedSeclevel = 1
121
- processFakeSubscriptObject(fakeSubscriptObjectName)
119
+ processFakeSubscriptObject(fakeSubscriptObjectName, 1)
122
120
  }
123
121
  for (const fakeSubscriptObjectName of ["$ns", "$0s"])
124
122
  if (program.scope.hasGlobal(fakeSubscriptObjectName)) {
125
123
  detectedSeclevel = 0
126
- processFakeSubscriptObject(fakeSubscriptObjectName)
124
+ processFakeSubscriptObject(fakeSubscriptObjectName, 0)
127
125
  }
128
126
  seclevel = Math.min(seclevel, detectedSeclevel)
129
127
  const neededDbMethodLets = new Set()
130
128
  if (program.scope.hasGlobal("$db"))
131
129
  for (const referencePath of getReferencePathsToGlobal("$db", program)) {
132
- assert("MemberExpression" == referencePath.parentPath.node.type, "src/processScript/transform.ts:187:69")
133
- assert("Identifier" == referencePath.parentPath.node.property.type, "src/processScript/transform.ts:188:72")
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")
134
132
  const databaseOpMethodName = referencePath.parentPath.node.property.name
135
133
  assert(
136
134
  validDBMethods.includes(databaseOpMethodName),
137
- `src/processScript/transform.ts:194:8 invalid db method "${databaseOpMethodName}", valid db methods are "${validDBMethods.join('", "')}"`
135
+ `src/processScript/transform.ts:192:8 invalid db method "${databaseOpMethodName}", valid db methods are "${validDBMethods.join('", "')}"`
138
136
  )
139
137
  if ("CallExpression" == referencePath.parentPath.parentPath?.type)
140
138
  referencePath.parentPath.replaceWith(t.identifier(`$${uniqueId}$DB$${databaseOpMethodName}$`))
@@ -157,9 +155,10 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
157
155
  if (program.scope.hasGlobal("$FMCL"))
158
156
  for (const referencePath of getReferencePathsToGlobal("$FMCL", program))
159
157
  referencePath.replaceWith(t.identifier(`$${uniqueId}$FMCL$`))
160
- if (program.scope.hasGlobal("$G"))
158
+ let needG = program.scope.hasGlobal("$G")
159
+ if (needG)
161
160
  for (const referencePath of getReferencePathsToGlobal("$G", program))
162
- referencePath.replaceWith(t.identifier(`$${uniqueId}$GLOBAL$`))
161
+ referencePath.replaceWith(t.identifier(`_${uniqueId}_G_`))
163
162
  if (program.scope.hasGlobal("_SECLEVEL"))
164
163
  for (const referencePath of getReferencePathsToGlobal("_SECLEVEL", program))
165
164
  referencePath.replaceWith(t.numericLiteral(seclevel))
@@ -193,11 +192,12 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
193
192
  "ExportSpecifier" == specifier.type,
194
193
  `src/processScript/transform.ts:276:51 ${specifier.type} is currently unsupported`
195
194
  )
196
- const exportedName =
197
- "Identifier" == specifier.exported.type ? specifier.exported.name : specifier.exported.value
198
- "default" == exportedName ?
199
- (exportDefaultName = specifier.local.name)
200
- : exports.set(specifier.local.name, exportedName)
195
+ if (
196
+ "default" !=
197
+ ("Identifier" == specifier.exported.type ? specifier.exported.name : specifier.exported.value)
198
+ )
199
+ throw Error("Only default exports are supported")
200
+ exportDefaultName = specifier.local.name
201
201
  }
202
202
  }
203
203
  const globalBlock = t.blockStatement([])
@@ -223,10 +223,6 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
223
223
  t.returnStatement(t.callExpression(t.identifier(exportDefaultName), []))
224
224
  ])
225
225
  ))
226
- if ("const" != statement.kind && exports.has(identifierName)) {
227
- liveExports.set(identifierName, exports.get(identifierName))
228
- exports.delete(identifierName)
229
- }
230
226
  globalBlock.body.push(
231
227
  t.variableDeclaration("let", [t.variableDeclarator(t.identifier(identifierName))])
232
228
  )
@@ -291,34 +287,16 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
291
287
  }
292
288
  program.node.body = [mainFunction]
293
289
  if (globalBlock.body.length) {
294
- ;(exports.size || liveExports.size) &&
295
- mainFunction.body.body.push(
296
- t.returnStatement(
297
- t.objectExpression([
298
- ...[...exports].map(([local, exported]) =>
299
- t.objectProperty(t.identifier(exported), t.identifier(local))
300
- ),
301
- ...[...liveExports].map(([local, exported]) =>
302
- t.objectMethod(
303
- "get",
304
- t.identifier(exported),
305
- [],
306
- t.blockStatement([t.returnStatement(t.identifier(local))])
307
- )
308
- )
309
- ])
310
- )
311
- )
312
290
  program.scope.crawl()
313
291
  const globalBlockVariables = new Set()
314
292
  let hoistedGlobalBlockFunctions = 0
315
293
  for (const [globalBlockIndex, globalBlockStatement] of [...globalBlock.body.entries()].reverse())
316
294
  if ("VariableDeclaration" == globalBlockStatement.type) {
317
- assert(1 == globalBlockStatement.declarations.length, "src/processScript/transform.ts:410:59")
295
+ assert(1 == globalBlockStatement.declarations.length, "src/processScript/transform.ts:390:59")
318
296
  const declarator = globalBlockStatement.declarations[0]
319
297
  assert(
320
298
  "Identifier" == declarator.id.type,
321
- `src/processScript/transform.ts:414:51 declarator.id.type was "${declarator.id.type}"`
299
+ `src/processScript/transform.ts:394:51 declarator.id.type was "${declarator.id.type}"`
322
300
  )
323
301
  program.scope.crawl()
324
302
  if (program.scope.hasGlobal(declarator.id.name)) {
@@ -333,15 +311,16 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
333
311
  Object.keys(program.scope.globals).some(global => globalBlockVariables.has(global))
334
312
  ) {
335
313
  const binding = program.scope.getBinding(declarator.id.name)
336
- assert(binding, "src/processScript/transform.ts:433:23")
314
+ assert(binding, "src/processScript/transform.ts:413:23")
337
315
  for (const referencePath of binding.referencePaths) {
338
- assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:436:56")
316
+ assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:416:56")
339
317
  referencePath.replaceWith(
340
318
  t.memberExpression(
341
- t.identifier(`$${uniqueId}$GLOBAL$`),
319
+ t.identifier(`_${uniqueId}_G_`),
342
320
  t.identifier(referencePath.node.name)
343
321
  )
344
322
  )
323
+ needG = !0
345
324
  }
346
325
  for (const referencePath of binding.constantViolations)
347
326
  if ("AssignmentExpression" == referencePath.node.type)
@@ -350,12 +329,13 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
350
329
  clearObject(node)
351
330
  Object.assign(
352
331
  node,
353
- t.memberExpression(t.identifier(`$${uniqueId}$GLOBAL$`), t.identifier(name))
332
+ t.memberExpression(t.identifier(`_${uniqueId}_G_`), t.identifier(name))
354
333
  )
334
+ needG = !0
355
335
  }
356
336
  globalBlockPath.remove()
357
337
  globalBlockStatementPath.remove()
358
- declarator.init &&
338
+ if (declarator.init) {
359
339
  globalBlock.body.splice(
360
340
  globalBlockIndex,
361
341
  0,
@@ -363,13 +343,15 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
363
343
  t.assignmentExpression(
364
344
  "=",
365
345
  t.memberExpression(
366
- t.identifier(`$${uniqueId}$GLOBAL$`),
346
+ t.identifier(`_${uniqueId}_G_`),
367
347
  t.identifier(declarator.id.name)
368
348
  ),
369
349
  declarator.init
370
350
  )
371
351
  )
372
352
  )
353
+ needG = !0
354
+ }
373
355
  } else {
374
356
  globalBlockPath.remove()
375
357
  globalBlockStatementPath.remove()
@@ -379,22 +361,20 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
379
361
  } else globalBlockVariables.add(declarator.id.name)
380
362
  } else if ("ClassDeclaration" == globalBlockStatement.type) {
381
363
  program.scope.crawl()
382
- assert(globalBlockStatement.id, "src/processScript/transform.ts:487:37")
364
+ assert(globalBlockStatement.id, "src/processScript/transform.ts:473:37")
383
365
  if (program.scope.hasGlobal(globalBlockStatement.id.name)) {
384
366
  globalBlock.body.splice(globalBlockIndex, 1)
385
367
  const [globalBlockPath] = program.unshiftContainer("body", globalBlock),
386
368
  [globalBlockStatementPath] = program.unshiftContainer("body", globalBlockStatement)
387
369
  program.scope.crawl()
388
370
  const binding = program.scope.getBinding(globalBlockStatement.id.name)
389
- assert(binding, "src/processScript/transform.ts:499:22")
371
+ assert(binding, "src/processScript/transform.ts:485:22")
390
372
  for (const referencePath of binding.referencePaths) {
391
- assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:502:55")
373
+ assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:488:55")
392
374
  referencePath.replaceWith(
393
- t.memberExpression(
394
- t.identifier(`$${uniqueId}$GLOBAL$`),
395
- t.identifier(referencePath.node.name)
396
- )
375
+ t.memberExpression(t.identifier(`_${uniqueId}_G_`), t.identifier(referencePath.node.name))
397
376
  )
377
+ needG = !0
398
378
  }
399
379
  globalBlockPath.remove()
400
380
  globalBlockStatementPath.remove()
@@ -405,7 +385,7 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
405
385
  t.assignmentExpression(
406
386
  "=",
407
387
  t.memberExpression(
408
- t.identifier(`$${uniqueId}$GLOBAL$`),
388
+ t.identifier(`_${uniqueId}_G_`),
409
389
  t.identifier(globalBlockStatement.id.name)
410
390
  ),
411
391
  t.classExpression(
@@ -417,13 +397,9 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
417
397
  )
418
398
  )
419
399
  )
400
+ needG = !0
420
401
  }
421
402
  }
422
- if (program.scope.hasGlobal("_EXPORTS"))
423
- for (const referencePath of getReferencePathsToGlobal("_EXPORTS", program))
424
- referencePath.replaceWith(
425
- t.arrayExpression([...exports.keys(), ...liveExports.keys()].map(name => t.stringLiteral(name)))
426
- )
427
403
  globalBlock.body.length &&
428
404
  mainFunction.body.body.splice(
429
405
  hoistedGlobalBlockFunctions,
@@ -522,12 +498,12 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
522
498
  mainFunction.body.body.unshift(
523
499
  t.variableDeclaration(
524
500
  "let",
525
- [...neededSubscriptLets].map(name =>
501
+ [...neededSubscriptLets].map(([name, seclevel]) =>
526
502
  t.variableDeclarator(
527
503
  t.identifier(`_${uniqueId}_SUBSCRIPT_${name}_`),
528
504
  t.arrowFunctionExpression(
529
505
  [t.restElement(t.identifier("args"))],
530
- t.callExpression(t.identifier(`$${uniqueId}$SUBSCRIPT$${name}$`), [
506
+ t.callExpression(t.identifier(`$${uniqueId}$${seclevel}$SUBSCRIPT$${name}$`), [
531
507
  t.spreadElement(t.identifier("args"))
532
508
  ])
533
509
  )
@@ -535,6 +511,12 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
535
511
  )
536
512
  )
537
513
  )
514
+ needG &&
515
+ mainFunction.body.body.unshift(
516
+ t.variableDeclaration("let", [
517
+ t.variableDeclarator(t.identifier(`_${uniqueId}_G_`), t.identifier(`$${uniqueId}$GLOBAL$`))
518
+ ])
519
+ )
538
520
  traverse(file, {
539
521
  BlockStatement({ node: blockStatement }) {
540
522
  for (const [index, functionDeclaration] of blockStatement.body.entries())
@@ -555,7 +537,7 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
555
537
  }
556
538
  },
557
539
  ClassBody({ node: classBody, scope, parent }) {
558
- assert(t.isClass(parent), "src/processScript/transform.ts:669:30")
540
+ assert(t.isClass(parent), "src/processScript/transform.ts:658:30")
559
541
  let thisIsReferenced = !1
560
542
  for (const classMethod of classBody.body) {
561
543
  if ("ClassMethod" != classMethod.type) continue
@@ -661,36 +643,37 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
661
643
  t.identifier("prototype")
662
644
  )
663
645
  }
664
- function processFakeSubscriptObject(fakeSubscriptObjectName) {
646
+ function processFakeSubscriptObject(fakeSubscriptObjectName, seclevel) {
665
647
  for (const referencePath of getReferencePathsToGlobal(fakeSubscriptObjectName, program)) {
666
- assert("MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:785:60")
648
+ assert("MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:774:60")
667
649
  assert("Identifier" == referencePath.parent.property.type)
668
650
  assert(
669
651
  "MemberExpression" == referencePath.parentPath.parentPath?.node.type,
670
- "src/processScript/transform.ts:787:81"
652
+ "src/processScript/transform.ts:776:81"
671
653
  )
672
654
  assert(
673
655
  "Identifier" == referencePath.parentPath.parentPath.node.property.type,
674
- "src/processScript/transform.ts:788:83"
656
+ "src/processScript/transform.ts:777:83"
675
657
  )
676
658
  assert(
677
659
  /^[_a-z][\d_a-z]{0,24}$/.test(referencePath.parent.property.name),
678
- `src/processScript/transform.ts:792:8 invalid user "${referencePath.parent.property.name}" in subscript`
660
+ `src/processScript/transform.ts:781:8 invalid user "${referencePath.parent.property.name}" in subscript`
679
661
  )
680
662
  assert(
681
663
  /^[_a-z][\d_a-z]{0,24}$/.test(referencePath.parentPath.parentPath.node.property.name),
682
- `src/processScript/transform.ts:797:8 invalid script name "${referencePath.parentPath.parentPath.node.property.name}" in subscript`
664
+ `src/processScript/transform.ts:786:8 invalid script name "${referencePath.parentPath.parentPath.node.property.name}" in subscript`
683
665
  )
684
666
  if ("CallExpression" == referencePath.parentPath.parentPath.parentPath?.type)
685
667
  referencePath.parentPath.parentPath.replaceWith(
686
668
  t.identifier(
687
- `$${uniqueId}$SUBSCRIPT$${referencePath.parent.property.name}$${referencePath.parentPath.parentPath.node.property.name}$`
669
+ `$${uniqueId}$${seclevel}$SUBSCRIPT$${referencePath.parent.property.name}$${referencePath.parentPath.parentPath.node.property.name}$`
688
670
  )
689
671
  )
690
672
  else {
691
673
  const name = `${referencePath.parent.property.name}$${referencePath.parentPath.parentPath.node.property.name}`
692
674
  referencePath.parentPath.parentPath.replaceWith(t.identifier(`_${uniqueId}_SUBSCRIPT_${name}_`))
693
- neededSubscriptLets.add(name)
675
+ const maxSecLevel = Math.max(neededSubscriptLets.get(name) || 0, seclevel)
676
+ neededSubscriptLets.set(name, maxSecLevel)
694
677
  }
695
678
  }
696
679
  }
package/watch.js CHANGED
@@ -9,6 +9,7 @@ import { extname, basename, resolve } from "path"
9
9
  import { supportedExtensions } from "./constants.js"
10
10
  import { generateTypeDeclaration } from "./generateTypeDeclaration.js"
11
11
  import { processScript } from "./processScript/index.js"
12
+ import "path/posix"
12
13
  import "@babel/generator"
13
14
  import "@babel/parser"
14
15
  import "@babel/plugin-proposal-decorators"