hackmud-script-manager 0.20.5-97101bc → 0.21.1-0b2f476

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.
@@ -22,9 +22,8 @@ const { default: traverse } = babelTraverse,
22
22
  "BigInt"
23
23
  ]
24
24
  function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scriptName, seclevel = 4 }) {
25
- const topFunctionName = `_${uniqueId}_SCRIPT_`,
26
- exports = new Map(),
27
- liveExports = new Map()
25
+ const warnings = [],
26
+ topFunctionName = `_${uniqueId}_SCRIPT_`
28
27
  let program
29
28
  traverse(file, {
30
29
  Program(path) {
@@ -46,9 +45,17 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
46
45
  referencePath.replaceWith(t.identifier(`_${uniqueId}_SCRIPT_USER_`))
47
46
  } else
48
47
  referencePath.replaceWith(t.stringLiteral(1 == scriptUser ? `$${uniqueId}$SCRIPT_USER$` : scriptUser))
49
- if (program.scope.hasGlobal("_SCRIPT_NAME"))
48
+ if (program.scope.hasGlobal("_SCRIPT_NAME")) {
49
+ warnings.push({
50
+ message:
51
+ "Global _SCRIPT_NAME is deprecated and will be removed in the next minor release of HSM, use _SCRIPT_SUBNAME instead"
52
+ })
50
53
  for (const referencePath of getReferencePathsToGlobal("_SCRIPT_NAME", program))
51
54
  referencePath.replaceWith(t.stringLiteral(1 == scriptName ? `$${uniqueId}$SCRIPT_NAME$` : scriptName))
55
+ }
56
+ if (program.scope.hasGlobal("_SCRIPT_SUBNAME"))
57
+ for (const referencePath of getReferencePathsToGlobal("_SCRIPT_SUBNAME", program))
58
+ referencePath.replaceWith(t.stringLiteral(1 == scriptName ? `$${uniqueId}$SCRIPT_NAME$` : scriptName))
52
59
  if (program.scope.hasGlobal("_FULL_SCRIPT_NAME"))
53
60
  for (const referencePath of getReferencePathsToGlobal("_FULL_SCRIPT_NAME", program))
54
61
  if (1 == scriptUser || 1 == scriptName)
@@ -70,30 +77,30 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
70
77
  const referencePath = FunctionReferencePaths[0]
71
78
  assert(
72
79
  "MemberExpression" == referencePath.parent.type,
73
- "src/processScript/transform.ts:105:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
80
+ "src/processScript/transform.ts:111:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
74
81
  )
75
82
  assert(
76
83
  "Identifier" == referencePath.parent.property.type,
77
- "src/processScript/transform.ts:110:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
84
+ "src/processScript/transform.ts:116:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
78
85
  )
79
86
  assert(
80
87
  "prototype" == referencePath.parent.property.name,
81
- "src/processScript/transform.ts:115:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
88
+ "src/processScript/transform.ts:121:8 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
82
89
  )
83
90
  referencePath.parentPath.replaceWith(createGetFunctionPrototypeNode())
84
91
  } else {
85
92
  for (const referencePath of FunctionReferencePaths) {
86
93
  assert(
87
94
  "MemberExpression" == referencePath.parent.type,
88
- "src/processScript/transform.ts:123:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
95
+ "src/processScript/transform.ts:129:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
89
96
  )
90
97
  assert(
91
98
  "Identifier" == referencePath.parent.property.type,
92
- "src/processScript/transform.ts:128:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
99
+ "src/processScript/transform.ts:134:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
93
100
  )
94
101
  assert(
95
102
  "prototype" == referencePath.parent.property.name,
96
- "src/processScript/transform.ts:133:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
103
+ "src/processScript/transform.ts:139:9 `Function` isn't available in hackmud, only `Function.prototype` is accessible"
97
104
  )
98
105
  functionDotPrototypeIsReferencedMultipleTimes = !0
99
106
  referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_FUNCTION_DOT_PROTOTYPE_`))
@@ -101,40 +108,45 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
101
108
  functionDotPrototypeIsReferencedMultipleTimes = !0
102
109
  }
103
110
  }
104
- const neededSubscriptLets = new Set()
111
+ const neededSubscriptLets = new Map()
105
112
  let detectedSeclevel = 4
113
+ program.scope.hasGlobal("$s") &&
114
+ warnings.push({
115
+ message:
116
+ "Subscripts in the form of $s.foo.bar() and #s.foo.bar() are deprecated. Use explicit seclevels instead."
117
+ })
106
118
  for (const fakeSubscriptObjectName of ["$fs", "$4s", "$s"])
107
- program.scope.hasGlobal(fakeSubscriptObjectName) && processFakeSubscriptObject(fakeSubscriptObjectName)
119
+ program.scope.hasGlobal(fakeSubscriptObjectName) && processFakeSubscriptObject(fakeSubscriptObjectName, 4)
108
120
  for (const fakeSubscriptObjectName of ["$hs", "$3s"])
109
121
  if (program.scope.hasGlobal(fakeSubscriptObjectName)) {
110
122
  detectedSeclevel = 3
111
- processFakeSubscriptObject(fakeSubscriptObjectName)
123
+ processFakeSubscriptObject(fakeSubscriptObjectName, 3)
112
124
  }
113
125
  for (const fakeSubscriptObjectName of ["$ms", "$2s"])
114
126
  if (program.scope.hasGlobal(fakeSubscriptObjectName)) {
115
127
  detectedSeclevel = 2
116
- processFakeSubscriptObject(fakeSubscriptObjectName)
128
+ processFakeSubscriptObject(fakeSubscriptObjectName, 2)
117
129
  }
118
130
  for (const fakeSubscriptObjectName of ["$ls", "$1s"])
119
131
  if (program.scope.hasGlobal(fakeSubscriptObjectName)) {
120
132
  detectedSeclevel = 1
121
- processFakeSubscriptObject(fakeSubscriptObjectName)
133
+ processFakeSubscriptObject(fakeSubscriptObjectName, 1)
122
134
  }
123
135
  for (const fakeSubscriptObjectName of ["$ns", "$0s"])
124
136
  if (program.scope.hasGlobal(fakeSubscriptObjectName)) {
125
137
  detectedSeclevel = 0
126
- processFakeSubscriptObject(fakeSubscriptObjectName)
138
+ processFakeSubscriptObject(fakeSubscriptObjectName, 0)
127
139
  }
128
140
  seclevel = Math.min(seclevel, detectedSeclevel)
129
141
  const neededDbMethodLets = new Set()
130
142
  if (program.scope.hasGlobal("$db"))
131
143
  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")
144
+ assert("MemberExpression" == referencePath.parentPath.node.type, "src/processScript/transform.ts:199:69")
145
+ assert("Identifier" == referencePath.parentPath.node.property.type, "src/processScript/transform.ts:200:72")
134
146
  const databaseOpMethodName = referencePath.parentPath.node.property.name
135
147
  assert(
136
148
  validDBMethods.includes(databaseOpMethodName),
137
- `src/processScript/transform.ts:194:8 invalid db method "${databaseOpMethodName}", valid db methods are "${validDBMethods.join('", "')}"`
149
+ `src/processScript/transform.ts:206:8 invalid db method "${databaseOpMethodName}", valid db methods are "${validDBMethods.join('", "')}"`
138
150
  )
139
151
  if ("CallExpression" == referencePath.parentPath.parentPath?.type)
140
152
  referencePath.parentPath.replaceWith(t.identifier(`$${uniqueId}$DB$${databaseOpMethodName}$`))
@@ -157,27 +169,32 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
157
169
  if (program.scope.hasGlobal("$FMCL"))
158
170
  for (const referencePath of getReferencePathsToGlobal("$FMCL", program))
159
171
  referencePath.replaceWith(t.identifier(`$${uniqueId}$FMCL$`))
160
- if (program.scope.hasGlobal("$G"))
172
+ let needG = program.scope.hasGlobal("$G")
173
+ if (needG)
161
174
  for (const referencePath of getReferencePathsToGlobal("$G", program))
162
- referencePath.replaceWith(t.identifier(`$${uniqueId}$GLOBAL$`))
175
+ referencePath.replaceWith(t.identifier(`_${uniqueId}_G_`))
163
176
  if (program.scope.hasGlobal("_SECLEVEL"))
164
177
  for (const referencePath of getReferencePathsToGlobal("_SECLEVEL", program))
165
178
  referencePath.replaceWith(t.numericLiteral(seclevel))
166
- let needGetPrototypeOf = !1
179
+ let needGetPrototypeOf = !1,
180
+ needHasOwn = !1
167
181
  if (program.scope.hasGlobal("Object"))
168
182
  for (const referencePath of getReferencePathsToGlobal("Object", program))
169
183
  if ("MemberExpression" == referencePath.parent.type && !referencePath.parent.computed) {
170
- assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:241:64")
184
+ assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:256:64")
171
185
  if ("getPrototypeOf" == referencePath.parent.property.name) {
172
186
  referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_GET_PROTOTYPE_OF_`))
173
187
  needGetPrototypeOf = !0
188
+ } else if ("hasOwn" == referencePath.parent.property.name) {
189
+ referencePath.parentPath.replaceWith(t.identifier(`_${uniqueId}_HAS_OWN_`))
190
+ needHasOwn = !0
174
191
  }
175
192
  }
