hackmud-script-manager 0.20.4-c524114 → 0.20.4-c908d16

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,27 +155,32 @@ 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))
166
- let needGetPrototypeOf = !1
165
+ let needGetPrototypeOf = !1,
166
+ needHasOwn = !1
167
167
  if (program.scope.hasGlobal("Object"))
168
168
  for (const referencePath of getReferencePathsToGlobal("Object", program))
169
169
  if ("MemberExpression" == referencePath.parent.type && !referencePath.parent.computed) {
170
- 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")
171
171
  if ("getPrototypeOf" == referencePath.parent.property.name) {
172
172
  referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_GET_PROTOTYPE_OF_`))
173
173
  needGetPrototypeOf = !0
174
+ } else if ("hasOwn" == referencePath.parent.property.name) {
175
+ referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_HAS_OWN_`))
176
+ needHasOwn = !0
174
177
  }
175
178
  }
176
179
  const consoleMethodsReferenced = new Set()
177
180
  if (program.scope.hasGlobal("console"))
178
181
  for (const referencePath of getReferencePathsToGlobal("console", program))
179
182
  if ("MemberExpression" == referencePath.parent.type && !referencePath.parent.computed) {
180
- 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")
181
184
  referencePath.parentPath.replaceWith(
182
185
  t.identifier(`_${uniqueId}_CONSOLE_METHOD_${referencePath.parent.property.name}_`)
183
186
  )
@@ -185,19 +188,20 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
185
188
  }
186
189
  const lastStatement = program.node.body.at(-1)
187
190
  let exportDefaultName
188
- assert(lastStatement, "src/processScript/transform.ts:270:27 program is empty")
191
+ assert(lastStatement, "src/processScript/transform.ts:274:27 program is empty")
189
192
  if ("ExportNamedDeclaration" == lastStatement.type) {
190
193
  program.node.body.pop()
191
194
  for (const specifier of lastStatement.specifiers) {
192
195
  assert(
193
196
  "ExportSpecifier" == specifier.type,
194
- `src/processScript/transform.ts:276:51 ${specifier.type} is currently unsupported`
197
+ `src/processScript/transform.ts:280:51 ${specifier.type} is currently unsupported`
195
198
  )
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)
199
+ if (
200
+ "default" !=
201
+ ("Identifier" == specifier.exported.type ? specifier.exported.name : specifier.exported.value)
202
+ )
203
+ throw Error("Only default exports are supported")
204
+ exportDefaultName = specifier.local.name
201
205
  }
202
206
  }
203
207
  const globalBlock = t.blockStatement([])
@@ -223,10 +227,6 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
223
227
  t.returnStatement(t.callExpression(t.identifier(exportDefaultName), []))
224
228
  ])
225
229
  ))
226
- if ("const" != statement.kind && exports.has(identifierName)) {
227
- liveExports.set(identifierName, exports.get(identifierName))
228
- exports.delete(identifierName)
229
- }
230
230
  globalBlock.body.push(
231
231
  t.variableDeclaration("let", [t.variableDeclarator(t.identifier(identifierName))])
232
232
  )
@@ -291,34 +291,16 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
291
291
  }
292
292
  program.node.body = [mainFunction]
293
293
  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
294
  program.scope.crawl()
313
295
  const globalBlockVariables = new Set()
314
296
  let hoistedGlobalBlockFunctions = 0
315
297
  for (const [globalBlockIndex, globalBlockStatement] of [...globalBlock.body.entries()].reverse())
