@pleger/esa-js 0.2.0

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/instrument.js ADDED
@@ -0,0 +1,668 @@
1
+ const acorn = typeof require === "function" ? require("acorn") : globalThis.acorn;
2
+ const astring = typeof require === "function" ? require("astring") : globalThis.astring;
3
+
4
+ let scopeCounter = 1;
5
+
6
+ function id(name) {
7
+ return { type: "Identifier", name };
8
+ }
9
+
10
+ function literal(value) {
11
+ return { type: "Literal", value };
12
+ }
13
+
14
+ function member(object, property, computed = false) {
15
+ return { type: "MemberExpression", object, property, computed, optional: false };
16
+ }
17
+
18
+ function callExpr(callee, args) {
19
+ return { type: "CallExpression", callee, arguments: args, optional: false };
20
+ }
21
+
22
+ function arrayExpr(elements) {
23
+ return { type: "ArrayExpression", elements };
24
+ }
25
+
26
+ function exprStmt(expression) {
27
+ return { type: "ExpressionStatement", expression };
28
+ }
29
+
30
+ function returnStmt(argument) {
31
+ return { type: "ReturnStatement", argument };
32
+ }
33
+
34
+ function block(body) {
35
+ return { type: "BlockStatement", body };
36
+ }
37
+
38
+ function varDecl(kind, declarations) {
39
+ return { type: "VariableDeclaration", kind, declarations };
40
+ }
41
+
42
+ function decl(name, init = null) {
43
+ return { type: "VariableDeclarator", id: id(name), init };
44
+ }
45
+
46
+ function functionExpr(name, params, body) {
47
+ return {
48
+ type: "FunctionExpression",
49
+ id: name ? id(name) : null,
50
+ params,
51
+ body,
52
+ generator: false,
53
+ async: false,
54
+ expression: false,
55
+ };
56
+ }
57
+
58
+ function objectExpr(properties) {
59
+ return { type: "ObjectExpression", properties };
60
+ }
61
+
62
+ function propertyNode(key, value, computed = false) {
63
+ return {
64
+ type: "Property",
65
+ key,
66
+ value,
67
+ kind: "init",
68
+ method: false,
69
+ shorthand: false,
70
+ computed,
71
+ };
72
+ }
73
+
74
+ function clone(node) {
75
+ return JSON.parse(JSON.stringify(node));
76
+ }
77
+
78
+ class Scope {
79
+ constructor(kind, parent, declarations, scopeName) {
80
+ this.kind = kind;
81
+ this.parent = parent;
82
+ this.declarations = declarations;
83
+ this.scopeName = scopeName;
84
+ this.scopeId = kind === "function" || kind === "catch" ? "__as_scope_" + scopeCounter++ : null;
85
+ }
86
+
87
+ owns(name) {
88
+ return this.declarations.has(name);
89
+ }
90
+
91
+ resolve(name) {
92
+ if (name === "undefined" || name === "NaN" || name === "Infinity" || name === "arguments") {
93
+ return null;
94
+ }
95
+ let cursor = this;
96
+ while (cursor) {
97
+ if (cursor.owns(name)) {
98
+ if (cursor.kind === "global") {
99
+ return { mode: "globalProp", target: member(id("AspectScript"), id("globalObject")) };
100
+ }
101
+ return { mode: "local", target: id(cursor.scopeId) };
102
+ }
103
+ cursor = cursor.parent;
104
+ }
105
+ return { mode: "globalProp", target: member(id("AspectScript"), id("globalObject")) };
106
+ }
107
+ }
108
+
109
+ function collectFunctionScopeDeclarations(statements, out = new Set()) {
110
+ for (const stmt of statements) {
111
+ if (!stmt) {
112
+ continue;
113
+ }
114
+ switch (stmt.type) {
115
+ case "FunctionDeclaration":
116
+ out.add(stmt.id.name);
117
+ break;
118
+ case "VariableDeclaration":
119
+ if (stmt.kind === "var") {
120
+ for (const declarator of stmt.declarations) {
121
+ if (declarator.id.type === "Identifier") {
122
+ out.add(declarator.id.name);
123
+ }
124
+ }
125
+ }
126
+ break;
127
+ case "BlockStatement":
128
+ collectFunctionScopeDeclarations(stmt.body, out);
129
+ break;
130
+ case "IfStatement":
131
+ collectFunctionScopeDeclarations([stmt.consequent], out);
132
+ if (stmt.alternate) {
133
+ collectFunctionScopeDeclarations([stmt.alternate], out);
134
+ }
135
+ break;
136
+ case "ForStatement":
137
+ if (stmt.init && stmt.init.type === "VariableDeclaration" && stmt.init.kind === "var") {
138
+ for (const declarator of stmt.init.declarations) {
139
+ if (declarator.id.type === "Identifier") {
140
+ out.add(declarator.id.name);
141
+ }
142
+ }
143
+ }
144
+ collectFunctionScopeDeclarations([stmt.body], out);
145
+ break;
146
+ case "ForInStatement":
147
+ case "ForOfStatement":
148
+ if (stmt.left && stmt.left.type === "VariableDeclaration" && stmt.left.kind === "var") {
149
+ for (const declarator of stmt.left.declarations) {
150
+ if (declarator.id.type === "Identifier") {
151
+ out.add(declarator.id.name);
152
+ }
153
+ }
154
+ }
155
+ collectFunctionScopeDeclarations([stmt.body], out);
156
+ break;
157
+ case "WhileStatement":
158
+ case "DoWhileStatement":
159
+ case "LabeledStatement":
160
+ case "WithStatement":
161
+ collectFunctionScopeDeclarations([stmt.body], out);
162
+ break;
163
+ case "SwitchStatement":
164
+ for (const switchCase of stmt.cases) {
165
+ collectFunctionScopeDeclarations(switchCase.consequent, out);
166
+ }
167
+ break;
168
+ case "TryStatement":
169
+ collectFunctionScopeDeclarations([stmt.block], out);
170
+ if (stmt.handler) {
171
+ collectFunctionScopeDeclarations(stmt.handler.body.body, out);
172
+ }
173
+ if (stmt.finalizer) {
174
+ collectFunctionScopeDeclarations([stmt.finalizer], out);
175
+ }
176
+ break;
177
+ default:
178
+ break;
179
+ }
180
+ }
181
+ return out;
182
+ }
183
+
184
+ function transformProgram(source) {
185
+ scopeCounter = 1;
186
+ const ast = acorn.parse(source, {
187
+ ecmaVersion: 2020,
188
+ sourceType: "script",
189
+ allowReturnOutsideFunction: true,
190
+ });
191
+ const globalDecls = collectFunctionScopeDeclarations(ast.body);
192
+ const scope = new Scope("global", null, globalDecls, "global");
193
+ const body = transformStatementList(ast.body, scope, null);
194
+ return astring.generate({ type: "Program", body, sourceType: "script" });
195
+ }
196
+
197
+ function transformStatementList(statements, scope, catchScope) {
198
+ const hoisted = [];
199
+ const body = [];
200
+ for (const stmt of statements) {
201
+ if (!stmt) {
202
+ continue;
203
+ }
204
+ if (stmt.type === "FunctionDeclaration") {
205
+ hoisted.push(varDecl("var", [decl(stmt.id.name, transformFunction(stmt, scope))]));
206
+ continue;
207
+ }
208
+ const transformed = transformStatement(stmt, scope, catchScope);
209
+ if (Array.isArray(transformed)) {
210
+ body.push(...transformed);
211
+ } else if (transformed) {
212
+ body.push(transformed);
213
+ }
214
+ }
215
+ return hoisted.concat(body);
216
+ }
217
+
218
+ function transformFunction(node, parentScope) {
219
+ const declarations = collectFunctionScopeDeclarations(node.body.body, new Set());
220
+ for (const param of node.params) {
221
+ if (param.type === "Identifier") {
222
+ declarations.add(param.name);
223
+ }
224
+ }
225
+ if (node.id && node.type === "FunctionExpression") {
226
+ declarations.add(node.id.name);
227
+ }
228
+ const scope = new Scope("function", parentScope, declarations, node.id ? node.id.name : "");
229
+ const transformedBody = transformStatementList(node.body.body, scope, null);
230
+ transformedBody.unshift(varDecl("var", [decl(scope.scopeId, callExpr(member(id("AspectScript"), id("__scope")), [literal(scope.scopeName || "")]))]));
231
+ return callExpr(member(id("AspectScript"), id("__wrapFunction")), [
232
+ functionExpr(node.id ? node.id.name : null, node.params, block(transformedBody)),
233
+ literal(node.id ? node.id.name : ""),
234
+ ]);
235
+ }
236
+
237
+ function transformCatchClause(node, scope) {
238
+ const declarations = new Set();
239
+ if (node.param && node.param.type === "Identifier") {
240
+ declarations.add(node.param.name);
241
+ }
242
+ const catchScope = new Scope("catch", scope, declarations, node.param ? node.param.name : "");
243
+ const body = transformStatementList(node.body.body, scope, catchScope);
244
+ body.unshift(varDecl("var", [decl(catchScope.scopeId, callExpr(member(id("AspectScript"), id("__scope")), [literal(catchScope.scopeName || "")]))]));
245
+ return {
246
+ type: "CatchClause",
247
+ param: node.param,
248
+ body: block(body),
249
+ };
250
+ }
251
+
252
+ function transformStatement(node, scope, catchScope) {
253
+ switch (node.type) {
254
+ case "BlockStatement":
255
+ return block(transformStatementList(node.body, scope, catchScope));
256
+ case "ExpressionStatement":
257
+ return exprStmt(transformExpression(node.expression, scope, catchScope));
258
+ case "VariableDeclaration":
259
+ return transformVariableDeclaration(node, scope, catchScope);
260
+ case "ReturnStatement":
261
+ return returnStmt(node.argument ? transformExpression(node.argument, scope, catchScope) : null);
262
+ case "IfStatement":
263
+ return {
264
+ type: "IfStatement",
265
+ test: transformExpression(node.test, scope, catchScope),
266
+ consequent: wrapStatement(transformStatement(node.consequent, scope, catchScope)),
267
+ alternate: node.alternate ? wrapStatement(transformStatement(node.alternate, scope, catchScope)) : null,
268
+ };
269
+ case "WhileStatement":
270
+ return {
271
+ type: "WhileStatement",
272
+ test: transformExpression(node.test, scope, catchScope),
273
+ body: wrapStatement(transformStatement(node.body, scope, catchScope)),
274
+ };
275
+ case "DoWhileStatement":
276
+ return {
277
+ type: "DoWhileStatement",
278
+ body: wrapStatement(transformStatement(node.body, scope, catchScope)),
279
+ test: transformExpression(node.test, scope, catchScope),
280
+ };
281
+ case "ForStatement":
282
+ return {
283
+ type: "ForStatement",
284
+ init: node.init ? transformForInit(node.init, scope, catchScope) : null,
285
+ test: node.test ? transformExpression(node.test, scope, catchScope) : null,
286
+ update: node.update ? transformExpression(node.update, scope, catchScope) : null,
287
+ body: wrapStatement(transformStatement(node.body, scope, catchScope)),
288
+ };
289
+ case "ForInStatement":
290
+ return {
291
+ type: "ForInStatement",
292
+ left: node.left,
293
+ right: transformExpression(node.right, scope, catchScope),
294
+ body: wrapStatement(transformStatement(node.body, scope, catchScope)),
295
+ };
296
+ case "ForOfStatement":
297
+ return {
298
+ type: "ForOfStatement",
299
+ await: false,
300
+ left: node.left,
301
+ right: transformExpression(node.right, scope, catchScope),
302
+ body: wrapStatement(transformStatement(node.body, scope, catchScope)),
303
+ };
304
+ case "BreakStatement":
305
+ case "ContinueStatement":
306
+ case "DebuggerStatement":
307
+ case "EmptyStatement":
308
+ return clone(node);
309
+ case "ThrowStatement":
310
+ return { type: "ThrowStatement", argument: transformExpression(node.argument, scope, catchScope) };
311
+ case "TryStatement":
312
+ return {
313
+ type: "TryStatement",
314
+ block: transformStatement(node.block, scope, catchScope),
315
+ handler: node.handler ? transformCatchClause(node.handler, scope) : null,
316
+ finalizer: node.finalizer ? transformStatement(node.finalizer, scope, catchScope) : null,
317
+ };
318
+ case "SwitchStatement":
319
+ return {
320
+ type: "SwitchStatement",
321
+ discriminant: transformExpression(node.discriminant, scope, catchScope),
322
+ cases: node.cases.map((switchCase) => ({
323
+ type: "SwitchCase",
324
+ test: switchCase.test ? transformExpression(switchCase.test, scope, catchScope) : null,
325
+ consequent: transformStatementList(switchCase.consequent, scope, catchScope),
326
+ })),
327
+ };
328
+ case "FunctionDeclaration":
329
+ return null;
330
+ default:
331
+ return clone(node);
332
+ }
333
+ }
334
+
335
+ function wrapStatement(node) {
336
+ return node.type === "BlockStatement" ? node : block([node]);
337
+ }
338
+
339
+ function transformForInit(node, scope, catchScope) {
340
+ if (node.type === "VariableDeclaration") {
341
+ return node;
342
+ }
343
+ return transformExpression(node, scope, catchScope);
344
+ }
345
+
346
+ function transformVariableDeclaration(node, scope, catchScope) {
347
+ const declarations = [];
348
+ const extra = [];
349
+ for (const declarator of node.declarations) {
350
+ declarations.push(decl(declarator.id.name, null));
351
+ if (declarator.init) {
352
+ extra.push(exprStmt(transformAssignment(
353
+ { type: "AssignmentExpression", operator: "=", left: declarator.id, right: declarator.init },
354
+ scope,
355
+ catchScope,
356
+ )));
357
+ }
358
+ }
359
+ return [varDecl(node.kind, declarations), ...extra];
360
+ }
361
+
362
+ function transformExpression(node, scope, catchScope, context = {}) {
363
+ if (!node) {
364
+ return node;
365
+ }
366
+ switch (node.type) {
367
+ case "Literal":
368
+ return clone(node);
369
+ case "Identifier":
370
+ return transformIdentifier(node, scope, catchScope, context);
371
+ case "ThisExpression":
372
+ return scope.kind === "global" ? member(id("AspectScript"), id("globalObject")) : clone(node);
373
+ case "FunctionExpression":
374
+ return transformFunction(node, scope);
375
+ case "ArrayExpression":
376
+ return arrayExpr(node.elements.map((element) => element ? transformExpression(element, scope, catchScope) : null));
377
+ case "ObjectExpression":
378
+ return transformObjectExpression(node, scope, catchScope);
379
+ case "CallExpression":
380
+ return transformCall(node, scope, catchScope);
381
+ case "NewExpression":
382
+ return transformNew(node, scope, catchScope);
383
+ case "MemberExpression":
384
+ return transformMemberExpression(node, scope, catchScope, context);
385
+ case "AssignmentExpression":
386
+ return transformAssignment(node, scope, catchScope);
387
+ case "UpdateExpression":
388
+ return transformUpdate(node, scope, catchScope);
389
+ case "UnaryExpression":
390
+ return transformUnary(node, scope, catchScope);
391
+ case "BinaryExpression":
392
+ case "LogicalExpression":
393
+ return {
394
+ type: node.type,
395
+ operator: node.operator,
396
+ left: transformExpression(node.left, scope, catchScope),
397
+ right: transformExpression(node.right, scope, catchScope),
398
+ };
399
+ case "ConditionalExpression":
400
+ return {
401
+ type: "ConditionalExpression",
402
+ test: transformExpression(node.test, scope, catchScope),
403
+ consequent: transformExpression(node.consequent, scope, catchScope),
404
+ alternate: transformExpression(node.alternate, scope, catchScope),
405
+ };
406
+ case "SequenceExpression":
407
+ return {
408
+ type: "SequenceExpression",
409
+ expressions: node.expressions.map((expr) => transformExpression(expr, scope, catchScope)),
410
+ };
411
+ case "ArrayPattern":
412
+ case "ObjectPattern":
413
+ return clone(node);
414
+ default:
415
+ return clone(node);
416
+ }
417
+ }
418
+
419
+ function transformIdentifier(node, scope, catchScope, context) {
420
+ if (context.noRewrite) {
421
+ return clone(node);
422
+ }
423
+ const binding = (catchScope && catchScope.resolve(node.name)) || scope.resolve(node.name);
424
+ if (!binding) {
425
+ return clone(node);
426
+ }
427
+ if (binding.mode === "globalProp") {
428
+ return callExpr(member(id("AspectScript"), id("__getProp")), [
429
+ binding.target,
430
+ literal(node.name),
431
+ ]);
432
+ }
433
+ return callExpr(member(id("AspectScript"), id("__getVar")), [
434
+ binding.target,
435
+ literal(node.name),
436
+ functionExpr(null, [], block([returnStmt(clone(node))])),
437
+ literal(binding.mode),
438
+ ]);
439
+ }
440
+
441
+ function transformObjectExpression(node, scope, catchScope) {
442
+ const entries = [];
443
+ for (const prop of node.properties) {
444
+ if (prop.type !== "Property" || prop.kind !== "init") {
445
+ continue;
446
+ }
447
+ const key = prop.computed ? transformExpression(prop.key, scope, catchScope) :
448
+ literal(prop.key.type === "Identifier" ? prop.key.name : prop.key.value);
449
+ entries.push(objectExpr([
450
+ propertyNode(id("key"), key, prop.computed),
451
+ propertyNode(id("value"), transformExpression(prop.value, scope, catchScope)),
452
+ ]));
453
+ }
454
+ return callExpr(member(id("AspectScript"), id("__makeObjectLiteral")), [arrayExpr(entries)]);
455
+ }
456
+
457
+ function transformCall(node, scope, catchScope) {
458
+ if (node.callee.type === "MemberExpression" &&
459
+ !node.callee.computed &&
460
+ node.callee.property.type === "Identifier" &&
461
+ (node.callee.property.name === "call" || node.callee.property.name === "apply") &&
462
+ isExplicitFunctionDispatch(node.callee.object)) {
463
+ const calleeObject = node.callee.object;
464
+ const methodName = inferMethodNames(calleeObject);
465
+ const target = node.arguments[0] ? transformExpression(node.arguments[0], scope, catchScope) : literal(null);
466
+ if (node.callee.property.name === "call") {
467
+ return callExpr(member(id("AspectScript"), id("__explicitCall")), [
468
+ transformCallable(calleeObject, scope, catchScope),
469
+ target,
470
+ arrayExpr(node.arguments.slice(1).map((arg) => transformExpression(arg, scope, catchScope))),
471
+ arrayExpr(methodName.map(literal)),
472
+ ]);
473
+ }
474
+ return callExpr(member(id("AspectScript"), id("__explicitApply")), [
475
+ transformCallable(calleeObject, scope, catchScope),
476
+ target,
477
+ node.arguments[1] ? transformExpression(node.arguments[1], scope, catchScope) : arrayExpr([]),
478
+ arrayExpr(methodName.map(literal)),
479
+ ]);
480
+ }
481
+
482
+ if (node.callee.type === "MemberExpression") {
483
+ return callExpr(member(id("AspectScript"), id("__callProp")), [
484
+ transformExpression(node.callee.object, scope, catchScope),
485
+ node.callee.computed ?
486
+ transformExpression(node.callee.property, scope, catchScope) :
487
+ literal(node.callee.property.name),
488
+ arrayExpr(node.arguments.map((arg) => transformExpression(arg, scope, catchScope))),
489
+ arrayExpr(inferMethodNames(node.callee).map(literal)),
490
+ ]);
491
+ }
492
+
493
+ return callExpr(member(id("AspectScript"), id("__call")), [
494
+ member(id("AspectScript"), id("globalObject")),
495
+ transformCallable(node.callee, scope, catchScope),
496
+ arrayExpr(node.arguments.map((arg) => transformExpression(arg, scope, catchScope))),
497
+ arrayExpr(inferMethodNames(node.callee).map(literal)),
498
+ ]);
499
+ }
500
+
501
+ function isExplicitFunctionDispatch(node) {
502
+ return node.type === "Identifier" && !["AJS", "PCs", "Testing", "AspectScript"].includes(node.name);
503
+ }
504
+
505
+ function transformCallable(node, scope, catchScope) {
506
+ if (node.type === "Identifier") {
507
+ const binding = (catchScope && catchScope.resolve(node.name)) || scope.resolve(node.name);
508
+ if (binding && binding.mode === "globalProp") {
509
+ return callExpr(member(id("AspectScript"), id("__getProp")), [
510
+ binding.target,
511
+ literal(node.name),
512
+ ]);
513
+ }
514
+ return clone(node);
515
+ }
516
+ return transformExpression(node, scope, catchScope);
517
+ }
518
+
519
+ function transformNew(node, scope, catchScope) {
520
+ return callExpr(member(id("AspectScript"), id("__new")), [
521
+ transformCallable(node.callee, scope, catchScope),
522
+ arrayExpr(node.arguments.map((arg) => transformExpression(arg, scope, catchScope))),
523
+ arrayExpr(inferMethodNames(node.callee).map(literal)),
524
+ ]);
525
+ }
526
+
527
+ function transformMemberExpression(node, scope, catchScope, context) {
528
+ if (context.asLeft) {
529
+ return clone(node);
530
+ }
531
+ const object = transformExpression(node.object, scope, catchScope);
532
+ const key = node.computed ? transformExpression(node.property, scope, catchScope) : literal(node.property.name);
533
+ return callExpr(member(id("AspectScript"), id("__getProp")), [object, key]);
534
+ }
535
+
536
+ function makeSetterFunction(left, binding) {
537
+ const actualLeft = binding && binding.mode === "globalProp"
538
+ ? member(binding.target, literal(left.name), true)
539
+ : left;
540
+ return functionExpr(null, [id("__as_value")], block([returnStmt({
541
+ type: "AssignmentExpression",
542
+ operator: "=",
543
+ left: actualLeft,
544
+ right: id("__as_value"),
545
+ })]));
546
+ }
547
+
548
+ function transformAssignment(node, scope, catchScope) {
549
+ if (node.operator !== "=") {
550
+ const asBinary = {
551
+ type: "AssignmentExpression",
552
+ operator: "=",
553
+ left: node.left,
554
+ right: {
555
+ type: "BinaryExpression",
556
+ operator: node.operator.slice(0, -1),
557
+ left: clone(node.left),
558
+ right: node.right,
559
+ },
560
+ };
561
+ return transformAssignment(asBinary, scope, catchScope);
562
+ }
563
+
564
+ const right = transformExpression(node.right, scope, catchScope);
565
+ if (node.left.type === "Identifier") {
566
+ const binding = (catchScope && catchScope.resolve(node.left.name)) || scope.resolve(node.left.name);
567
+ if (binding.mode === "globalProp") {
568
+ return callExpr(member(id("AspectScript"), id("__setProp")), [
569
+ binding.target,
570
+ literal(node.left.name),
571
+ right,
572
+ ]);
573
+ }
574
+ return callExpr(member(id("AspectScript"), id("__setVar")), [
575
+ binding.target,
576
+ literal(node.left.name),
577
+ right,
578
+ makeSetterFunction(clone(node.left), binding),
579
+ literal(binding.mode),
580
+ ]);
581
+ }
582
+
583
+ if (node.left.type === "MemberExpression") {
584
+ return callExpr(member(id("AspectScript"), id("__setProp")), [
585
+ transformExpression(node.left.object, scope, catchScope),
586
+ node.left.computed ? transformExpression(node.left.property, scope, catchScope) : literal(node.left.property.name),
587
+ right,
588
+ ]);
589
+ }
590
+
591
+ return {
592
+ type: "AssignmentExpression",
593
+ operator: "=",
594
+ left: clone(node.left),
595
+ right,
596
+ };
597
+ }
598
+
599
+ function transformUpdate(node, scope, catchScope) {
600
+ const delta = node.operator === "++" ? 1 : -1;
601
+ if (node.argument.type === "Identifier") {
602
+ const binding = (catchScope && catchScope.resolve(node.argument.name)) || scope.resolve(node.argument.name);
603
+ if (binding.mode === "globalProp") {
604
+ return callExpr(member(id("AspectScript"), id("__updateProp")), [
605
+ binding.target,
606
+ literal(node.argument.name),
607
+ literal(delta),
608
+ literal(node.prefix),
609
+ ]);
610
+ }
611
+ return callExpr(member(id("AspectScript"), id("__updateVar")), [
612
+ binding.target,
613
+ literal(node.argument.name),
614
+ functionExpr(null, [], block([returnStmt(clone(node.argument))])),
615
+ makeSetterFunction(clone(node.argument), binding),
616
+ literal(delta),
617
+ literal(node.prefix),
618
+ literal(binding.mode),
619
+ ]);
620
+ }
621
+ if (node.argument.type === "MemberExpression") {
622
+ return callExpr(member(id("AspectScript"), id("__updateProp")), [
623
+ transformExpression(node.argument.object, scope, catchScope),
624
+ node.argument.computed ? transformExpression(node.argument.property, scope, catchScope) : literal(node.argument.property.name),
625
+ literal(delta),
626
+ literal(node.prefix),
627
+ ]);
628
+ }
629
+ return clone(node);
630
+ }
631
+
632
+ function transformUnary(node, scope, catchScope) {
633
+ if (node.operator === "delete" && node.argument.type === "MemberExpression") {
634
+ return callExpr(member(id("AspectScript"), id("__deleteProp")), [
635
+ transformExpression(node.argument.object, scope, catchScope),
636
+ node.argument.computed ? transformExpression(node.argument.property, scope, catchScope) : literal(node.argument.property.name),
637
+ ]);
638
+ }
639
+ return {
640
+ type: "UnaryExpression",
641
+ operator: node.operator,
642
+ prefix: node.prefix,
643
+ argument: transformExpression(node.argument, scope, catchScope),
644
+ };
645
+ }
646
+
647
+ function inferMethodNames(node) {
648
+ if (!node) {
649
+ return [];
650
+ }
651
+ if (node.type === "Identifier") {
652
+ return [node.name];
653
+ }
654
+ if (node.type === "MemberExpression" && !node.computed && node.property.type === "Identifier") {
655
+ return [node.property.name];
656
+ }
657
+ return [];
658
+ }
659
+
660
+ if (typeof module !== "undefined" && module.exports) {
661
+ module.exports = {
662
+ transformProgram,
663
+ };
664
+ } else {
665
+ globalThis.AspectScriptInstrument = {
666
+ transformProgram,
667
+ };
668
+ }