176
193
  const consoleMethodsReferenced = new Set()
177
194
  if (program.scope.hasGlobal("console"))
178
195
  for (const referencePath of getReferencePathsToGlobal("console", program))
179
196
  if ("MemberExpression" == referencePath.parent.type && !referencePath.parent.computed) {
180
- assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:256:64")
197
+ assert("Identifier" == referencePath.parent.property.type, "src/processScript/transform.ts:274:64")
181
198
  referencePath.parentPath.replaceWith(
182
199
  t.identifier(`_${uniqueId}_CONSOLE_METHOD_${referencePath.parent.property.name}_`)
183
200
  )
@@ -185,19 +202,20 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
185
202
  }
186
203
  const lastStatement = program.node.body.at(-1)
187
204
  let exportDefaultName
188
- assert(lastStatement, "src/processScript/transform.ts:270:27 program is empty")
205
+ assert(lastStatement, "src/processScript/transform.ts:288:27 program is empty")
189
206
  if ("ExportNamedDeclaration" == lastStatement.type) {
190
207
  program.node.body.pop()
191
208
  for (const specifier of lastStatement.specifiers) {
192
209
  assert(
193
210
  "ExportSpecifier" == specifier.type,
194
- `src/processScript/transform.ts:276:51 ${specifier.type} is currently unsupported`
211
+ `src/processScript/transform.ts:294:51 ${specifier.type} is currently unsupported`
212
+ )
213
+ if (
214
+ "default" !=
215
+ ("Identifier" == specifier.exported.type ? specifier.exported.name : specifier.exported.value)
195
216
  )
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)
217
+ throw Error("Only default exports are supported")
218
+ exportDefaultName = specifier.local.name
201
219
  }