316
298
  if ("VariableDeclaration" == globalBlockStatement.type) {
317
- assert(1 == globalBlockStatement.declarations.length, "src/processScript/transform.ts:410:59")
299
+ assert(1 == globalBlockStatement.declarations.length, "src/processScript/transform.ts:394:59")
318
300
  const declarator = globalBlockStatement.declarations[0]
319
301
  assert(
320
302
  "Identifier" == declarator.id.type,
321
- `src/processScript/transform.ts:414:51 declarator.id.type was "${declarator.id.type}"`
303
+ `src/processScript/transform.ts:398:51 declarator.id.type was "${declarator.id.type}"`
322
304
  )
323
305
  program.scope.crawl()
324
306
  if (program.scope.hasGlobal(declarator.id.name)) {
@@ -333,15 +315,16 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
333
315
  Object.keys(program.scope.globals).some(global => globalBlockVariables.has(global))
334
316
  ) {
335
317
  const binding = program.scope.getBinding(declarator.id.name)
336
- assert(binding, "src/processScript/transform.ts:433:23")
318
+ assert(binding, "src/processScript/transform.ts:417:23")
337
319
  for (const referencePath of binding.referencePaths) {
338
- assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:436:56")
320
+ assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:420:56")
339
321
  referencePath.replaceWith(
340
322
  t.memberExpression(
341
- t.identifier(`$${uniqueId}$GLOBAL$`),
323
+ t.identifier(`_${uniqueId}_G_`),
342
324
  t.identifier(referencePath.node.name)
343
325
  )
344
326
  )
327
+ needG = !0
345
328
  }
346
329
  for (const referencePath of binding.constantViolations)
347
330
  if ("AssignmentExpression" == referencePath.node.type)
@@ -350,12 +333,13 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
350
333
  clearObject(node)
351
334
  Object.assign(
352
335
  node,
353
- t.memberExpression(t.identifier(`$${uniqueId}$GLOBAL$`), t.identifier(name))
336
+ t.memberExpression(t.identifier(`_${uniqueId}_G_`), t.identifier(name))
354
337
  )
338
+ needG = !0
355
339
  }
356
340
  globalBlockPath.remove()
357
341
  globalBlockStatementPath.remove()
358
- declarator.init &&
342
+ if (declarator.init) {
359
343
  globalBlock.body.splice(
360
344
  globalBlockIndex,
361
345
  0,
@@ -363,13 +347,15 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
363
347
  t.assignmentExpression(
364
348
  "=",
365
349
  t.memberExpression(
366
- t.identifier(`$${uniqueId}$GLOBAL$`),
350
+ t.identifier(`_${uniqueId}_G_`),
367
351
  t.identifier(declarator.id.name)
368
352
  ),
369
353
  declarator.init
370
354
  )
371
355
  )
372
356
  )
357
+ needG = !0
358
+ }
373
359
  } else {
374
360
  globalBlockPath.remove()
375
361
  globalBlockStatementPath.remove()
@@ -379,22 +365,20 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
379
365
  } else globalBlockVariables.add(declarator.id.name)
380
366
  } else if ("ClassDeclaration" == globalBlockStatement.type) {
381
367
  program.scope.crawl()
382
- assert(globalBlockStatement.id, "src/processScript/transform.ts:487:37")
368
+ assert(globalBlockStatement.id, "src/processScript/transform.ts:477:37")
383
369
  if (program.scope.hasGlobal(globalBlockStatement.id.name)) {
384
370
  globalBlock.body.splice(globalBlockIndex, 1)
385
371
  const [globalBlockPath] = program.unshiftContainer("body", globalBlock),
386
372
  [globalBlockStatementPath] = program.unshiftContainer("body", globalBlockStatement)
387
373
  program.scope.crawl()
388
374
  const binding = program.scope.getBinding(globalBlockStatement.id.name)
389
- assert(binding, "src/processScript/transform.ts:499:22")
375
+ assert(binding, "src/processScript/transform.ts:489:22")
390
376
  for (const referencePath of binding.referencePaths) {
391
- assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:502:55")
377
+ assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:492:55")
392
378
  referencePath.replaceWith(
393
- t.memberExpression(
394
- t.identifier(`$${uniqueId}$GLOBAL$`),
395
- t.identifier(referencePath.node.name)
396
- )
379
+ t.memberExpression(t.identifier(`_${uniqueId}_G_`), t.identifier(referencePath.node.name))
397
380
  )
381
+ needG = !0
398
382
  }
399
383
  globalBlockPath.remove()
400
384
  globalBlockStatementPath.remove()
@@ -405,7 +389,7 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
405
389
  t.assignmentExpression(
406
390
  "=",
407
391
  t.memberExpression(
408
- t.identifier(`$${uniqueId}$GLOBAL$`),
392
+ t.identifier(`_${uniqueId}_G_`),
409
393
  t.identifier(globalBlockStatement.id.name)
410
394
  ),
411
395
  t.classExpression(
@@ -417,13 +401,9 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
417
401
  )
418
402
  )
419
403
  )
404
+ needG = !0
420
405
  }
