hackmud-script-manager 0.20.4-550e28d → 0.20.4-698da0d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,6 +20,10 @@ You can read about how HSM works [in my blog post](https://samual.uk/blog/js-cod
20
20
  > ```
21
21
  > You will need to run `Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser` in PowerShell as an administrator. For more information, see [Microsoft's page about Execution Policies](https://learn.microsoft.com/en-gb/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.4).
22
22
 
23
+ ![image](https://github.com/samualtnorman/hackmud-script-manager/assets/18307063/69a371fe-f8c8-43fe-b3c7-39f3735ce6fb)
24
+ ![image](https://github.com/samualtnorman/hackmud-script-manager/assets/18307063/08103f9e-74fa-4a56-a739-94858ba8c139)
25
+ ![image](https://github.com/samualtnorman/hackmud-script-manager/assets/18307063/25ccb86d-1fe3-4632-b703-ac47f5b32c9c)
26
+
23
27
  ## Features
24
28
  - Minification
25
29
  - This includes auto quine cheating.
package/bin/hsm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { Cache } from "@samual/lib/Cache"
2
+ import { AutoMap } from "@samual/lib/AutoMap"
3
3
  import { assert } from "@samual/lib/assert"
4
4
  import { countHackmudCharacters } from "@samual/lib/countHackmudCharacters"
5
5
  import { writeFilePersistent } from "@samual/lib/writeFilePersistent"
@@ -13,10 +13,10 @@ import { syncMacros } from "../syncMacros.js"
13
13
  import "@samual/lib/readDirectoryWithStats"
14
14
  import "path/posix"
15
15
  import "@samual/lib/copyFilePersistent"
16
- const version = "0.20.4-550e28d",
16
+ const formatOption = name => colourN(`-${1 == name.length ? "" : "-"}${name}`),
17
17
  options = new Map(),
18
18
  commands = [],
19
- userColours = new Cache(user => {
19
+ userColours = new AutoMap(user => {
20
20
  let hash = 0
21
21
  for (const char of user) hash += (hash >> 1) + hash + "xi1_8ratvsw9hlbgm02y5zpdcn7uekof463qj".indexOf(char) + 1
22
22
  return [colourJ, colourK, colourM, colourW, colourL, colourB][hash % 6](user)
@@ -62,7 +62,7 @@ process.version.startsWith("v21.") &&
62
62
  )
63
63
  )
64
64
  if ("v" == commands[0] || "version" == commands[0] || popOption("version", "v")?.value) {
65
- console.log(version)
65
+ console.log("0.20.4-698da0d")
66
66
  process.exit()
67
67
  }
68
68
  if (popOption("help", "h")?.value) {
@@ -83,7 +83,7 @@ switch (commands[0]) {
83
83
  noMinifyIncompatibleOption = mangleNamesOption || forceQuineCheatsOption
84
84
  if (noMinifyOption && noMinifyIncompatibleOption) {
85
85
  logError(
86
- `Options ${colourN(noMinifyOption.name)} and ${colourN(noMinifyIncompatibleOption.name)} are incompatible\n`
86
+ `Options ${formatOption(noMinifyOption.name)} and ${formatOption(noMinifyIncompatibleOption.name)} are incompatible\n`
87
87
  )
88
88
  logHelp()
89
89
  process.exit(1)
@@ -106,6 +106,7 @@ switch (commands[0]) {
106
106
  )
107
107
  process.exit(1)
108
108
  }
109
+ complainAboutUnrecognisedOptions()
109
110
  const { processScript } = await processScriptModule,
110
111
  fileBaseName = basename(target, fileExtension),
111
112
  fileBaseNameEndsWithDotSrc = fileBaseName.endsWith(".src"),
@@ -178,15 +179,15 @@ switch (commands[0]) {
178
179
  }
179
180
  } else scripts.push("*.*")
180
181
  if ("push" == commands[0]) {
181
- const { push, MissingSourceFolderError, MissingHackmudFolderError, NoUsersError } =
182
- await pushModule,
183
- infos = await push(sourcePath, hackmudPath, {
184
- scripts,
185
- onPush: info => logInfo(info, hackmudPath),
186
- minify: noMinifyOption && !noMinifyOption.value,
187
- mangleNames: mangleNamesOption?.value,
188
- forceQuineCheats: forceQuineCheatsOption?.value
189
- })
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
+ })
190
191
  if (infos instanceof Error) {
191
192
  logError(infos.message)
192
193
  if (infos instanceof MissingSourceFolderError || infos instanceof NoUsersError) {
@@ -200,12 +201,13 @@ switch (commands[0]) {
200
201
  } else infos.length || logError("Could not find any scripts to push")
201
202
  } else {
202
203
  const typeDeclarationPathOption = popOption(
203
- "type-declaration-path",
204
- "type-declaration",
205
- "dts",
206
- "gen-types"
207
- ),
208
- { watch } = await watchModule
204
+ "type-declaration-path",
205
+ "type-declaration",
206
+ "dts",
207
+ "gen-types"
208
+ )
209
+ complainAboutUnrecognisedOptions()
210
+ const { watch } = await watchModule
209
211
  watch(sourcePath, hackmudPath, {
210
212
  scripts,
211
213
  onPush: info => logInfo(info, hackmudPath),
@@ -229,6 +231,7 @@ switch (commands[0]) {
229
231
  logHelp()
230
232
  process.exit(1)
231
233
  }
234
+ complainAboutUnrecognisedOptions()
232
235
  const sourcePath = commands[2] || "."
233
236
  await pull(sourcePath, hackmudPath, script).catch(error => {
234
237
  console.error(error)
@@ -238,8 +241,9 @@ switch (commands[0]) {
238
241
  break
239
242
  case "sync-macros":
240
243
  {
241
- const hackmudPath = getHackmudPath(),
242
- { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
244
+ const hackmudPath = getHackmudPath()
245
+ complainAboutUnrecognisedOptions()
246
+ const { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
243
247
  log(`Synced ${macrosSynced} macros to ${usersSynced} users`)
244
248
  }
245
249
  break
@@ -255,12 +259,13 @@ switch (commands[0]) {
255
259
  logHelp()
256
260
  process.exit(1)
257
261
  }
262
+ complainAboutUnrecognisedOptions()
258
263
  const sourcePath = resolve(target),
259
264
  outputPath = commands[2] || "./player.d.ts",
260
265
  typeDeclaration = await generateTypeDeclaration(sourcePath, hackmudPath)
261
266
  let typeDeclarationPath = resolve(outputPath)
262
267
  await writeFile(typeDeclarationPath, typeDeclaration).catch(error => {
263
- assert(error instanceof Error, "src/bin/hsm.ts:330:35")
268
+ assert(error instanceof Error, "src/bin/hsm.ts:343:35")
264
269
  if ("EISDIR" != error.code) throw error
265
270
  typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
266
271
  return writeFile(typeDeclarationPath, typeDeclaration)
@@ -281,7 +286,7 @@ function logHelp() {
281
286
  const pushCommandDescription = "Push scripts from a directory to hackmud user's scripts directories",
282
287
  forceQuineCheatsOptionDescription = `Force quine cheats on. Use ${colourN("--force-quine-cheats")}=${colourV("false")} to force off`,
283
288
  hackmudPathOption = `${colourN("--hackmud-path")}=${colourB("<path>")}\n Override hackmud path`
284
- console.log(colourN("Version") + colourS(": ") + colourV(version))
289
+ console.log(colourN("Version") + colourS(": ") + colourV("0.20.4-698da0d"))
285
290
  switch (commands[0]) {
286
291
  case "dev":
287
292
  case "watch":
@@ -359,7 +364,7 @@ function getHackmudPath() {
359
364
  }
360
365
  function assertOptionIsBoolean(option) {
361
366
  if ("boolean" != typeof option.value) {
362
- logError(`The value for ${colourN(option.name)} must be ${colourV("true")} or ${colourV("false")}\n`)
367
+ logError(`The value for ${formatOption(option.name)} must be ${colourV("true")} or ${colourV("false")}\n`)
363
368
  logHelp()
364
369
  process.exit(1)
365
370
  }
@@ -367,9 +372,7 @@ function assertOptionIsBoolean(option) {
367
372
  function popOption(...names) {
368
373
  const presentOptionNames = names.filter(name => options.has(name))
369
374
  if (!presentOptionNames.length) return
370
- const presentOptionNamesWithDashDash = presentOptionNames.map(name =>
371
- colourN(`-${1 == name.length ? "" : "-"}${name}`)
372
- )
375
+ const presentOptionNamesWithDashDash = presentOptionNames.map(formatOption)
373
376
  if (presentOptionNames.length > 1) {
374
377
  logError(
375
378
  `The options ${presentOptionNamesWithDashDash.join(", ")} are aliases for each other. Please only specify one`
@@ -380,3 +383,11 @@ function popOption(...names) {
380
383
  options.delete(presentOptionNames[0])
381
384
  return { name: presentOptionNamesWithDashDash[0], value }
382
385
  }
386
+ function complainAboutUnrecognisedOptions() {
387
+ if (options.size) {
388
+ logError(
389
+ `Unrecognised option${options.size > 1 ? "s" : ""}: ${[...options.keys()].map(formatOption).join(", ")}`
390
+ )
391
+ process.exit(1)
392
+ }
393
+ }
package/env.d.ts CHANGED
@@ -3,13 +3,7 @@ type ScriptSuccess<T = object> = { ok: true } & T
3
3
  type ScriptFailure = { ok: false, msg?: string }
4
4
  type ScriptResponse<T = object> = ScriptSuccess<T> | ScriptFailure
5
5
  type ErrorScripts = Record<string, () => ScriptFailure>
6
-
7
- type AllOptional<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? true : false }[keyof T]
8
-
9
- type Scriptor<Args = unknown, Ret = unknown> = {
10
- name: string
11
- call: AllOptional<Args> extends true ? (args?: Args) => Ret : (args: Args) => Ret
12
- }
6
+ type Scriptor<TArgs extends any[] = any[]> = { name: string, call: (...args: TArgs) => unknown }
13
7
 
14
8
  type Subscripts = Record<string, Record<string, (...args: any) => any>> & {
15
9
  accts: ErrorScripts
@@ -34,8 +28,8 @@ interface PlayerLowsec {}
34
28
  interface PlayerNullsec {}
35
29
 
36
30
  type UpgradeRarityString = "`0noob`" | "`1kiddie`" | "`2h4x0r`" | "`3h4rdc0r3`" | "`4|_|b3|2`" | "`531337`"
37
- type UpgradeRarityNumber = 0 | 1 | 2 | 3 | 4 | 5;
38
- type UpgradeRarity = UpgradeRarityString | UpgradeRarityNumber;
31
+ type UpgradeRarityNumber = 0 | 1 | 2 | 3 | 4 | 5
32
+ type UpgradeRarity = UpgradeRarityString | UpgradeRarityNumber
39
33
 
40
34
  type UpgradeBase = {
41
35
  name: string
@@ -51,10 +45,8 @@ type UpgradeBase = {
51
45
 
52
46
  type Upgrade = UpgradeBase & Record<string, null | boolean | number | string>
53
47
 
54
- type CliUpgrade = Omit<UpgradeBase, `rarity`> & {
55
- [x: string]: null | boolean | number | string
56
- rarity: UpgradeRarityString
57
- }
48
+ type CliUpgrade = Omit<UpgradeBase, `rarity`> &
49
+ { [k: string]: null | boolean | number | string, rarity: UpgradeRarityString }
58
50
 
59
51
  type UsersTopItem<R> = { rank: R, name: string, last_activity: string, balance: string }
60
52
  type CorpsTopItem<R> = { rank: R, name: string, worth: string }
@@ -132,21 +124,11 @@ type Fullsec = Subscripts & PlayerFullsec & {
132
124
  }
133
125
 
134
126
  escrow: {
135
- /** **FULLSEC** */ charge: (args: {
136
- cost: number | string
137
- is_unlim?: boolean
138
- }) => null | ScriptFailure
139
-
127
+ /** **FULLSEC** */ charge: (args: { cost: number | string, is_unlim?: boolean }) => null | ScriptFailure
140
128
  confirm: never
141
129
  }
142
130
 
143
- gui: {
144
- chats: never
145
- quiet: never
146
- size: never
147
- vfx: never
148
- vol: never
149
- }
131
+ gui: { chats: never, quiet: never, size: never, vfx: never, vol: never }
150
132
 
151
133
  market: {
152
134
  /** **FULLSEC** */ browse: {
@@ -465,7 +447,10 @@ type Highsec = Fullsec & PlayerHighsec & {
465
447
  /** **HIGHSEC**
466
448
  * @returns GC balance as number if `is_script` is true (default).
467
449
  * @returns GC balance as string if `is_script` is false. */
468
- balance: ((args?: { is_script?: true }) => number) & ((args: { is_script: false }) => string)
450
+ balance: {
451
+ (args?: { is_script?: true }): number
452
+ (args: { is_script: false }): string
453
+ }
469
454
 
470
455
  /** **HIGHSEC**
471
456
  * @returns Transaction history according to filter.
@@ -635,6 +620,9 @@ type Lowsec = Midsec & PlayerLowsec & {
635
620
  (args: { i: number | number[], to: string, memo?: string }): ScriptResponse
636
621
  (args: { sn: string | string[], to: string, memo?: string }): ScriptResponse
637
622
  }
623
+ /** **LOWSEC** */ expose_access_log: (args: { target: string }) => ScriptResponse
624
+ /** **LOWSEC** */ xfer_gc_from: (args: { target: string, amount: number | string }) => ScriptResponse
625
+ /** **LOWSEC** */ expose_balance: (args: { target: string }) => ScriptResponse
638
626
  }
639
627
  }
640
628
 
@@ -719,95 +707,146 @@ type Nullsec = Lowsec & PlayerNullsec & {
719
707
  }
720
708
  }
721
709
 
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
-
726
- type MongoValue = string | number | boolean | Date | MongoValue[] | { [key: string]: MongoValue } | null
727
-
728
- type MongoCommandValue = string | number | boolean | Date | MongoCommandValue[] | { [key: string]: MongoCommandValue } |
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[]
710
+ // database
711
+ type MongoPrimitive = null | boolean | number | Date | string
712
+ type MongoValue = MongoPrimitive | MongoValue[] | MongoObject
713
+ type MongoObject = { [k: string]: MongoValue, [k: `$${string}`]: never }
714
+ type MongoQueryValue = MongoPrimitive | MongoQueryValue[] | MongoQueryObject
715
+
716
+ type MongoQueryObject =
717
+ { [k: string]: MongoQueryValue, [k: `$${string}`]: MongoValue, $type?: keyof MongoTypeStringsToTypes | (string & {}) }
718
+
719
+ type MongoTypeStringsToTypes = {
720
+ double: number
721
+ string: string
722
+ object: MongoObject
723
+ array: MongoValue[]
724
+ objectId: ObjectId
725
+ bool: boolean
726
+ date: Date
727
+ null: null
728
+ int: number
729
+ long: number
739
730
  }
740
731
 
741
- type MongoArraySelectors<T extends Array<MongoValue> = Array<MongoValue>> = {
742
- $all: T
743
- $elemMatch: T
744
- $size: number
732
+ type MongoTypeString = keyof MongoTypeStringsToTypes
733
+ type MongoTypeNumber = -1 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 127
734
+ type MongoId = Exclude<MongoPrimitive, null> | MongoObject
735
+ type MongoQueryId = Exclude<MongoPrimitive, null> | MongoQueryObject
736
+ type MongoDocument = MongoObject & { _id?: MongoId }
737
+
738
+ type MongoQueryType<TQuery extends MongoQueryObject> = {
739
+ -readonly [K in keyof TQuery]:
740
+ TQuery[K] extends MongoPrimitive ?
741
+ TQuery[K]
742
+ : TQuery[K] extends { $type: infer TType } ?
743
+ TType extends keyof MongoTypeStringsToTypes ? MongoTypeStringsToTypes[TType] : unknown
744
+ : TQuery[K] extends { $in: (infer TIn)[] } ?
745
+ TIn
746
+ : keyof TQuery[K] extends `$${string}` ?
747
+ unknown
748
+ : TQuery[K] extends { [k: string]: any } ?
749
+ MongoQueryType<TQuery[K]>
750
+ : never
745
751
  }
746
752
 
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
- }
753
+ type MongoCommandValue = MongoPrimitive | MongoCommandValue[] | { [k: string]: MongoCommandValue }
754
+ type MongoArraySelectors<T extends MongoValue[] = MongoValue[]> = { $all: T, $elemMatch: T, $size: number }
757
755
 
758
- type MongoElementSelectors = {
759
- $exists: boolean
760
- $type: MongoTypeNumber | MongoTypeString
761
- }
756
+ type MongoComparisonSelectors<T extends MongoValue = MongoValue> =
757
+ { $eq: T, $gt: T, $gte: T, $in: T[], $lt: T, $lte: T, $ne: T, $nin: T[] }
758
+
759
+ type MongoElementSelectors = { $exists: boolean, $type: MongoTypeNumber | MongoTypeString }
762
760
 
763
- type MongoQuerySelector<T extends MongoValue = MongoValue> = Partial<T extends MongoValue[] ?
764
- (MongoArraySelectors<T> & MongoElementSelectors & MongoComparisonSelectors<T>) :
765
- (MongoElementSelectors & MongoComparisonSelectors<T>)>
761
+ type MongoQuerySelector<T extends MongoValue> = Partial<
762
+ T extends []
763
+ ? MongoArraySelectors<T> & MongoElementSelectors & MongoComparisonSelectors<T>
764
+ : MongoElementSelectors & MongoComparisonSelectors<T>
765
+ >
766
766
 
767
- type Query = { [key: string]: MongoValue | Query } & { _id?: Id, $in?: MongoValue[] }
767
+ type MongoQuery<T extends MongoObject> = { [K in keyof T]?: T[K] | MongoQuerySelector<T[K]> } & { _id?: MongoId }
768
768
  type Projection = Record<string, boolean | 0 | 1>
769
769
 
770
- type MongoCommand = MongoCommandValue & Partial<
771
- { $set: Record<string, MongoCommandValue>, $push: Record<string, MongoCommandValue>, $unset: Record<string, ""> }
772
- >
770
+ type MongoUpdateOperators<T extends MongoObject> = Partial<{
771
+ /* Universal operators */
772
+ $set: Partial<Record<string, MongoCommandValue> & T>
773
+ $setOnInsert: Partial<Record<string, MongoCommandValue> & T>
774
+ $unset: Partial<Record<string, ""> & T>
775
+
776
+ $rename: Partial<Record<string, string> & { [key in keyof T]: string }>
777
+
778
+ /* Date & number operators */
779
+ $inc: Record<string, number> &
780
+ { [K in keyof T as T[K] extends number | Date ? K : never]?: T[K] extends number ? number : Date }
781
+
782
+ $mul: Record<string, number> & { [K in keyof T as T[K] extends number ? K : never]?: number }
783
+ $min: Record<string, number> & { [K in keyof T as T[K] extends number ? K : never]?: number }
784
+ $max: Record<string, number> & { [K in keyof T as T[K] extends number ? K : never]?: number }
785
+
786
+ /* Array operators */
787
+ $pop: Record<string, -1 | 1> & { [K in keyof T as T[K] extends [] ? K : never]?: -1 | 1 }
788
+
789
+ $push: Record<string, MongoCommandValue> & {
790
+ [K in keyof T as T[K] extends [] ? K : never]?: (T[K] extends (infer U)[] ? U : never)
791
+ | MongoUpdateArrayOperatorModifiers<T[K]>
792
+ }
793
+
794
+ $addToSet: Partial<Record<string, MongoCommandValue> & {
795
+ [K in keyof T as T[K] extends [] ? K : never]: (T[K] extends (infer U)[] ? U : never)
796
+ | MongoUpdateArrayOperatorUniversalModifiers<T[K]>
797
+ }>
798
+
799
+ $pull: Partial<Record<string, MongoCommandValue> & {
800
+ [K in keyof T as T[K] extends [] ? K : never]: (T[K] extends (infer U)[] ? U : never)
801
+ | MongoQuerySelector<T[K]>
802
+ }>
803
+
804
+ $pullAll: Record<string, MongoCommandValue> & { [K in keyof T as T[K] extends [] ? K : never]?: T[K] }
805
+ }>
806
+
807
+ type MongoUpdateArrayOperatorUniversalModifiers<T> = { $each?: T extends [] ? T : T[] }
808
+
809
+ type MongoUpdateArrayOperatorModifiers<T> = MongoUpdateArrayOperatorUniversalModifiers<T> &
810
+ { $position?: number, $slice?: number, $sort?: 1 | -1 }
811
+
812
+ type MongoUpdateCommand<Schema extends MongoObject> = MongoUpdateOperators<Schema>
773
813
 
774
- type Id = string | number | boolean | Date | Record<string, MongoValue>
775
- type MongoDocument = { [key: string]: MongoValue, _id: Id }
776
814
  type SortOrder = { [key: string]: 1 | -1 | SortOrder }
777
815
 
778
- type Cursor = {
779
- /** Returns the first document that satisfies the query. */ first: () => MongoDocument | null
780
- /** Returns an array of documents that satisfy the query. */ array: () => MongoDocument[]
816
+ type Cursor<T> = {
817
+ /** Returns the first document that satisfies the query. */ first: () => T | null
818
+ /** Returns an array of documents that satisfy the query. */ array: () => T[]
781
819
  /** Returns the number of documents that match the query. */ count: () => number
782
820
 
783
821
  /** Returns the first document that satisfies the query. Also makes cursor unusable. */
784
- first_and_close: () => MongoDocument
822
+ first_and_close: () => T
785
823
 
786
824
  /** Returns an array of documents that satisfy the query. Also makes cursor unusable. */
787
- array_and_close: () => MongoDocument[]
825
+ array_and_close: () => T[]
788
826
 
789
827
  /** Returns the number of documents that match the query. Also makes cursor unusable. */
790
828
  count_and_close: () => number
791
829
 
792
830
  /** Run `callback` on each document that satisfied the query. */
793
- each: (callback: (document: MongoDocument) => void) => null
831
+ each: (callback: (document: T) => void) => null
794
832
 
795
833
  /** Returns a new cursor with documents sorted as specified.
796
834
  * A value of 1 sorts the property ascending, and -1 descending.
797
835
  * @param order The way the documents are to be sorted. */
798
- sort: (order?: SortOrder) => Cursor
836
+ sort: (order?: SortOrder) => Cursor<T>
799
837
 
800
838
  /** Returns a new cursor without the first number of documents.
801
839
  * @param count Number of documents to skip. */
802
- skip: (count: number) => Cursor
840
+ skip: (count: number) => Cursor<T>
803
841
 
804
842
  /** Returns a new cursor limited to a number of documents as specified.
805
843
  * @param count Number of documents. */
806
- limit: (count: number) => Cursor
844
+ limit: (count: number) => Cursor<T>
807
845
 
808
- /** @param key The key of the documents. */ distinct: ((key: string) => MongoValue[]) & ((key: "_id") => Id[])
846
+ /** @param key The key of the documents. */ distinct: { (key: string): MongoValue[], (key: "_id"): MongoId[] }
809
847
  /** Make cursor unusable. */ close: () => null
810
848
  NumberLong: (number: number) => number
849
+ // TODO what actually is the type here?
811
850
  ObjectId: () => any
812
851
  }
813
852
 
@@ -818,7 +857,9 @@ type CliContext = {
818
857
  /** The number of rows in the caller’s terminal. */ rows: number
819
858
 
820
859
  /** The name of the script that directly called this script, or null if called on the command line or as a
821
- * scriptor. */ calling_script: null
860
+ * scriptor. */
861
+ calling_script: null
862
+
822
863
  is_scriptor?: undefined
823
864
  is_brain?: undefined
824
865
  }
@@ -829,12 +870,8 @@ type SubscriptContext = Replace<CliContext, {
829
870
  calling_script: string
830
871
  }>
831
872
 
832
- type ScriptorContext =
833
- Replace<CliContext, { /** Whether the script is being run as a scriptor. */ is_scriptor: true }>
834
-
835
- type BrainContext =
836
- Replace<CliContext, { /** Whether the script is being run via a bot brain. */ is_brain: true }>
837
-
873
+ type ScriptorContext = Replace<CliContext, { /** Whether the script is being run as a scriptor. */ is_scriptor: true }>
874
+ type BrainContext = Replace<CliContext, { /** Whether the script is being run via a bot brain. */ is_brain: true }>
838
875
  type Context = CliContext | SubscriptContext | ScriptorContext | BrainContext
839
876
 
840
877
  /** Subscript space that can call FULLSEC scripts. */ declare const $fs: Fullsec
@@ -871,8 +908,8 @@ declare const $0s: typeof $ns
871
908
 
872
909
  /** Subscript space that can call any script. Uses seclevel provided in comment before script (defaults to NULLSEC)
873
910
  * @example
874
- * // @ seclevel MIDSEC
875
- * // remove the space betwen "@" and "s", there's only a space because otherwise vscode breaks
911
+ * // @​seclevel MIDSEC
912
+ * // note, do NOT copy paste the above line because there is a zero-width space inserted between "@" and "s"
876
913
  * export function script() {
877
914
  * $s.foo.bar() // will be converted to #ms.foo.bar()
878
915
  * } */
@@ -880,99 +917,65 @@ declare const $s: Nullsec
880
917
 
881
918
  type ObjectId = { $oid: string }
882
919
 
920
+ // _id is always returned unless _id: false is passed
921
+ // when anyField: true is given, other fields (except _id) are omitted
922
+
923
+ type MongoProject<TDocument, TProjection> =
924
+ true extends (1 extends TProjection[keyof TProjection] ? true : TProjection[keyof TProjection]) ?
925
+ (TProjection extends { _id: false | 0 } ? {} : { _id: TDocument extends { _id: infer TId } ? TId : MongoId }) &
926
+ {
927
+ [K in
928
+ keyof TDocument as K extends keyof TProjection ? TProjection[K] extends true | 1 ? K : never : never
929
+ ]: TDocument[K]
930
+ } &
931
+ {
932
+ -readonly [K in
933
+ keyof TProjection as TProjection[K] extends true | 1 ? K extends keyof TDocument ? never : K : never
934
+ ]?: MongoValue
935
+ }
936
+ : { [k: string]: MongoValue } & { [K in keyof TDocument as K extends keyof TProjection ? never : K]: TDocument[K] }
937
+
883
938
  declare const $db: {
884
939
  /** Insert a document or documents into a collection.
885
940
  * @param documents A document or array of documents to insert into the collection. */
886
- i: (documents: object | object[]) => {
887
- ok: 1
888
- n: number
889
- opTime: { ts: "Undefined Conversion", t: number }
890
- electionId: "Undefined Conversion"
891
- operationTime: "Undefined Conversion"
892
- $clusterTime: {
893
- clusterTime: "Undefined Conversion"
894
- signature: { hash: "Undefined Conversion", keyId: "Undefined Conversion" }
895
- }
896
- }
941
+ i: <T extends MongoDocument>(documents: (T & { _id?: MongoId }) | (T & { _id?: MongoId })[]) =>
942
+ { n: number, opTime: { t: number }, ok: 0 | 1 }[]
897
943
 
898
944
  /** Remove documents from a collection.
899
945
  * @param query Specifies deletion criteria using query operators. */
900
- r: (query: Query) => {
901
- ok: 0 | 1
902
- n: number
903
- opTime: { ts: "Undefined Conversion", t: number }
904
- electionId: "Undefined Conversion"
905
- operationTime: "Undefined Conversion"
906
- $clusterTime: {
907
- clusterTime: "Undefined Conversion"
908
- signature: { hash: "Undefined Conversion", keyId: "Undefined Conversion" }
909
- }
910
- }
946
+ r: <T extends MongoDocument>(query: MongoQuery<T>) => { n: number, opTime: { t: number }, ok: 0 | 1 }[]
911
947
 
912
948
  /** Find documents in a collection or view and returns a cursor to the selected documents.
913
949
  * @param query Specifies deletion criteria using query operators.
914
950
  * @param projection Specifies the fields to return in the documents that match the query filter. */
915
- f: (query?: Query, projection?: Projection) => Cursor
951
+ f: <
952
+ const TQuery extends MongoQueryObject & { _id?: MongoQueryId },
953
+ const TProjection extends { [k: string]: boolean | 0 | 1 } = {}
954
+ >(query: TQuery, projection?: TProjection) => Cursor<MongoProject<MongoQueryType<TQuery>, TProjection>>
916
955
 
917
- /** Update an existing documents in a collection.
956
+ /** Update existing documents in a collection.
918
957
  * @param query Specifies deletion criteria using query operators.
919
958
  * @param command The modifications to apply.
920
959
  * {@link https://docs.mongodb.com/manual/reference/method/db.collection.update/#parameters} */
921
- u: (query: Query | Query[], command: MongoCommand) => {
922
- ok: 0 | 1
923
- nModified: number
924
- n: number
925
- opTime: { ts: "Undefined Conversion", t: number }
926
- electionId: "Undefined Conversion"
927
- operationTime: "Undefined Conversion"
928
- $clusterTime: {
929
- clusterTime: "Undefined Conversion"
930
- signature: { hash: "Undefined Conversion", keyId: "Undefined Conversion" }
931
- }
932
- }
960
+ u: <T extends MongoDocument>(query: MongoQuery<T> | MongoQuery<T>[], command: MongoUpdateCommand<T>) =>
961
+ { n: number, opTime: { t: number }, ok: 0 | 1, nModified: number }[]
933
962
 
934
963
  /** Updates one document within the collection based on the filter.
935
964
  * @param query Specifies deletion criteria using query operators.
936
965
  * @param command The modifications to apply.
937
966
  * {@link https://docs.mongodb.com/manual/reference/method/db.collection.update/#parameters} */
938
- u1: (query: Query | Query[], command: MongoCommand) => {
939
- ok: 0 | 1
940
- nModified: number
941
- n: number
942
- opTime: {
943
- ts: "Undefined Conversion"
944
- t: number
945
- }
946
- electionId: "Undefined Conversion"
947
- operationTime: "Undefined Conversion"
948
- $clusterTime: {
949
- clusterTime: "Undefined Conversion"
950
- signature: {
951
- hash: "Undefined Conversion"
952
- keyId: "Undefined Conversion"
953
- }
954
- }
955
- }
967
+ u1: <T extends MongoDocument>(query: MongoQuery<T> | MongoQuery<T>[], command: MongoUpdateCommand<T>) =>
968
+ { n: number, ok: 0 | 1, opTime: { t: number }, nModified: number }[]
956
969
 
957
- /** Update or insert or insert document.
970
+ /** Update or insert document.
958
971
  * Same as Update, but if no documents match the query, one document will be inserted based on the properties in
959
972
  * both the query and the command.
960
973
  * The `$setOnInsert` operator is useful to set defaults.
961
974
  * @param query Specifies deletion criteria using query operators.
962
975
  * @param command The modifications to apply.
963
976
  * {@link https://docs.mongodb.com/manual/reference/method/db.collection.update/#parameters} */
964
- us: (query: Query | Query[], command: MongoCommand) => {
965
- ok: 0 | 1
966
- nModified: number
967
- n: number
968
- opTime: { ts: "Undefined Conversion", t: number }
969
- electionId: "Undefined Conversion"
970
- operationTime: "Undefined Conversion"
971
- $clusterTime: {
972
- clusterTime: "Undefined Conversion"
973
- signature: { hash: "Undefined Conversion", keyId: "Undefined Conversion" }
974
- }
975
- }
977
+ us: <T extends MongoDocument>(query: MongoQuery<T> | MongoQuery<T>[], command: MongoUpdateCommand<T>) =>
978
+ { n: number, ok: 0 | 1, opTime: { t: number }, nModified: number }[]
976
979
 
977
980
  ObjectId: () => ObjectId
978
981
  }
package/index.js CHANGED
@@ -46,7 +46,7 @@ import "import-meta-resolve"
46
46
  import "./processScript/transform.js"
47
47
  import "@samual/lib/clearObject"
48
48
  import "@samual/lib/copyFilePersistent"
49
- import "@samual/lib/Cache"
49
+ import "@samual/lib/AutoMap"
50
50
  import "@samual/lib/writeFilePersistent"
51
51
  import "fs/promises"
52
52
  import "chokidar"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hackmud-script-manager",
3
- "version": "0.20.4-550e28d",
3
+ "version": "0.20.4-698da0d",
4
4
  "description": "Script manager for game hackmud, with minification, TypeScript support, and player script type definition generation.",
5
5
  "keywords": [
6
6
  "api",
@@ -31,50 +31,50 @@
31
31
  "url": "https://github.com/samualtnorman/hackmud-script-manager.git"
32
32
  },
33
33
  "dependencies": {
34
- "@babel/generator": "^7.24.4",
35
- "@babel/parser": "^7.24.4",
36
- "@babel/plugin-proposal-decorators": "^7.24.1",
37
- "@babel/plugin-proposal-destructuring-private": "^7.24.1",
38
- "@babel/plugin-proposal-do-expressions": "^7.24.1",
39
- "@babel/plugin-proposal-explicit-resource-management": "^7.24.1",
40
- "@babel/plugin-proposal-function-bind": "^7.24.1",
41
- "@babel/plugin-proposal-function-sent": "^7.24.1",
42
- "@babel/plugin-proposal-partial-application": "^7.24.1",
43
- "@babel/plugin-proposal-pipeline-operator": "^7.24.1",
44
- "@babel/plugin-proposal-record-and-tuple": "^7.24.1",
45
- "@babel/plugin-proposal-throw-expressions": "^7.24.1",
46
- "@babel/plugin-transform-class-properties": "^7.24.1",
47
- "@babel/plugin-transform-class-static-block": "^7.24.4",
48
- "@babel/plugin-transform-exponentiation-operator": "^7.24.1",
49
- "@babel/plugin-transform-json-strings": "^7.24.1",
50
- "@babel/plugin-transform-logical-assignment-operators": "^7.24.1",
51
- "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1",
52
- "@babel/plugin-transform-numeric-separator": "^7.24.1",
53
- "@babel/plugin-transform-object-rest-spread": "^7.24.1",
54
- "@babel/plugin-transform-optional-catch-binding": "^7.24.1",
55
- "@babel/plugin-transform-optional-chaining": "^7.24.1",
56
- "@babel/plugin-transform-private-property-in-object": "^7.24.1",
57
- "@babel/plugin-transform-typescript": "^7.24.4",
58
- "@babel/plugin-transform-unicode-sets-regex": "^7.24.1",
59
- "@babel/traverse": "^7.24.1",
60
- "@babel/types": "^7.24.0",
34
+ "@babel/generator": "^7.26.2",
35
+ "@babel/parser": "^7.26.2",
36
+ "@babel/plugin-proposal-decorators": "^7.25.9",
37
+ "@babel/plugin-proposal-destructuring-private": "^7.26.0",
38
+ "@babel/plugin-proposal-do-expressions": "^7.25.9",
39
+ "@babel/plugin-proposal-explicit-resource-management": "^7.25.9",
40
+ "@babel/plugin-proposal-function-bind": "^7.25.9",
41
+ "@babel/plugin-proposal-function-sent": "^7.25.9",
42
+ "@babel/plugin-proposal-partial-application": "^7.25.9",
43
+ "@babel/plugin-proposal-pipeline-operator": "^7.25.9",
44
+ "@babel/plugin-proposal-record-and-tuple": "^7.25.9",
45
+ "@babel/plugin-proposal-throw-expressions": "^7.25.9",
46
+ "@babel/plugin-transform-class-properties": "^7.25.9",
47
+ "@babel/plugin-transform-class-static-block": "^7.26.0",
48
+ "@babel/plugin-transform-exponentiation-operator": "^7.25.9",
49
+ "@babel/plugin-transform-json-strings": "^7.25.9",
50
+ "@babel/plugin-transform-logical-assignment-operators": "^7.25.9",
51
+ "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9",
52
+ "@babel/plugin-transform-numeric-separator": "^7.25.9",
53
+ "@babel/plugin-transform-object-rest-spread": "^7.25.9",
54
+ "@babel/plugin-transform-optional-catch-binding": "^7.25.9",
55
+ "@babel/plugin-transform-optional-chaining": "^7.25.9",
56
+ "@babel/plugin-transform-private-property-in-object": "^7.25.9",
57
+ "@babel/plugin-transform-typescript": "^7.25.9",
58
+ "@babel/plugin-transform-unicode-sets-regex": "^7.25.9",
59
+ "@babel/traverse": "^7.25.9",
60
+ "@babel/types": "^7.26.0",
61
61
  "@bloomberg/record-tuple-polyfill": "^0.0.4",
62
62
  "@rollup/plugin-babel": "^6.0.4",
63
- "@rollup/plugin-commonjs": "^25.0.7",
63
+ "@rollup/plugin-commonjs": "^28.0.1",
64
64
  "@rollup/plugin-json": "^6.1.0",
65
- "@rollup/plugin-node-resolve": "^15.2.3",
66
- "@samual/lib": "0.11.0",
67
- "acorn": "^8.11.3",
65
+ "@rollup/plugin-node-resolve": "^15.3.0",
66
+ "@samual/lib": "^0.13.0",
67
+ "acorn": "^8.14.0",
68
68
  "chalk": "^5.3.0",
69
- "chokidar": "^3.6.0",
70
- "import-meta-resolve": "^4.0.0",
71
- "prettier": "^3.2.5",
69
+ "chokidar": "^4.0.1",
70
+ "import-meta-resolve": "^4.1.0",
71
+ "prettier": "^3.3.3",
72
72
  "proxy-polyfill": "^0.3.2",
73
- "rollup": "^4.16.4",
74
- "terser": "^5.30.4"
73
+ "rollup": "^4.27.4",
74
+ "terser": "^5.36.0"
75
75
  },
76
76
  "peerDependencies": {
77
- "typescript": "5.4.5"
77
+ "typescript": "^5.4.5"
78
78
  },
79
79
  "type": "module",
80
80
  "exports": {
@@ -86,6 +86,6 @@
86
86
  "hsm": "bin/hsm.js"
87
87
  },
88
88
  "engines": {
89
- "node": "^18 || >=20"
89
+ "node": "^18 || ^20 || >=22"
90
90
  }
91
91
  }
@@ -204,6 +204,7 @@ async function processScript(
204
204
  const bundle = await rollup({
205
205
  input: filePathResolved,
206
206
  plugins: [
207
+ rollupPluginJSON({ preferConst: !0 }),
207
208
  {
208
209
  name: "hackmud-script-manager",
209
210
  async transform(code, id) {
@@ -227,8 +228,7 @@ async function processScript(
227
228
  },
228
229
  babel({ babelHelpers: "bundled", plugins, configFile: !1, extensions: supportedExtensions }),
229
230
  rollupPluginCommonJS(),
230
- rollupPluginNodeResolve({ extensions: supportedExtensions }),
231
- rollupPluginJSON()
231
+ rollupPluginNodeResolve({ extensions: supportedExtensions })
232
232
  ],
233
233
  treeshake: { moduleSideEffects: !1 }
234
234
  }),
@@ -162,21 +162,25 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
162
162
  if (program.scope.hasGlobal("_SECLEVEL"))
163
163
  for (const referencePath of getReferencePathsToGlobal("_SECLEVEL", program))
164
164
  referencePath.replaceWith(t.numericLiteral(seclevel))
165
- let needGetPrototypeOf = !1
165
+ let needGetPrototypeOf = !1,
166
+ needHasOwn = !1
166
167
  if (program.scope.hasGlobal("Object"))
167
168
  for (const referencePath of getReferencePathsToGlobal("Object", program))
168
169
  if ("MemberExpression" == referencePath.parent.type && !referencePath.parent.computed) {
169
- assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:241:64")
170
+ assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:242:64")
170
171
  if ("getPrototypeOf" == referencePath.parent.property.name) {
171
172
  referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_GET_PROTOTYPE_OF_`))