202
220
  }
203
221
  const globalBlock = t.blockStatement([])
@@ -223,10 +241,6 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
223
241
  t.returnStatement(t.callExpression(t.identifier(exportDefaultName), []))
224
242
  ])
225
243
  ))
226
- if ("const" != statement.kind && exports.has(identifierName)) {
227
- liveExports.set(identifierName, exports.get(identifierName))
228
- exports.delete(identifierName)
229
- }
230
244
  globalBlock.body.push(
231
245
  t.variableDeclaration("let", [t.variableDeclarator(t.identifier(identifierName))])
232
246
  )
@@ -291,34 +305,16 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
291
305
  }
292
306
  program.node.body = [mainFunction]
293
307
  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
308
  program.scope.crawl()
313
309
  const globalBlockVariables = new Set()
314
310
  let hoistedGlobalBlockFunctions = 0
315
311
  for (const [globalBlockIndex, globalBlockStatement] of [...globalBlock.body.entries()].reverse())
316
312
  if ("VariableDeclaration" == globalBlockStatement.type) {
317
- assert(1 == globalBlockStatement.declarations.length, "src/processScript/transform.ts:410:59")
313
+ assert(1 == globalBlockStatement.declarations.length, "src/processScript/transform.ts:408:59")
318
314
  const declarator = globalBlockStatement.declarations[0]
319
315
  assert(
320
316
  "Identifier" == declarator.id.type,
321
- `src/processScript/transform.ts:414:51 declarator.id.type was "${declarator.id.type}"`
317
+ `src/processScript/transform.ts:412:51 declarator.id.type was "${declarator.id.type}"`
322
318
  )
323
319
  program.scope.crawl()
324
320
  if (program.scope.hasGlobal(declarator.id.name)) {
@@ -333,15 +329,16 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
333
329
  Object.keys(program.scope.globals).some(global => globalBlockVariables.has(global))
334
330
  ) {
335
331
  const binding = program.scope.getBinding(declarator.id.name)
336
- assert(binding, "src/processScript/transform.ts:433:23")
332
+ assert(binding, "src/processScript/transform.ts:431:23")
337
333
  for (const referencePath of binding.referencePaths) {
338
- assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:436:56")
334
+ assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:434:56")
339
335
  referencePath.replaceWith(
340
336
  t.memberExpression(
341
- t.identifier(`$${uniqueId}$GLOBAL$`),
337
+ t.identifier(`_${uniqueId}_G_`),
342
338
  t.identifier(referencePath.node.name)
343
339
  )
344
340
  )
341
+ needG = !0
345
342
  }
346
343
  for (const referencePath of binding.constantViolations)
347
344
  if ("AssignmentExpression" == referencePath.node.type)
@@ -350,12 +347,13 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
350
347
  clearObject(node)
351
348
  Object.assign(
352
349
  node,
353
- t.memberExpression(t.identifier(`$${uniqueId}$GLOBAL$`), t.identifier(name))
350
+ t.memberExpression(t.identifier(`_${uniqueId}_G_`), t.identifier(name))
354
351
  )
352
+ needG = !0
355
353
  }
356
354
  globalBlockPath.remove()
357
355
  globalBlockStatementPath.remove()
358
- declarator.init &&
356
+ if (declarator.init) {
359
357
  globalBlock.body.splice(
360
358
  globalBlockIndex,
361
359
  0,
@@ -363,13 +361,15 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
363
361
  t.assignmentExpression(
364
362
  "=",
365
363
  t.memberExpression(
366
- t.identifier(`$${uniqueId}$GLOBAL$`),
364
+ t.identifier(`_${uniqueId}_G_`),
367
365
  t.identifier(declarator.id.name)
368
366
  ),
369
367
  declarator.init
370
368
  )
371
369
  )
372
370
  )
371
+ needG = !0
372
+ }
373
373
  } else {
374
374
  globalBlockPath.remove()
375
375
  globalBlockStatementPath.remove()
@@ -379,22 +379,20 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
379
379
  } else globalBlockVariables.add(declarator.id.name)