421
406
  }
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
407
  globalBlock.body.length &&
428
408
  mainFunction.body.body.splice(
429
409
  hoistedGlobalBlockFunctions,
@@ -472,6 +452,31 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
472
452
  )
473
453
  ])
474
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
+ )
475
480
  consoleMethodsReferenced.size &&
476
481
  mainFunction.body.body.unshift(
477
482
  t.variableDeclaration(
@@ -522,12 +527,12 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
522
527
  mainFunction.body.body.unshift(
523
528
  t.variableDeclaration(
524
529
  "let",
525
- [...neededSubscriptLets].map(name =>
530
+ [...neededSubscriptLets].map(([name, seclevel]) =>
526
531
  t.variableDeclarator(
527
532
  t.identifier(`_${uniqueId}_SUBSCRIPT_${name}_`),
528
533
  t.arrowFunctionExpression(
529
534
  [t.restElement(t.identifier("args"))],
530
- t.callExpression(t.identifier(`$${uniqueId}$SUBSCRIPT$${name}$`), [
535
+ t.callExpression(t.identifier(`$${uniqueId}$${seclevel}$SUBSCRIPT$${name}$`), [
531
536
  t.spreadElement(t.identifier("args"))
532
537
  ])
533
538
  )
@@ -535,6 +540,12 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
535
540
  )
536
541
  )
537
542
  )
543
+ needG &&
544
+ mainFunction.body.body.unshift(
545
+ t.variableDeclaration("let", [
546
+ t.variableDeclarator(t.identifier(`_${uniqueId}_G_`), t.identifier(`$${uniqueId}$GLOBAL$`))
547
+ ])
548
+ )
538
549
  traverse(file, {
539
550
  BlockStatement({ node: blockStatement }) {
540
551
  for (const [index, functionDeclaration] of blockStatement.body.entries())
@@ -555,7 +566,7 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
555
566
  }
556
567
  },
557
568
  ClassBody({ node: classBody, scope, parent }) {
558
- assert(t.isClass(parent), "src/processScript/transform.ts:669:30")
569
+ assert(t.isClass(parent), "src/processScript/transform.ts:687:30")
559
570
  let thisIsReferenced = !1
560
571
  for (const classMethod of classBody.body) {
561
572
  if ("ClassMethod" != classMethod.type) continue
@@ -631,7 +642,9 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
631
642
  VariableDeclaration({ node: variableDeclaration }) {
632
643
  "const" == variableDeclaration.kind && (variableDeclaration.kind = "let")
633
644
  },
634
- ThisExpression: path => path.replaceWith(t.identifier("undefined")),
645
+ ThisExpression: path => {
646
+ path.replaceWith(t.identifier("undefined"))
647
+ },
635
648
  BigIntLiteral(path) {
636
649
  const bigIntAsNumber = Number(path.node.value)
637
650
  path.replaceWith(
@@ -645,50 +658,43 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
645
658
  })
646
659
  return { file, seclevel }
647
660
  function createGetFunctionPrototypeNode() {
648
- for (const globalFunction of globalFunctionsUnder7Characters)
649
- if (!program.scope.hasOwnBinding(globalFunction))
650
- return t.memberExpression(
651
- t.memberExpression(t.identifier(globalFunction), t.identifier("constructor")),
652
- t.identifier("prototype")
653
- )
661
+ const name = globalFunctionsUnder7Characters.find(name => !program.scope.hasOwnBinding(name))
654
662
  return t.memberExpression(
655
- t.memberExpression(
656
- t.arrowFunctionExpression([t.identifier("_")], t.identifier("_")),
657
- t.identifier("constructor")
658
- ),
659
- t.identifier("prototype")
663
+ name ? t.identifier(name) : t.arrowFunctionExpression([t.identifier("_")], t.identifier("_")),
664
+ t.identifier("__proto__")
660
665
  )
661
666
  }
662
- function processFakeSubscriptObject(fakeSubscriptObjectName) {
667
+ function processFakeSubscriptObject(fakeSubscriptObjectName, seclevel) {
663
668
  for (const referencePath of getReferencePathsToGlobal(fakeSubscriptObjectName, program)) {
664
- assert("MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:783:60")
669
+ assert("MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:793:60")
665
670
  assert("Identifier" == referencePath.parent.property.type)
666
671
  assert(
667
672
  "MemberExpression" == referencePath.parentPath.parentPath?.node.type,
668
- "src/processScript/transform.ts:785:81"
673
+ "src/processScript/transform.ts:795:81"
669
674
  )
670
675
  assert(
671
676
  "Identifier" == referencePath.parentPath.parentPath.node.property.type,
672
- "src/processScript/transform.ts:786:83"
677
+ "src/processScript/transform.ts:796:83"
673
678
  )
674
679
  assert(
675
680
  /^[_a-z][\d_a-z]{0,24}$/.test(referencePath.parent.property.name),
676
- `src/processScript/transform.ts:790:8 invalid user "${referencePath.parent.property.name}" in subscript`
681
+ `src/processScript/transform.ts:800:8 invalid user "${referencePath.parent.property.name}" in subscript`
677
682
  )
678
683
  assert(
679
684
  /^[_a-z][\d_a-z]{0,24}$/.test(referencePath.parentPath.parentPath.node.property.name),
680
- `src/processScript/transform.ts:795: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`
681
686
  )
682
687
  if ("CallExpression" == referencePath.parentPath.parentPath.parentPath?.type)
683
688
  referencePath.parentPath.parentPath.replaceWith(
684
689
  t.identifier(
685
- `$${uniqueId}$SUBSCRIPT$${referencePath.parent.property.name}$${referencePath.parentPath.parentPath.node.property.name}$`
690
+ `$${uniqueId}$${seclevel}$SUBSCRIPT$${referencePath.parent.property.name}$${referencePath.parentPath.parentPath.node.property.name}$`
686
691
  )
687
692
  )
688
693
  else {
689
694
  const name = `${referencePath.parent.property.name}$${referencePath.parentPath.parentPath.node.property.name}`
690
695
  referencePath.parentPath.parentPath.replaceWith(t.identifier(`_${uniqueId}_SUBSCRIPT_${name}_`))
691
- neededSubscriptLets.add(name)
696
+ const maxSecLevel = Math.max(neededSubscriptLets.get(name) || 0, seclevel)
697
+ neededSubscriptLets.set(name, maxSecLevel)
692
698
  }
693
699
  }
694
700
  }
package/push.d.ts CHANGED
@@ -18,6 +18,14 @@ export type PushOptions = LaxPartial<{
18
18
  */
19
19
  forceQuineCheats: boolean;
20
20
  }>;
21
+ export declare class MissingSourceFolderError extends Error {
22
+ }
23
+ export declare class MissingHackmudFolderError extends Error {
24
+ }
25
+ export declare class NoUsersError extends Error {
26
+ }
27
+ export declare class NoScriptsError extends Error {
28
+ }
21
29
  /** Push scripts from a source directory to the hackmud directory.
22
30
  *
23
31
  * Pushes files directly in the source folder to all users
@@ -25,4 +33,4 @@ export type PushOptions = LaxPartial<{
25
33
  * @param hackmudPath directory created by hackmud containing user data including scripts
26
34
  * @param options {@link PushOptions details}
27
35
  * @returns array of info on pushed scripts */
28
- export declare function push(sourcePath: string, hackmudPath: string, { scripts, onPush, minify, mangleNames, forceQuineCheats }?: PushOptions): Promise<Info[]>;
36
+ export declare function push(sourcePath: string, hackmudPath: string, { scripts, onPush, minify, mangleNames, forceQuineCheats }?: PushOptions): Promise<MissingSourceFolderError | MissingHackmudFolderError | NoUsersError | NoScriptsError | Info[]>;
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"
@@ -42,32 +42,54 @@ import "./processScript/preprocess.js"
42
42
  import "import-meta-resolve"
43
43
  import "./processScript/transform.js"
44
44
  import "@samual/lib/clearObject"
45
+ class MissingSourceFolderError extends Error {}
46
+ Object.defineProperty(MissingSourceFolderError.prototype, "name", { value: "MissingSourceFolderError" })
47
+ class MissingHackmudFolderError extends Error {}
48
+ Object.defineProperty(MissingHackmudFolderError.prototype, "name", { value: "MissingHackmudFolderError" })
49
+ class NoUsersError extends Error {}
50
+ Object.defineProperty(NoUsersError.prototype, "name", { value: "NoUsersError" })
51
+ class NoScriptsError extends Error {}
52
+ Object.defineProperty(NoScriptsError.prototype, "name", { value: "NoScriptsError" })
45
53
  async function push(
46
54
  sourcePath,
47
55
  hackmudPath,
48
56
  { scripts = ["*.*"], onPush = () => {}, minify = !0, mangleNames = !1, forceQuineCheats } = {}
49
57
  ) {
50
58
  const [sourceFolder, hackmudFolder] = await Promise.all([
51
- readDirectoryWithStats(sourcePath),
52
- readDirectoryWithStats(hackmudPath)
53
- ]),
54
- sourceFolderFolders = sourceFolder.filter(({ stats }) => stats.isDirectory()),
59
+ readDirectoryWithStats(sourcePath).catch(error => {
60
+ if (error && "ENOENT" == error.code)
61
+ return new MissingSourceFolderError("There is no folder at " + sourcePath)
62
+ throw error
63
+ }),
64
+ readDirectoryWithStats(hackmudPath).catch(error => {
65
+ if (error && "ENOENT" == error.code)
66
+ return new MissingHackmudFolderError("There is no folder at " + hackmudPath)
67
+ throw error
68
+ })
69
+ ])
70
+ if (sourceFolder instanceof Error) return sourceFolder
71
+ if (hackmudFolder instanceof Error) return hackmudFolder
72
+ const sourceFolderFolders = sourceFolder.filter(({ stats }) => stats.isDirectory()),
55
73
  allUsers = new Set([
56
74
  ...scripts
57
- .map(scriptName => ensure(scriptName.split(".")[0], "src/push.ts:52:65"))
75
+ .map(scriptName => ensure(scriptName.split(".")[0], "src/push.ts:82:65"))
58
76
  .filter(name => "*" != name),
59
77
  ...sourceFolderFolders.map(({ name }) => name),
60
78
  ...hackmudFolder.filter(({ stats }) => stats.isDirectory()).map(({ name }) => name),
61
79
  ...hackmudFolder
62
80
  .filter(({ stats, name }) => stats.isFile() && name.endsWith(".key"))
63
81
  .map(({ name }) => name.slice(0, -4))
64
- ]),
65
- usersToScriptsToPush = new Cache(_user => new Map()),
66
- scriptNamesToUsers = new Cache(_scriptName => new Set())
82
+ ])
83
+ if (!allUsers.size)
84
+ return new NoUsersError(
85
+ "Could not find any users. Either provide the names of your users or log into a user in hackmud"
86
+ )
87
+ const usersToScriptsToPush = new AutoMap(_user => new Map()),
88
+ scriptNamesToUsers = new AutoMap(_scriptName => new Set())
67
89
  for (const script of scripts) {
68
90
  const [user, scriptName] = script.split(".")
69
- assert(user, "src/push.ts:69:16")
70
- assert(scriptName, "src/push.ts:70:22")
91
+ assert(user, "src/push.ts:105:16")
92
+ assert(scriptName, "src/push.ts:106:22")
71
93
  "*" == user ? scriptNamesToUsers.set(scriptName, allUsers) : scriptNamesToUsers.get(scriptName).add(user)
72
94
  }
73
95
  const sourceFolderFiles = sourceFolder.filter(({ stats }) => stats.isFile()),
@@ -98,8 +120,8 @@ async function push(
98
120
  for (const [scriptName, users] of scriptNamesToUsers)
99
121
  for (const user of users)
100
122
  if (!usersToScriptsToPush.get(user).has(scriptName))
101
- throw Error(`Could not find script ${user}.${scriptName} to push`)
102
- const pathsToUsers = new Cache(_path => new Set())
123
+ return new NoScriptsError(`Could not find script ${user}.${scriptName} to push`)
124
+ const pathsToUsers = new AutoMap(_path => new Set())
103
125
  for (const [user, scriptsToPush] of usersToScriptsToPush)
104
126
  for (const path of scriptsToPush.values()) pathsToUsers.get(path).add(user)
105
127
  const allInfo = []
@@ -135,4 +157,4 @@ async function push(
135
157
  )
136
158
  return allInfo
137
159
  }
138
- export { push }
160
+ export { MissingHackmudFolderError, MissingSourceFolderError, NoScriptsError, NoUsersError, push }
package/watch.js CHANGED
@@ -1,14 +1,15 @@
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"
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"
@@ -58,7 +59,8 @@ async function watch(
58
59
  } = {}
59
60
  ) {
60
61
  if (!scripts.length) throw Error("scripts option was an empty array")
61
- 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()),
62
64
  wildScriptUsers = new Set(),
63
65
  wildUserScripts = new Set()
64
66
  let pushEverything = !1
@@ -90,7 +92,7 @@ async function watch(
90
92
  )
91
93
  )
92
94
  return
93
- const scriptNamesToUsersToSkip = new Cache(_scriptName => [])
95
+ const scriptNamesToUsersToSkip = new AutoMap(_scriptName => [])
94
96
  await Promise.all(
95
97
  (await readDirectoryWithStats(sourceDirectory)).map(async ({ stats, name, path }) => {
96
98
  if (stats.isDirectory())
@@ -135,7 +137,7 @@ async function watch(
135
137
  forceQuineCheats
136
138
  }))
137
139
  } catch (error) {
138
- assert(error instanceof Error, "src/watch.ts:141:36")
140
+ assert(error instanceof Error, "src/watch.ts:146:36")
139
141
  onPush?.({ path, users: [], characterCount: 0, error })
140
142
  return
141
143
  }
@@ -180,7 +182,7 @@ async function watch(
180
182
  forceQuineCheats
181
183
  }))
182
184
  } catch (error) {
183
- assert(error instanceof Error, "src/watch.ts:177:35")
185
+ assert(error instanceof Error, "src/watch.ts:182:35")
184
186
  onPush?.({ path, users: [], characterCount: 0, error })
185
187
  return
186
188
  }
@@ -195,7 +197,7 @@ async function watch(
195
197
  try {
196
198
  await writeFile(typeDeclarationPath, typeDeclaration)
197
199
  } catch (error) {
198
- assert(error instanceof Error, "src/watch.ts:210:35")
200
+ assert(error instanceof Error, "src/watch.ts:215:35")
199
201
  if ("EISDIR" != error.code) throw error
200
202
  typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
201
203
  await writeFile(typeDeclarationPath, typeDeclaration)