172
173
  needGetPrototypeOf = !0
174
+ } else if ("hasOwn" == referencePath.parent.property.name) {
175
+ referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_HAS_OWN_`))
176
+ needHasOwn = !0
173
177
  }
174
178
  }
175
179
  const consoleMethodsReferenced = new Set()
176
180
  if (program.scope.hasGlobal("console"))
177
181
  for (const referencePath of getReferencePathsToGlobal("console", program))
178
182
  if ("MemberExpression" == referencePath.parent.type && !referencePath.parent.computed) {
179
- assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:256:64")
183
+ assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:260:64")
180
184
  referencePath.parentPath.replaceWith(
181
185
  t.identifier(`_${uniqueId}_CONSOLE_METHOD_${referencePath.parent.property.name}_`)
182
186
  )
@@ -184,13 +188,13 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
184
188
  }
185
189
  const lastStatement = program.node.body.at(-1)
186
190
  let exportDefaultName
187
- assert(lastStatement, "src/processScript/transform.ts:270:27 program is empty")
191
+ assert(lastStatement, "src/processScript/transform.ts:274:27 program is empty")
188
192
  if ("ExportNamedDeclaration" == lastStatement.type) {
189
193
  program.node.body.pop()
190
194
  for (const specifier of lastStatement.specifiers) {
191
195
  assert(
192
196
  "ExportSpecifier" == specifier.type,
193
- `src/processScript/transform.ts:276:51 ${specifier.type} is currently unsupported`
197
+ `src/processScript/transform.ts:280:51 ${specifier.type} is currently unsupported`
194
198
  )
195
199
  if (
196
200
  "default" !=
@@ -292,11 +296,11 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
292
296
  let hoistedGlobalBlockFunctions = 0
293
297
  for (const [globalBlockIndex, globalBlockStatement] of [...globalBlock.body.entries()].reverse())
294
298
  if ("VariableDeclaration" == globalBlockStatement.type) {
295
- assert(1 == globalBlockStatement.declarations.length, "src/processScript/transform.ts:390:59")
299
+ assert(1 == globalBlockStatement.declarations.length, "src/processScript/transform.ts:394:59")
296
300
  const declarator = globalBlockStatement.declarations[0]
297
301
  assert(
298
302
  "Identifier" == declarator.id.type,
299
- `src/processScript/transform.ts:394:51 declarator.id.type was "${declarator.id.type}"`
303
+ `src/processScript/transform.ts:398:51 declarator.id.type was "${declarator.id.type}"`
300
304
  )
301
305
  program.scope.crawl()
302
306
  if (program.scope.hasGlobal(declarator.id.name)) {
@@ -311,9 +315,9 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
311
315
  Object.keys(program.scope.globals).some(global => globalBlockVariables.has(global))
312
316
  ) {
313
317
  const binding = program.scope.getBinding(declarator.id.name)
314
- assert(binding, "src/processScript/transform.ts:413:23")
318
+ assert(binding, "src/processScript/transform.ts:417:23")
315
319
  for (const referencePath of binding.referencePaths) {
316
- assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:416:56")
320
+ assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:420:56")
317
321
  referencePath.replaceWith(
318
322
  t.memberExpression(
319
323
  t.identifier(`_${uniqueId}_G_`),
@@ -361,16 +365,16 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
361
365
  } else globalBlockVariables.add(declarator.id.name)
362
366
  } else if ("ClassDeclaration" == globalBlockStatement.type) {
363
367
  program.scope.crawl()
364
- assert(globalBlockStatement.id, "src/processScript/transform.ts:473:37")
368
+ assert(globalBlockStatement.id, "src/processScript/transform.ts:477:37")
365
369
  if (program.scope.hasGlobal(globalBlockStatement.id.name)) {
366
370
  globalBlock.body.splice(globalBlockIndex, 1)
367
371
  const [globalBlockPath] = program.unshiftContainer("body", globalBlock),
368
372
  [globalBlockStatementPath] = program.unshiftContainer("body", globalBlockStatement)
369
373
  program.scope.crawl()
370
374
  const binding = program.scope.getBinding(globalBlockStatement.id.name)
371
- assert(binding, "src/processScript/transform.ts:485:22")
375
+ assert(binding, "src/processScript/transform.ts:489:22")
372
376
  for (const referencePath of binding.referencePaths) {
373
- assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:488:55")
377
+ assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:492:55")
374
378
  referencePath.replaceWith(
375
379
  t.memberExpression(t.identifier(`_${uniqueId}_G_`), t.identifier(referencePath.node.name))
376
380
  )
@@ -448,6 +452,31 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
448
452
  )
449
453
  ])
450
454
  )
455
+ needHasOwn &&
456
+ mainFunction.body.body.unshift(
457
+ t.variableDeclaration("let", [
458
+ t.variableDeclarator(
459
+ t.identifier(`_${uniqueId}_HAS_OWN_`),
460
+ t.callExpression(
461
+ t.memberExpression(
462
+ t.memberExpression(
463
+ t.identifier(
464
+ globalFunctionsUnder7Characters.find(name => !program.scope.hasOwnBinding(name))
465
+ ),
466
+ t.identifier("call")
467
+ ),
468
+ t.identifier("bind")
469
+ ),
470
+ [
471
+ t.memberExpression(
472
+ t.memberExpression(t.identifier("Object"), t.identifier("prototype")),
473
+ t.identifier("hasOwnProperty")
474
+ )
475
+ ]
476
+ )
477
+ )
478
+ ])
479
+ )
451
480
  consoleMethodsReferenced.size &&
452
481
  mainFunction.body.body.unshift(
453
482
  t.variableDeclaration(
@@ -537,7 +566,7 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
537
566
  }
538
567
  },
539
568
  ClassBody({ node: classBody, scope, parent }) {
540
- assert(t.isClass(parent), "src/processScript/transform.ts:658:30")
569
+ assert(t.isClass(parent), "src/processScript/transform.ts:687:30")
541
570
  let thisIsReferenced = !1
542
571
  for (const classMethod of classBody.body) {
543
572
  if ("ClassMethod" != classMethod.type) continue
@@ -629,39 +658,31 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
629
658
  })
630
659
  return { file, seclevel }
631
660
  function createGetFunctionPrototypeNode() {
632
- for (const globalFunction of globalFunctionsUnder7Characters)
633
- if (!program.scope.hasOwnBinding(globalFunction))
634
- return t.memberExpression(
635
- t.memberExpression(t.identifier(globalFunction), t.identifier("constructor")),
636
- t.identifier("prototype")
637
- )
661
+ const name = globalFunctionsUnder7Characters.find(name => !program.scope.hasOwnBinding(name))
638
662
  return t.memberExpression(
639
- t.memberExpression(
640
- t.arrowFunctionExpression([t.identifier("_")], t.identifier("_")),
641
- t.identifier("constructor")
642
- ),
643
- t.identifier("prototype")
663
+ name ? t.identifier(name) : t.arrowFunctionExpression([t.identifier("_")], t.identifier("_")),
664
+ t.identifier("__proto__")
644
665
  )
645
666
  }
646
667
  function processFakeSubscriptObject(fakeSubscriptObjectName, seclevel) {
647
668
  for (const referencePath of getReferencePathsToGlobal(fakeSubscriptObjectName, program)) {
648
- assert("MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:774:60")
669
+ assert("MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:793:60")
649
670
  assert("Identifier" == referencePath.parent.property.type)
650
671
  assert(
651
672
  "MemberExpression" == referencePath.parentPath.parentPath?.node.type,
652
- "src/processScript/transform.ts:776:81"
673
+ "src/processScript/transform.ts:795:81"
653
674
  )
654
675
  assert(
655
676
  "Identifier" == referencePath.parentPath.parentPath.node.property.type,
656
- "src/processScript/transform.ts:777:83"
677
+ "src/processScript/transform.ts:796:83"
657
678
  )
658
679
  assert(
659
680
  /^[_a-z][\d_a-z]{0,24}$/.test(referencePath.parent.property.name),
660
- `src/processScript/transform.ts:781:8 invalid user "${referencePath.parent.property.name}" in subscript`
681
+ `src/processScript/transform.ts:800:8 invalid user "${referencePath.parent.property.name}" in subscript`
661
682
  )
662
683
  assert(
663
684
  /^[_a-z][\d_a-z]{0,24}$/.test(referencePath.parentPath.parentPath.node.property.name),
664
- `src/processScript/transform.ts:786:8 invalid script name "${referencePath.parentPath.parentPath.node.property.name}" in subscript`
685
+ `src/processScript/transform.ts:805:8 invalid script name "${referencePath.parentPath.parentPath.node.property.name}" in subscript`
665
686
  )
666
687
  if ("CallExpression" == referencePath.parentPath.parentPath.parentPath?.type)
667
688
  referencePath.parentPath.parentPath.replaceWith(
package/push.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Cache } from "@samual/lib/Cache"
1
+ import { AutoMap } from "@samual/lib/AutoMap"
2
2
  import { ensure, assert } from "@samual/lib/assert"
3
3
  import { countHackmudCharacters } from "@samual/lib/countHackmudCharacters"
4
4
  import { readDirectoryWithStats } from "@samual/lib/readDirectoryWithStats"
@@ -84,8 +84,8 @@ async function push(
84
84
  return new NoUsersError(
85
85
  "Could not find any users. Either provide the names of your users or log into a user in hackmud"
86
86
  )
87
- const usersToScriptsToPush = new Cache(_user => new Map()),
88
- scriptNamesToUsers = new Cache(_scriptName => new Set())
87
+ const usersToScriptsToPush = new AutoMap(_user => new Map()),
88
+ scriptNamesToUsers = new AutoMap(_scriptName => new Set())
89
89
  for (const script of scripts) {
90
90
  const [user, scriptName] = script.split(".")
91
91
  assert(user, "src/push.ts:105:16")
@@ -121,7 +121,7 @@ async function push(
121
121
  for (const user of users)
122
122
  if (!usersToScriptsToPush.get(user).has(scriptName))
123
123
  return new NoScriptsError(`Could not find script ${user}.${scriptName} to push`)
124
- const pathsToUsers = new Cache(_path => new Set())
124
+ const pathsToUsers = new AutoMap(_path => new Set())
125
125
  for (const [user, scriptsToPush] of usersToScriptsToPush)
126
126
  for (const path of scriptsToPush.values()) pathsToUsers.get(path).add(user)
127
127
  const allInfo = []
package/watch.js CHANGED
@@ -1,10 +1,10 @@
1
- import { Cache } from "@samual/lib/Cache"
1
+ import { AutoMap } from "@samual/lib/AutoMap"
2
2
  import { assert } from "@samual/lib/assert"
3
3
  import { countHackmudCharacters } from "@samual/lib/countHackmudCharacters"
4
4
  import { readDirectoryWithStats } from "@samual/lib/readDirectoryWithStats"
5
5
  import { writeFilePersistent } from "@samual/lib/writeFilePersistent"
6
6
  import { watch as watch$1 } from "chokidar"
7
- import { readFile, writeFile } from "fs/promises"
7
+ import { stat, readFile, writeFile } from "fs/promises"
8
8
  import { extname, basename, resolve } from "path"
9
9
  import { supportedExtensions } from "./constants.js"
10
10
  import { generateTypeDeclaration } from "./generateTypeDeclaration.js"
@@ -59,7 +59,8 @@ async function watch(
59
59
  } = {}
60
60
  ) {
61
61
  if (!scripts.length) throw Error("scripts option was an empty array")
62
- const scriptNamesToUsers = new Cache(_scriptName => new Set()),
62
+ if (!(await stat(sourceDirectory)).isDirectory()) throw Error("Target folder must be a folder")
63
+ const scriptNamesToUsers = new AutoMap(_scriptName => new Set()),
63
64
  wildScriptUsers = new Set(),
64
65
  wildUserScripts = new Set()
65
66
  let pushEverything = !1
@@ -91,7 +92,7 @@ async function watch(
91
92
  )
92
93
  )
93
94
  return
94
- const scriptNamesToUsersToSkip = new Cache(_scriptName => [])
95
+ const scriptNamesToUsersToSkip = new AutoMap(_scriptName => [])
95
96
  await Promise.all(
96
97
  (await readDirectoryWithStats(sourceDirectory)).map(async ({ stats, name, path }) => {
97
98
  if (stats.isDirectory())
@@ -136,7 +137,7 @@ async function watch(
136
137
  forceQuineCheats
137
138
  }))
138
139
  } catch (error) {
139
- assert(error instanceof Error, "src/watch.ts:141:36")
140
+ assert(error instanceof Error, "src/watch.ts:146:36")
140
141
  onPush?.({ path, users: [], characterCount: 0, error })
141
142
  return
142
143
  }
@@ -181,7 +182,7 @@ async function watch(
181
182
  forceQuineCheats
182
183
  }))
183
184
  } catch (error) {
184
- assert(error instanceof Error, "src/watch.ts:177:35")
185
+ assert(error instanceof Error, "src/watch.ts:182:35")
185
186
  onPush?.({ path, users: [], characterCount: 0, error })
186
187
  return
187
188
  }
@@ -196,7 +197,7 @@ async function watch(
196
197
  try {
197
198
  await writeFile(typeDeclarationPath, typeDeclaration)
198
199
  } catch (error) {
199
- assert(error instanceof Error, "src/watch.ts:210:35")
200
+ assert(error instanceof Error, "src/watch.ts:215:35")
200
201
  if ("EISDIR" != error.code) throw error
201
202
  typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
202
203
  await writeFile(typeDeclarationPath, typeDeclaration)