380
380
  } else if ("ClassDeclaration" == globalBlockStatement.type) {
381
381
  program.scope.crawl()
382
- assert(globalBlockStatement.id, "src/processScript/transform.ts:487:37")
382
+ assert(globalBlockStatement.id, "src/processScript/transform.ts:491:37")
383
383
  if (program.scope.hasGlobal(globalBlockStatement.id.name)) {
384
384
  globalBlock.body.splice(globalBlockIndex, 1)
385
385
  const [globalBlockPath] = program.unshiftContainer("body", globalBlock),
386
386
  [globalBlockStatementPath] = program.unshiftContainer("body", globalBlockStatement)
387
387
  program.scope.crawl()
388
388
  const binding = program.scope.getBinding(globalBlockStatement.id.name)
389
- assert(binding, "src/processScript/transform.ts:499:22")
389
+ assert(binding, "src/processScript/transform.ts:503:22")
390
390
  for (const referencePath of binding.referencePaths) {
391
- assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:502:55")
391
+ assert("Identifier" == referencePath.node.type, "src/processScript/transform.ts:506:55")
392
392
  referencePath.replaceWith(
393
- t.memberExpression(
394
- t.identifier(`$${uniqueId}$GLOBAL$`),
395
- t.identifier(referencePath.node.name)
396
- )
393
+ t.memberExpression(t.identifier(`_${uniqueId}_G_`), t.identifier(referencePath.node.name))
397
394
  )
395
+ needG = !0
398
396
  }
399
397
  globalBlockPath.remove()
400
398
  globalBlockStatementPath.remove()
@@ -405,7 +403,7 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
405
403
  t.assignmentExpression(
406
404
  "=",
407
405
  t.memberExpression(
408
- t.identifier(`$${uniqueId}$GLOBAL$`),
406
+ t.identifier(`_${uniqueId}_G_`),
409
407
  t.identifier(globalBlockStatement.id.name)
410
408
  ),
411
409
  t.classExpression(
@@ -417,13 +415,9 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
417
415
  )
418
416
  )
419
417
  )
418
+ needG = !0
420
419
  }
421
420
  }
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
421
  globalBlock.body.length &&
428
422
  mainFunction.body.body.splice(
429
423
  hoistedGlobalBlockFunctions,
@@ -472,6 +466,31 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
472
466
  )
473
467
  ])
474
468
  )
469
+ needHasOwn &&
470
+ mainFunction.body.body.unshift(
471
+ t.variableDeclaration("let", [
472
+ t.variableDeclarator(
473
+ t.identifier(`_${uniqueId}_HAS_OWN_`),
474
+ t.callExpression(
475
+ t.memberExpression(
476
+ t.memberExpression(
477
+ t.identifier(
478
+ globalFunctionsUnder7Characters.find(name => !program.scope.hasOwnBinding(name))
479
+ ),
480
+ t.identifier("call")
481
+ ),
482
+ t.identifier("bind")
483
+ ),
484
+ [
485
+ t.memberExpression(
486
+ t.memberExpression(t.identifier("Object"), t.identifier("prototype")),
487
+ t.identifier("hasOwnProperty")
488
+ )
489
+ ]
490
+ )
491
+ )
492
+ ])
493
+ )
475
494
  consoleMethodsReferenced.size &&
476
495
  mainFunction.body.body.unshift(
477
496
  t.variableDeclaration(
@@ -522,12 +541,12 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
522
541
  mainFunction.body.body.unshift(
523
542
  t.variableDeclaration(
524
543
  "let",
525
- [...neededSubscriptLets].map(name =>
544
+ [...neededSubscriptLets].map(([name, seclevel]) =>
526
545
  t.variableDeclarator(
527
546
  t.identifier(`_${uniqueId}_SUBSCRIPT_${name}_`),
528
547
  t.arrowFunctionExpression(
529
548
  [t.restElement(t.identifier("args"))],
530
- t.callExpression(t.identifier(`$${uniqueId}$SUBSCRIPT$${name}$`), [
549
+ t.callExpression(t.identifier(`$${uniqueId}$${seclevel}$SUBSCRIPT$${name}$`), [
531
550
  t.spreadElement(t.identifier("args"))
532
551
  ])
533
552
  )
@@ -535,6 +554,12 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
535
554
  )
536
555
  )
537
556
  )
557
+ needG &&
558
+ mainFunction.body.body.unshift(
559
+ t.variableDeclaration("let", [
560
+ t.variableDeclarator(t.identifier(`_${uniqueId}_G_`), t.identifier(`$${uniqueId}$GLOBAL$`))
561
+ ])
562
+ )
538
563
  traverse(file, {
539
564
  BlockStatement({ node: blockStatement }) {
540
565
  for (const [index, functionDeclaration] of blockStatement.body.entries())
@@ -555,7 +580,7 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
555
580
  }
556
581
  },
557
582
  ClassBody({ node: classBody, scope, parent }) {
558
- assert(t.isClass(parent), "src/processScript/transform.ts:669:30")
583
+ assert(t.isClass(parent), "src/processScript/transform.ts:701:30")
559
584
  let thisIsReferenced = !1
560
585
  for (const classMethod of classBody.body) {
561
586
  if ("ClassMethod" != classMethod.type) continue
@@ -645,52 +670,45 @@ function transform(file, sourceCode, { uniqueId = "00000000000", scriptUser, scr
645
670
  )
646
671
  }
647
672
  })
648
- return { file, seclevel }
673
+ return { file, seclevel, warnings }
649
674
  function createGetFunctionPrototypeNode() {
650
- for (const globalFunction of globalFunctionsUnder7Characters)
651
- if (!program.scope.hasOwnBinding(globalFunction))
652
- return t.memberExpression(
653
- t.memberExpression(t.identifier(globalFunction), t.identifier("constructor")),
654
- t.identifier("prototype")
655
- )
675
+ const name = globalFunctionsUnder7Characters.find(name => !program.scope.hasOwnBinding(name))
656
676
  return t.memberExpression(
657
- t.memberExpression(
658
- t.arrowFunctionExpression([t.identifier("_")], t.identifier("_")),
659
- t.identifier("constructor")
660
- ),
661
- t.identifier("prototype")
677
+ name ? t.identifier(name) : t.arrowFunctionExpression([t.identifier("_")], t.identifier("_")),
678
+ t.identifier("__proto__")
662
679
  )
663
680
  }
664
- function processFakeSubscriptObject(fakeSubscriptObjectName) {
681
+ function processFakeSubscriptObject(fakeSubscriptObjectName, seclevel) {
665
682
  for (const referencePath of getReferencePathsToGlobal(fakeSubscriptObjectName, program)) {
666
- assert("MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:785:60")
683
+ assert("MemberExpression" == referencePath.parent.type, "src/processScript/transform.ts:807:60")
667
684
  assert("Identifier" == referencePath.parent.property.type)
668
685
  assert(
669
686
  "MemberExpression" == referencePath.parentPath.parentPath?.node.type,
670
- "src/processScript/transform.ts:787:81"
687
+ "src/processScript/transform.ts:809:81"
671
688
  )
672
689
  assert(
673
690
  "Identifier" == referencePath.parentPath.parentPath.node.property.type,
674
- "src/processScript/transform.ts:788:83"
691
+ "src/processScript/transform.ts:810:83"
675
692
  )
676
693
  assert(
677
694
  /^[_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`
695
+ `src/processScript/transform.ts:814:8 invalid user "${referencePath.parent.property.name}" in subscript`
679
696
  )
680
697
  assert(
681
698
  /^[_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`
699
+ `src/processScript/transform.ts:819:8 invalid script name "${referencePath.parentPath.parentPath.node.property.name}" in subscript`
683
700
  )
684
701
  if ("CallExpression" == referencePath.parentPath.parentPath.parentPath?.type)
685
702
  referencePath.parentPath.parentPath.replaceWith(
686
703
  t.identifier(
687
- `$${uniqueId}$SUBSCRIPT$${referencePath.parent.property.name}$${referencePath.parentPath.parentPath.node.property.name}$`
704
+ `$${uniqueId}$${seclevel}$SUBSCRIPT$${referencePath.parent.property.name}$${referencePath.parentPath.parentPath.node.property.name}$`
688
705
  )
689
706
  )
690
707
  else {
691
708
  const name = `${referencePath.parent.property.name}$${referencePath.parentPath.parentPath.node.property.name}`
692
709
  referencePath.parentPath.parentPath.replaceWith(t.identifier(`_${uniqueId}_SUBSCRIPT_${name}_`))
693
- neededSubscriptLets.add(name)
710
+ const maxSecLevel = Math.max(neededSubscriptLets.get(name) || 0, seclevel)
711
+ neededSubscriptLets.set(name, maxSecLevel)
694
712
  }
695
713
  }
696
714
  }
package/push.d.ts CHANGED
@@ -17,7 +17,16 @@ export type PushOptions = LaxPartial<{
17
17
  * when left unset or set to `undefined`, automatically uses or doesn't use quine cheats based on character count
18
18
  */
19
19
  forceQuineCheats: boolean;
20
+ rootFolderPath: string;
20
21
  }>;
22
+ export declare class MissingSourceFolderError extends Error {
23
+ }
24
+ export declare class MissingHackmudFolderError extends Error {
25
+ }
26
+ export declare class NoUsersError extends Error {
27
+ }
28
+ export declare class NoScriptsError extends Error {
29
+ }
21
30
  /** Push scripts from a source directory to the hackmud directory.
22
31
  *
23
32
  * Pushes files directly in the source folder to all users
@@ -25,4 +34,4 @@ export type PushOptions = LaxPartial<{
25
34
  * @param hackmudPath directory created by hackmud containing user data including scripts
26
35
  * @param options {@link PushOptions details}
27
36
  * @returns array of info on pushed scripts */
28
- export declare function push(sourcePath: string, hackmudPath: string, { scripts, onPush, minify, mangleNames, forceQuineCheats }?: PushOptions): Promise<Info[]>;
37
+ export declare function push(sourcePath: string, hackmudPath: string, { scripts, onPush, minify, mangleNames, forceQuineCheats, rootFolderPath }?: 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"
@@ -25,6 +25,7 @@ import "@babel/plugin-transform-private-property-in-object"
25
25
  import "@babel/plugin-transform-unicode-sets-regex"
26
26
  import "@babel/traverse"
27
27
  import "@babel/types"
28
+ import "@rollup/plugin-alias"
28
29
  import "@rollup/plugin-babel"
29
30
  import "@rollup/plugin-commonjs"
30
31
  import "@rollup/plugin-json"
@@ -42,19 +43,37 @@ import "./processScript/preprocess.js"
42
43
  import "import-meta-resolve"
43
44
  import "./processScript/transform.js"
44
45
  import "@samual/lib/clearObject"
46
+ class MissingSourceFolderError extends Error {}
47
+ Object.defineProperty(MissingSourceFolderError.prototype, "name", { value: "MissingSourceFolderError" })
48
+ class MissingHackmudFolderError extends Error {}
49
+ Object.defineProperty(MissingHackmudFolderError.prototype, "name", { value: "MissingHackmudFolderError" })
50
+ class NoUsersError extends Error {}
51
+ Object.defineProperty(NoUsersError.prototype, "name", { value: "NoUsersError" })
52
+ class NoScriptsError extends Error {}
53
+ Object.defineProperty(NoScriptsError.prototype, "name", { value: "NoScriptsError" })
45
54
  async function push(
46
55
  sourcePath,
47
56
  hackmudPath,
48
- { scripts = ["*.*"], onPush = () => {}, minify = !0, mangleNames = !1, forceQuineCheats } = {}
57
+ { scripts = ["*.*"], onPush = () => {}, minify = !0, mangleNames = !1, forceQuineCheats, rootFolderPath } = {}
49
58
  ) {
50
59
  const [sourceFolder, hackmudFolder] = await Promise.all([
51
- readDirectoryWithStats(sourcePath),
52
- readDirectoryWithStats(hackmudPath)
53
- ]),
54
- sourceFolderFolders = sourceFolder.filter(({ stats }) => stats.isDirectory()),
60
+ readDirectoryWithStats(sourcePath).catch(error => {
61
+ if (error && "ENOENT" == error.code)
62
+ return new MissingSourceFolderError("There is no folder at " + sourcePath)
63
+ throw error
64
+ }),
65
+ readDirectoryWithStats(hackmudPath).catch(error => {
66
+ if (error && "ENOENT" == error.code)
67
+ return new MissingHackmudFolderError("There is no folder at " + hackmudPath)
68
+ throw error
69
+ })
70
+ ])
71
+ if (sourceFolder instanceof Error) return sourceFolder
72
+ if (hackmudFolder instanceof Error) return hackmudFolder
73
+ const sourceFolderFolders = sourceFolder.filter(({ stats }) => stats.isDirectory()),
55
74
  allUsers = new Set([
56
75
  ...scripts
57
- .map(scriptName => ensure(scriptName.split(".")[0], "src/push.ts:52:65"))
76
+ .map(scriptName => ensure(scriptName.split(".")[0], "src/push.ts:85:65"))
58
77
  .filter(name => "*" != name),
59
78
  ...sourceFolderFolders.map(({ name }) => name),
60
79
  ...hackmudFolder.filter(({ stats }) => stats.isDirectory()).map(({ name }) => name),
@@ -63,13 +82,15 @@ async function push(
63
82
  .map(({ name }) => name.slice(0, -4))
64
83
  ])
65
84
  if (!allUsers.size)
66
- throw Error("Could not find any users. Either provide the names of your users or log into a user in hackmud.")
67
- const usersToScriptsToPush = new Cache(_user => new Map()),
68
- scriptNamesToUsers = new Cache(_scriptName => new Set())
85
+ return new NoUsersError(
86
+ "Could not find any users. Either provide the names of your users or log into a user in hackmud"
87
+ )
88
+ const usersToScriptsToPush = new AutoMap(_user => new Map()),
89
+ scriptNamesToUsers = new AutoMap(_scriptName => new Set())
69
90
  for (const script of scripts) {
70
91
  const [user, scriptName] = script.split(".")
71
- assert(user, "src/push.ts:72:16")
72
- assert(scriptName, "src/push.ts:73:22")
92
+ assert(user, "src/push.ts:108:16")
93
+ assert(scriptName, "src/push.ts:109:22")
73
94
  "*" == user ? scriptNamesToUsers.set(scriptName, allUsers) : scriptNamesToUsers.get(scriptName).add(user)
74
95
  }
75
96
  const sourceFolderFiles = sourceFolder.filter(({ stats }) => stats.isFile()),
@@ -100,8 +121,8 @@ async function push(
100
121
  for (const [scriptName, users] of scriptNamesToUsers)
101
122
  for (const user of users)
102
123
  if (!usersToScriptsToPush.get(user).has(scriptName))
103
- throw Error(`Could not find script ${user}.${scriptName} to push`)
104
- const pathsToUsers = new Cache(_path => new Set())
124
+ return new NoScriptsError(`Could not find script ${user}.${scriptName} to push`)
125
+ const pathsToUsers = new AutoMap(_path => new Set())
105
126
  for (const [user, scriptsToPush] of usersToScriptsToPush)
106
127
  for (const path of scriptsToPush.values()) pathsToUsers.get(path).add(user)
107
128
  const allInfo = []
@@ -111,16 +132,17 @@ async function push(
111
132
  uniqueId = Math.floor(Math.random() * 2 ** 52)
112
133
  .toString(36)
113
134
  .padStart(11, "0"),
114
- { script: minifiedCode } = await processScript(await readFile(path, { encoding: "utf8" }), {
135
+ { script: minifiedCode, warnings } = await processScript(await readFile(path, { encoding: "utf8" }), {
115
136
  minify,
116
137
  scriptUser: !0,
117
138
  scriptName,
118
139
  uniqueId,
119
140
  filePath: path,
120
141
  mangleNames,
121
- forceQuineCheats
142
+ forceQuineCheats,
143
+ rootFolderPath
122
144
  }),
123
- info = { path, users, characterCount: countHackmudCharacters(minifiedCode), error: void 0 }
145
+ info = { path, users, characterCount: countHackmudCharacters(minifiedCode), error: void 0, warnings }
124
146
  await Promise.all(
125
147
  users.map(user =>
126
148
  writeFilePersistent(
@@ -137,4 +159,4 @@ async function push(
137
159
  )
138
160
  return allInfo
139
161
  }
140
- export { push }
162
+ export { MissingHackmudFolderError, MissingSourceFolderError, NoScriptsError, NoUsersError, push }
package/watch.d.ts CHANGED
@@ -6,9 +6,10 @@ export type WatchOptions = PushOptions & LaxPartial<{
6
6
  * writing the type declarations enables interscript type checking and autocompletetes for the args */
7
7
  typeDeclarationPath: string;
8
8
  onReady: () => void;
9
+ rootFolderPath: string;
9
10
  }>;
10
11
  /** Watches target file or folder for updates and builds and pushes updated file.
11
12
  * @param sourceDirectory path to folder containing source files
12
13
  * @param hackmudDirectory path to hackmud directory
13
14
  * @param options {@link WatchOptions details} and {@link PushOptions more details} */
14
- export declare function watch(sourceDirectory: string, hackmudDirectory: string, { scripts, onPush, minify, mangleNames, typeDeclarationPath: typeDeclarationPath_, onReady, forceQuineCheats }?: WatchOptions): Promise<void>;
15
+ export declare function watch(sourceDirectory: string, hackmudDirectory: string, { scripts, onPush, minify, mangleNames, typeDeclarationPath: typeDeclarationPath_, onReady, forceQuineCheats, rootFolderPath }?: WatchOptions): Promise<void>;