@dacely/toildefender 0.1.4 → 0.1.6

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.
@@ -46,9 +46,358 @@ function blockToArray (node) {
46
46
 
47
47
  if (Array.isArray(node.body)) {
48
48
  return node.body;
49
- } else {
49
+ } else if (node.body) {
50
50
  return [ node.body ];
51
+ } else {
52
+ return [ node ];
53
+ }
54
+ }
55
+
56
+ function hasSpreadElement(nodes) {
57
+ return nodes.some(node => node && node.type == "SpreadElement");
58
+ }
59
+
60
+ function isSimpleThisReceiver(node) {
61
+ return node.type == "Identifier" || node.type == "ThisExpression";
62
+ }
63
+
64
+ function buildArrayConcat(parts) {
65
+ if (parts.length == 0) {
66
+ return { type: "ArrayExpression", elements: [] };
67
+ }
68
+ if (parts.length == 1) {
69
+ return parts[0];
70
+ }
71
+ return {
72
+ type: "CallExpression",
73
+ callee: {
74
+ type: "MemberExpression",
75
+ object: parts[0],
76
+ property: { type: "Identifier", name: "concat" },
77
+ computed: false
78
+ },
79
+ arguments: parts.slice(1)
80
+ };
81
+ }
82
+
83
+ function spreadArgumentsToArray(args) {
84
+ var parts = [];
85
+ var pending = [];
86
+
87
+ function flushPending() {
88
+ if (pending.length > 0) {
89
+ parts.push({ type: "ArrayExpression", elements: pending });
90
+ pending = [];
91
+ }
92
+ }
93
+
94
+ args.forEach(arg => {
95
+ if (arg.type == "SpreadElement") {
96
+ flushPending();
97
+ parts.push(arg.argument);
98
+ } else {
99
+ pending.push(arg);
100
+ }
101
+ });
102
+ flushPending();
103
+
104
+ return buildArrayConcat(parts);
105
+ }
106
+
107
+ function isLoopOrSwitch(node) {
108
+ return node.type == "WhileStatement"
109
+ || node.type == "DoWhileStatement"
110
+ || node.type == "ForStatement"
111
+ || node.type == "ForInStatement"
112
+ || node.type == "ForOfStatement"
113
+ || node.type == "SwitchStatement";
114
+ }
115
+
116
+ function exitsCurrentTry(node, stack) {
117
+ if (node.type == "ReturnStatement") {
118
+ return true;
119
+ }
120
+
121
+ if (node.type == "BreakStatement" || node.type == "ContinueStatement") {
122
+ return !stack.some(frame => isLoopOrSwitch(frame.node));
123
+ }
124
+
125
+ return false;
126
+ }
127
+
128
+ function withFinalizerBefore(node, finalizer) {
129
+ var body = [];
130
+
131
+ if (node.type == "ReturnStatement") {
132
+ body.push({
133
+ type: "VariableDeclaration",
134
+ kind: "var",
135
+ declarations: [
136
+ {
137
+ type: "VariableDeclarator",
138
+ id: { type: "Identifier", name: "veilmark$return" },
139
+ init: node.argument
140
+ }
141
+ ]
142
+ });
143
+ body.push(utils.cloneISwearIKnowWhatImDoing(finalizer));
144
+ body.push({
145
+ type: "ReturnStatement",
146
+ argument: { type: "Identifier", name: "veilmark$return" }
147
+ });
148
+ } else {
149
+ body.push(utils.cloneISwearIKnowWhatImDoing(finalizer));
150
+ body.push(node);
151
+ }
152
+
153
+ return {
154
+ type: "BlockStatement",
155
+ body: body
156
+ };
157
+ }
158
+
159
+ function methodDefinitionName(method) {
160
+ if (!method || !method.key) {
161
+ return "";
162
+ }
163
+ if (method.key.type == "Identifier") {
164
+ return method.key.name;
165
+ }
166
+ if (method.key.type == "Literal") {
167
+ return String(method.key.value);
168
+ }
169
+ return "";
170
+ }
171
+
172
+ function isConstructorMethod(method) {
173
+ return method.type == "MethodDefinition" && method.kind == "constructor" && methodDefinitionName(method) == "constructor";
174
+ }
175
+
176
+ function privateStoreName(className, privateName) {
177
+ return `$$private$${className}$${privateName}`;
178
+ }
179
+
180
+ function classFieldKey(field) {
181
+ if (field.key.type == "Identifier") {
182
+ return {
183
+ type: "Identifier",
184
+ name: field.key.name
185
+ };
186
+ }
187
+ if (field.key.type == "PrivateIdentifier") {
188
+ return {
189
+ type: "Literal",
190
+ value: field.key.name
191
+ };
192
+ }
193
+ return field.key;
194
+ }
195
+
196
+ function assignmentStatement(left, right) {
197
+ return {
198
+ type: "ExpressionStatement",
199
+ expression: {
200
+ type: "AssignmentExpression",
201
+ operator: "=",
202
+ left: left,
203
+ right: right || { type: "Identifier", name: "undefined" }
204
+ }
205
+ };
206
+ }
207
+
208
+ function weakMapSetStatement(storeName, object, value) {
209
+ return {
210
+ type: "ExpressionStatement",
211
+ expression: {
212
+ type: "CallExpression",
213
+ callee: {
214
+ type: "MemberExpression",
215
+ object: { type: "Identifier", name: storeName },
216
+ property: { type: "Identifier", name: "set" },
217
+ computed: false
218
+ },
219
+ arguments: [
220
+ object,
221
+ value || { type: "Identifier", name: "undefined" }
222
+ ]
223
+ }
224
+ };
225
+ }
226
+
227
+ function weakMapGetExpression(storeName, object) {
228
+ return {
229
+ type: "CallExpression",
230
+ callee: {
231
+ type: "MemberExpression",
232
+ object: { type: "Identifier", name: storeName },
233
+ property: { type: "Identifier", name: "get" },
234
+ computed: false
235
+ },
236
+ arguments: [ object ]
237
+ };
238
+ }
239
+
240
+ function undefinedExpression() {
241
+ return { type: "Identifier", name: "undefined" };
242
+ }
243
+
244
+ function nullishTest(expression) {
245
+ return {
246
+ type: "BinaryExpression",
247
+ operator: "==",
248
+ left: expression,
249
+ right: { type: "Literal", value: null }
250
+ };
251
+ }
252
+
253
+ function notNullishTest(expression) {
254
+ return {
255
+ type: "BinaryExpression",
256
+ operator: "!=",
257
+ left: expression,
258
+ right: { type: "Literal", value: null }
259
+ };
260
+ }
261
+
262
+ function propertyKeyValue(property) {
263
+ if (property.key.type == "Identifier") {
264
+ return property.key.name;
265
+ }
266
+ if (property.key.type == "Literal") {
267
+ return property.key.value;
268
+ }
269
+ return null;
270
+ }
271
+
272
+ function propertyMemberExpression(object, property) {
273
+ return {
274
+ type: "MemberExpression",
275
+ object: object,
276
+ property: property.key.type == "Identifier"
277
+ ? { type: "Identifier", name: property.key.name }
278
+ : utils.cloneISwearIKnowWhatImDoing(property.key),
279
+ computed: property.computed === true || property.key.type == "Literal"
280
+ };
281
+ }
282
+
283
+ function hasObjectRest(pattern) {
284
+ return pattern.type == "ObjectPattern" && pattern.properties.some(prop => prop.type == "RestElement");
285
+ }
286
+
287
+ function canLowerObjectRest(pattern) {
288
+ return pattern.type == "ObjectPattern" && pattern.properties.every(prop => {
289
+ if (prop.type == "RestElement") {
290
+ return prop.argument.type == "Identifier";
291
+ }
292
+ if (prop.type != "Property" || prop.computed === true || propertyKeyValue(prop) == null) {
293
+ return false;
294
+ }
295
+ if (prop.value.type == "Identifier") {
296
+ return true;
297
+ }
298
+ return prop.value.type == "AssignmentPattern" && prop.value.left.type == "Identifier";
299
+ });
300
+ }
301
+
302
+ function hasObjectSpread(node) {
303
+ return node.properties.some(prop => prop.type == "SpreadElement");
304
+ }
305
+
306
+ function objectAssignCall(parts) {
307
+ return {
308
+ type: "CallExpression",
309
+ callee: {
310
+ type: "MemberExpression",
311
+ object: { type: "Identifier", name: "Object" },
312
+ property: { type: "Identifier", name: "assign" },
313
+ computed: false
314
+ },
315
+ arguments: parts
316
+ };
317
+ }
318
+
319
+ function objectWithoutKeysCall(source, keys) {
320
+ return {
321
+ type: "CallExpression",
322
+ callee: { type: "Identifier", name: "veilmark$objectWithoutKeys" },
323
+ arguments: [
324
+ source,
325
+ {
326
+ type: "ArrayExpression",
327
+ elements: keys.map(key => ({ type: "Literal", value: key }))
328
+ }
329
+ ]
330
+ };
331
+ }
332
+
333
+ function objectPatternPropertyDeclaration(kind, sourceName, prop) {
334
+ var member = propertyMemberExpression(
335
+ { type: "Identifier", name: sourceName },
336
+ prop
337
+ );
338
+ var id = prop.value;
339
+ var init = member;
340
+
341
+ if (prop.value.type == "AssignmentPattern") {
342
+ id = prop.value.left;
343
+ init = {
344
+ type: "ConditionalExpression",
345
+ test: {
346
+ type: "BinaryExpression",
347
+ operator: "===",
348
+ left: utils.cloneISwearIKnowWhatImDoing(member),
349
+ right: undefinedExpression()
350
+ },
351
+ consequent: prop.value.right,
352
+ alternate: member
353
+ };
51
354
  }
355
+
356
+ return {
357
+ type: "VariableDeclaration",
358
+ kind: kind,
359
+ declarations: [
360
+ {
361
+ type: "VariableDeclarator",
362
+ id: id,
363
+ init: init
364
+ }
365
+ ]
366
+ };
367
+ }
368
+
369
+ function containsThisExpression(node) {
370
+ var found = false;
371
+ traverser.traverseEx(node, [], function (child) {
372
+ if (child.type == "ThisExpression") {
373
+ found = true;
374
+ this.abort();
375
+ }
376
+ return child;
377
+ });
378
+ return found;
379
+ }
380
+
381
+ function blockNeedsLexicalScope(node) {
382
+ if (node.type != "BlockStatement") {
383
+ return false;
384
+ }
385
+
386
+ var needsScope = false;
387
+ traverser.traverseEx(node, [], function (child) {
388
+ if (child != node && estest.isFunction(child)) {
389
+ return child;
390
+ }
391
+ if (
392
+ (child.type == "VariableDeclaration" && child.kind != "var")
393
+ || child.type == "ClassDeclaration"
394
+ ) {
395
+ needsScope = true;
396
+ this.abort();
397
+ }
398
+ return child;
399
+ });
400
+ return needsScope;
52
401
  }
53
402
 
54
403
  module.exports = class Normalizer {
@@ -79,10 +428,26 @@ module.exports = class Normalizer {
79
428
  return this.simplifyForStatement(node);
80
429
  case "ForInStatement":
81
430
  return this.simplifyForStatement(this.simplifyForInStatement(node));
431
+ case "ForOfStatement":
432
+ return this.simplifyForOfStatement(node);
82
433
  /*case "SwitchStatement":
83
434
  return this.simplifySwitchStatement(node);*/
84
435
  case "TryStatement":
85
436
  return this.simplifyTryStatement(node);
437
+ case "CallExpression":
438
+ return this.simplifyCallExpression(node);
439
+ case "ChainExpression":
440
+ return this.simplifyChainExpression(node);
441
+ case "LogicalExpression":
442
+ return this.simplifyLogicalExpression(node);
443
+ case "ObjectExpression":
444
+ return this.simplifyObjectExpression(node);
445
+ case "VariableDeclaration":
446
+ return this.simplifyVariableDeclaration(node, stack);
447
+ case "ArrowFunctionExpression":
448
+ return this.simplifyArrowFunctionExpression(node);
449
+ case "ClassDeclaration":
450
+ return this.simplifyClassDeclaration(node);
86
451
  default:
87
452
  return node;
88
453
  }
@@ -98,10 +463,13 @@ module.exports = class Normalizer {
98
463
  simplifyBlockStatement (node) {
99
464
  assert.ok(estest.isNode(node));
100
465
 
101
- function getBlockBodys(node) {
466
+ function getBlockBodys(node, isRoot) {
102
467
  if (node.type == "Program" || node.type == "BlockStatement") {
468
+ if (!isRoot && blockNeedsLexicalScope(node)) {
469
+ return [ node ];
470
+ }
103
471
  var stmts = [];
104
- node.body.forEach(stmt => utils.push(stmts, getBlockBodys(stmt)));
472
+ node.body.forEach(stmt => utils.push(stmts, getBlockBodys(stmt, false)));
105
473
  return stmts;
106
474
  } else {
107
475
  return [ node ];
@@ -110,7 +478,7 @@ module.exports = class Normalizer {
110
478
 
111
479
  return {
112
480
  type: node.type,
113
- body: getBlockBodys(node)
481
+ body: getBlockBodys(node, true)
114
482
  };
115
483
  }
116
484
 
@@ -299,6 +667,93 @@ module.exports = class Normalizer {
299
667
  return forStmt;
300
668
  }
301
669
 
670
+ /**
671
+ * Simplify ForOfStatement to an index-based ForStatement.
672
+ * @param {ForOfStatement} node
673
+ * @return {Node}
674
+ */
675
+ simplifyForOfStatement (node) {
676
+ assert.ok(estest.isNode(node));
677
+
678
+ var valuesName = `$$forof$values$${this.rngAlpha.get()}`, iterName = `$$forof$iter$${this.rngAlpha.get()}`;
679
+ var valueAtIndex = {
680
+ type: "MemberExpression",
681
+ object: { type: "Identifier", name: valuesName },
682
+ property: { type: "Identifier", name: iterName },
683
+ computed: true
684
+ };
685
+ var assignValue = node.left.type == "VariableDeclaration"
686
+ ?
687
+ {
688
+ type: "VariableDeclaration",
689
+ kind: node.left.kind == "const" ? "let" : node.left.kind,
690
+ declarations: [
691
+ {
692
+ type: "VariableDeclarator",
693
+ id: node.left.declarations[0].id,
694
+ init: valueAtIndex
695
+ }
696
+ ]
697
+ }
698
+ :
699
+ {
700
+ type: "ExpressionStatement",
701
+ expression: {
702
+ type: "AssignmentExpression",
703
+ operator: "=",
704
+ left: node.left,
705
+ right: valueAtIndex
706
+ }
707
+ };
708
+
709
+ return {
710
+ type: "BlockStatement",
711
+ body: [
712
+ {
713
+ type: "VariableDeclaration",
714
+ kind: "var",
715
+ declarations: [
716
+ {
717
+ type: "VariableDeclarator",
718
+ id: { type: "Identifier", name: valuesName },
719
+ init: node.right
720
+ },
721
+ {
722
+ type: "VariableDeclarator",
723
+ id: { type: "Identifier", name: iterName },
724
+ init: { type: "Literal", value: 0 }
725
+ }
726
+ ]
727
+ },
728
+ {
729
+ type: "ForStatement",
730
+ init: null,
731
+ test: {
732
+ type: "BinaryExpression",
733
+ operator: "<",
734
+ left: { type: "Identifier", name: iterName },
735
+ right: {
736
+ type: "MemberExpression",
737
+ object: { type: "Identifier", name: valuesName },
738
+ property: { type: "Identifier", name: "length" },
739
+ computed: false
740
+ }
741
+ },
742
+ update: {
743
+ type: "UpdateExpression",
744
+ operator: "++",
745
+ argument: { type: "Identifier", name: iterName },
746
+ prefix: false
747
+ },
748
+ body: {
749
+ type: "BlockStatement",
750
+ body: [assignValue].concat(blockToArray(node.body))
751
+ }
752
+ }
753
+ ]
754
+ };
755
+ }
756
+
302
757
  /**
303
758
  * Simplify SwitchStatement.
304
759
  * @param {SwitchStatement} node
@@ -416,28 +871,8 @@ module.exports = class Normalizer {
416
871
  if (stack.some(x => estest.isFunction(x.node))) {
417
872
  this.abort();
418
873
  return node;
419
- } else if (node.type == "ReturnStatement") {
420
- return {
421
- type: "BlockStatement",
422
- body: [
423
- {
424
- type: "VariableDeclaration",
425
- kind: "var",
426
- declarations: [
427
- {
428
- type: "VariableDeclarator",
429
- id: { type: "Identifier", name: "veilmark$return" },
430
- init: node.argument
431
- }
432
- ]
433
- },
434
- utils.cloneISwearIKnowWhatImDoing(finalizer),
435
- {
436
- type: "ReturnStatement",
437
- argument: { type: "Identifier", name: "veilmark$return" }
438
- }
439
- ]
440
- };
874
+ } else if (exitsCurrentTry(node, stack)) {
875
+ return withFinalizerBefore(node, finalizer);
441
876
  } else {
442
877
  return node;
443
878
  }
@@ -487,4 +922,520 @@ module.exports = class Normalizer {
487
922
  }
488
923
  }
489
924
 
925
+ /**
926
+ * Lower simple spread calls like target.push(...items) to
927
+ * target.push.apply(target, items). This keeps append-style calls stable
928
+ * even when Babel is disabled.
929
+ * @param {CallExpression} node
930
+ * @return {Node}
931
+ */
932
+ simplifyCallExpression (node) {
933
+ assert.ok(estest.isNode(node));
934
+
935
+ if (!hasSpreadElement(node.arguments)) {
936
+ return node;
937
+ }
938
+
939
+ var thisArg = { type: "Literal", value: null };
940
+ if (node.callee.type == "MemberExpression") {
941
+ if (!isSimpleThisReceiver(node.callee.object)) {
942
+ return node;
943
+ }
944
+ thisArg = utils.cloneISwearIKnowWhatImDoing(node.callee.object);
945
+ }
946
+
947
+ return {
948
+ type: "CallExpression",
949
+ callee: {
950
+ type: "MemberExpression",
951
+ object: node.callee,
952
+ property: { type: "Identifier", name: "apply" },
953
+ computed: false
954
+ },
955
+ arguments: [
956
+ thisArg,
957
+ spreadArgumentsToArray(node.arguments)
958
+ ]
959
+ };
960
+ }
961
+
962
+ /**
963
+ * Lower optional chains to conditional expressions before legacy passes.
964
+ * This intentionally targets deterministic AST compatibility rather than
965
+ * Babel-perfect single-evaluation semantics for every exotic receiver.
966
+ * @param {ChainExpression} node
967
+ * @return {Node}
968
+ */
969
+ simplifyChainExpression (node) {
970
+ assert.ok(estest.isNode(node));
971
+
972
+ return this.lowerOptionalChain(node.expression);
973
+ }
974
+
975
+ lowerOptionalChain (node) {
976
+ if (node.type == "MemberExpression") {
977
+ var object = this.lowerOptionalChain(node.object);
978
+ var member = {
979
+ type: "MemberExpression",
980
+ object: utils.cloneISwearIKnowWhatImDoing(object),
981
+ property: node.property,
982
+ computed: node.computed === true
983
+ };
984
+ if (node.optional === true) {
985
+ return {
986
+ type: "ConditionalExpression",
987
+ test: nullishTest(utils.cloneISwearIKnowWhatImDoing(object)),
988
+ consequent: undefinedExpression(),
989
+ alternate: member
990
+ };
991
+ }
992
+ return member;
993
+ }
994
+
995
+ if (node.type == "CallExpression") {
996
+ if (node.callee.type == "MemberExpression") {
997
+ return this.lowerOptionalMemberCall(node);
998
+ }
999
+
1000
+ var callee = this.lowerOptionalChain(node.callee);
1001
+ var call = {
1002
+ type: "CallExpression",
1003
+ callee: utils.cloneISwearIKnowWhatImDoing(callee),
1004
+ arguments: node.arguments,
1005
+ optional: false
1006
+ };
1007
+ if (node.optional === true) {
1008
+ return {
1009
+ type: "ConditionalExpression",
1010
+ test: nullishTest(utils.cloneISwearIKnowWhatImDoing(callee)),
1011
+ consequent: undefinedExpression(),
1012
+ alternate: call
1013
+ };
1014
+ }
1015
+ return call;
1016
+ }
1017
+
1018
+ return node;
1019
+ }
1020
+
1021
+ lowerOptionalMemberCall (node) {
1022
+ var member = node.callee;
1023
+ var object = this.lowerOptionalChain(member.object);
1024
+ var directMember = {
1025
+ type: "MemberExpression",
1026
+ object: utils.cloneISwearIKnowWhatImDoing(object),
1027
+ property: member.property,
1028
+ computed: member.computed === true
1029
+ };
1030
+
1031
+ var alternate;
1032
+ if (node.optional === true) {
1033
+ alternate = {
1034
+ type: "CallExpression",
1035
+ callee: {
1036
+ type: "MemberExpression",
1037
+ object: utils.cloneISwearIKnowWhatImDoing(directMember),
1038
+ property: { type: "Identifier", name: "call" },
1039
+ computed: false
1040
+ },
1041
+ arguments: [ utils.cloneISwearIKnowWhatImDoing(object) ].concat(node.arguments),
1042
+ optional: false
1043
+ };
1044
+ alternate = {
1045
+ type: "ConditionalExpression",
1046
+ test: nullishTest(utils.cloneISwearIKnowWhatImDoing(directMember)),
1047
+ consequent: undefinedExpression(),
1048
+ alternate: alternate
1049
+ };
1050
+ } else {
1051
+ alternate = {
1052
+ type: "CallExpression",
1053
+ callee: directMember,
1054
+ arguments: node.arguments,
1055
+ optional: false
1056
+ };
1057
+ }
1058
+
1059
+ if (member.optional === true) {
1060
+ return {
1061
+ type: "ConditionalExpression",
1062
+ test: nullishTest(utils.cloneISwearIKnowWhatImDoing(object)),
1063
+ consequent: undefinedExpression(),
1064
+ alternate: alternate
1065
+ };
1066
+ }
1067
+
1068
+ return alternate;
1069
+ }
1070
+
1071
+ /**
1072
+ * Lower nullish coalescing to an ES5-compatible conditional expression.
1073
+ * @param {LogicalExpression} node
1074
+ * @return {Node}
1075
+ */
1076
+ simplifyLogicalExpression (node) {
1077
+ assert.ok(estest.isNode(node));
1078
+
1079
+ if (node.operator != "??") {
1080
+ return node;
1081
+ }
1082
+
1083
+ return {
1084
+ type: "ConditionalExpression",
1085
+ test: notNullishTest(utils.cloneISwearIKnowWhatImDoing(node.left)),
1086
+ consequent: node.left,
1087
+ alternate: node.right
1088
+ };
1089
+ }
1090
+
1091
+ /**
1092
+ * Lower object spread to Object.assign({}, ...parts).
1093
+ * @param {ObjectExpression} node
1094
+ * @return {Node}
1095
+ */
1096
+ simplifyObjectExpression (node) {
1097
+ assert.ok(estest.isNode(node));
1098
+
1099
+ if (!hasObjectSpread(node)) {
1100
+ return node;
1101
+ }
1102
+
1103
+ var parts = [
1104
+ {
1105
+ type: "ObjectExpression",
1106
+ properties: []
1107
+ }
1108
+ ];
1109
+ var pending = [];
1110
+
1111
+ function flushPending() {
1112
+ if (pending.length > 0) {
1113
+ parts.push({
1114
+ type: "ObjectExpression",
1115
+ properties: pending
1116
+ });
1117
+ pending = [];
1118
+ }
1119
+ }
1120
+
1121
+ node.properties.forEach(prop => {
1122
+ if (prop.type == "SpreadElement") {
1123
+ flushPending();
1124
+ parts.push(prop.argument);
1125
+ } else {
1126
+ pending.push(prop);
1127
+ }
1128
+ });
1129
+ flushPending();
1130
+
1131
+ return objectAssignCall(parts);
1132
+ }
1133
+
1134
+ /**
1135
+ * Lower simple object rest declarations:
1136
+ * const { a, ...rest } = source
1137
+ * becomes:
1138
+ * var tmp = source; var a = tmp.a; var rest = withoutKeys(tmp, ["a"])
1139
+ * @param {VariableDeclaration} node
1140
+ * @param {Node[]} stack
1141
+ * @return {Node}
1142
+ */
1143
+ simplifyVariableDeclaration (node, stack) {
1144
+ assert.ok(estest.isNode(node));
1145
+
1146
+ if (!node.declarations.some(decl => hasObjectRest(decl.id))) {
1147
+ return node;
1148
+ }
1149
+ if (node.declarations.some(decl => hasObjectRest(decl.id) && !canLowerObjectRest(decl.id))) {
1150
+ return node;
1151
+ }
1152
+
1153
+ var parentFrame = stack[1];
1154
+ if (parentFrame && parentFrame.node.type == "ForStatement" && parentFrame.key == "init") {
1155
+ return node;
1156
+ }
1157
+
1158
+ var statements = [];
1159
+ var normalDeclarations = [];
1160
+ var declarationKind = node.kind == "const" ? "var" : node.kind;
1161
+
1162
+ function flushNormalDeclarations() {
1163
+ if (normalDeclarations.length > 0) {
1164
+ statements.push({
1165
+ type: "VariableDeclaration",
1166
+ kind: declarationKind,
1167
+ declarations: normalDeclarations
1168
+ });
1169
+ normalDeclarations = [];
1170
+ }
1171
+ }
1172
+
1173
+ node.declarations.forEach(decl => {
1174
+ if (!hasObjectRest(decl.id)) {
1175
+ normalDeclarations.push(decl);
1176
+ return;
1177
+ }
1178
+
1179
+ flushNormalDeclarations();
1180
+
1181
+ var sourceName = `$$destructure$obj$${this.rngAlpha.get()}`;
1182
+ statements.push({
1183
+ type: "VariableDeclaration",
1184
+ kind: "var",
1185
+ declarations: [
1186
+ {
1187
+ type: "VariableDeclarator",
1188
+ id: { type: "Identifier", name: sourceName },
1189
+ init: decl.init || { type: "ObjectExpression", properties: [] }
1190
+ }
1191
+ ]
1192
+ });
1193
+
1194
+ var excluded = [];
1195
+ decl.id.properties.forEach(prop => {
1196
+ if (prop.type == "RestElement") {
1197
+ statements.push({
1198
+ type: "VariableDeclaration",
1199
+ kind: declarationKind,
1200
+ declarations: [
1201
+ {
1202
+ type: "VariableDeclarator",
1203
+ id: prop.argument,
1204
+ init: objectWithoutKeysCall(
1205
+ { type: "Identifier", name: sourceName },
1206
+ excluded
1207
+ )
1208
+ }
1209
+ ]
1210
+ });
1211
+ return;
1212
+ }
1213
+
1214
+ var key = propertyKeyValue(prop);
1215
+ excluded.push(String(key));
1216
+ statements.push(objectPatternPropertyDeclaration(declarationKind, sourceName, prop));
1217
+ });
1218
+ });
1219
+
1220
+ flushNormalDeclarations();
1221
+
1222
+ return {
1223
+ type: "BlockStatement",
1224
+ body: statements
1225
+ };
1226
+ }
1227
+
1228
+ /**
1229
+ * Lower arrows so scope/control-flow passes do not leave callback bodies
1230
+ * inside an outer flattened frame. Bind lexical this only when needed.
1231
+ * @param {ArrowFunctionExpression} node
1232
+ * @return {Node}
1233
+ */
1234
+ simplifyArrowFunctionExpression (node) {
1235
+ assert.ok(estest.isNode(node));
1236
+
1237
+ var fn = {
1238
+ type: "FunctionExpression",
1239
+ id: null,
1240
+ params: node.params,
1241
+ body: node.body.type == "BlockStatement" ? node.body : {
1242
+ type: "BlockStatement",
1243
+ body: [
1244
+ {
1245
+ type: "ReturnStatement",
1246
+ argument: node.body
1247
+ }
1248
+ ]
1249
+ },
1250
+ generator: false,
1251
+ expression: false,
1252
+ async: node.async === true
1253
+ };
1254
+
1255
+ if (!containsThisExpression(fn.body)) {
1256
+ return fn;
1257
+ }
1258
+
1259
+ return {
1260
+ type: "CallExpression",
1261
+ callee: {
1262
+ type: "MemberExpression",
1263
+ object: fn,
1264
+ property: { type: "Identifier", name: "bind" },
1265
+ computed: false
1266
+ },
1267
+ arguments: [
1268
+ { type: "ThisExpression" }
1269
+ ]
1270
+ };
1271
+ }
1272
+
1273
+ /**
1274
+ * Lower class fields/private fields to older ESTree nodes that escodegen
1275
+ * and the classic passes can handle.
1276
+ * @param {ClassDeclaration} node
1277
+ * @return {Node}
1278
+ */
1279
+ simplifyClassDeclaration (node) {
1280
+ assert.ok(estest.isNode(node));
1281
+
1282
+ var className = node.id && node.id.name || `$$class$${this.rngAlpha.get()}`;
1283
+ var privateStores = {};
1284
+ var instanceInitializers = [];
1285
+ var staticAssignments = [];
1286
+ var methods = [];
1287
+
1288
+ node.body.body.forEach(element => {
1289
+ if (element.type != "PropertyDefinition" && element.type != "FieldDefinition") {
1290
+ methods.push(element);
1291
+ return;
1292
+ }
1293
+
1294
+ if (element.key.type == "PrivateIdentifier") {
1295
+ var storeName = privateStoreName(className, element.key.name);
1296
+ privateStores[element.key.name] = storeName;
1297
+ if (element.static) {
1298
+ staticAssignments.push(weakMapSetStatement(
1299
+ storeName,
1300
+ { type: "Identifier", name: className },
1301
+ element.value
1302
+ ));
1303
+ } else {
1304
+ instanceInitializers.push(weakMapSetStatement(
1305
+ storeName,
1306
+ { type: "ThisExpression" },
1307
+ element.value
1308
+ ));
1309
+ }
1310
+ return;
1311
+ }
1312
+
1313
+ var target = {
1314
+ type: "MemberExpression",
1315
+ object: element.static ? { type: "Identifier", name: className } : { type: "ThisExpression" },
1316
+ property: classFieldKey(element),
1317
+ computed: element.computed === true || element.key.type == "Literal"
1318
+ };
1319
+ if (element.static) {
1320
+ staticAssignments.push(assignmentStatement(target, element.value));
1321
+ } else {
1322
+ instanceInitializers.push(assignmentStatement(target, element.value));
1323
+ }
1324
+ });
1325
+
1326
+ methods.forEach(method => {
1327
+ this.lowerPrivateMembers(method, privateStores);
1328
+ });
1329
+
1330
+ if (instanceInitializers.length > 0) {
1331
+ var constructor = methods.find(isConstructorMethod);
1332
+ if (!constructor) {
1333
+ constructor = {
1334
+ type: "MethodDefinition",
1335
+ key: { type: "Identifier", name: "constructor" },
1336
+ computed: false,
1337
+ value: {
1338
+ type: "FunctionExpression",
1339
+ id: null,
1340
+ params: [],
1341
+ body: {
1342
+ type: "BlockStatement",
1343
+ body: node.superClass ? [
1344
+ {
1345
+ type: "ExpressionStatement",
1346
+ expression: {
1347
+ type: "CallExpression",
1348
+ callee: { type: "Super" },
1349
+ arguments: []
1350
+ }
1351
+ }
1352
+ ] : []
1353
+ },
1354
+ generator: false,
1355
+ expression: false,
1356
+ async: false
1357
+ },
1358
+ kind: "constructor",
1359
+ static: false
1360
+ };
1361
+ methods.unshift(constructor);
1362
+ }
1363
+
1364
+ var body = constructor.value.body.body;
1365
+ var insertAt = 0;
1366
+ if (node.superClass) {
1367
+ var superIndex = body.findIndex(stmt => stmt.type == "ExpressionStatement"
1368
+ && stmt.expression.type == "CallExpression"
1369
+ && stmt.expression.callee.type == "Super");
1370
+ insertAt = superIndex == -1 ? 0 : superIndex + 1;
1371
+ }
1372
+ body.splice.apply(body, [insertAt, 0].concat(instanceInitializers));
1373
+ }
1374
+
1375
+ node.body.body = methods;
1376
+
1377
+ var privateDeclarations = Object.keys(privateStores).map(name => {
1378
+ return {
1379
+ type: "VariableDeclaration",
1380
+ kind: "var",
1381
+ declarations: [
1382
+ {
1383
+ type: "VariableDeclarator",
1384
+ id: { type: "Identifier", name: privateStores[name] },
1385
+ init: {
1386
+ type: "NewExpression",
1387
+ callee: { type: "Identifier", name: "WeakMap" },
1388
+ arguments: []
1389
+ }
1390
+ }
1391
+ ]
1392
+ };
1393
+ });
1394
+
1395
+ if (privateDeclarations.length == 0 && staticAssignments.length == 0) {
1396
+ return node;
1397
+ }
1398
+
1399
+ return {
1400
+ type: "BlockStatement",
1401
+ body: privateDeclarations.concat([node]).concat(staticAssignments)
1402
+ };
1403
+ }
1404
+
1405
+ lowerPrivateMembers (node, privateStores) {
1406
+ traverser.traverse(node, [], (child, stack) => {
1407
+ var parentFrame = stack[1];
1408
+ if (child.type == "MemberExpression"
1409
+ && parentFrame
1410
+ && parentFrame.node.type == "AssignmentExpression"
1411
+ && parentFrame.key == "left") {
1412
+ return child;
1413
+ }
1414
+ if (child.type == "AssignmentExpression"
1415
+ && child.left.type == "MemberExpression"
1416
+ && child.left.property.type == "PrivateIdentifier"
1417
+ && privateStores[child.left.property.name]) {
1418
+ return {
1419
+ type: "CallExpression",
1420
+ callee: {
1421
+ type: "MemberExpression",
1422
+ object: { type: "Identifier", name: privateStores[child.left.property.name] },
1423
+ property: { type: "Identifier", name: "set" },
1424
+ computed: false
1425
+ },
1426
+ arguments: [
1427
+ child.left.object,
1428
+ child.right
1429
+ ]
1430
+ };
1431
+ }
1432
+ if (child.type == "MemberExpression"
1433
+ && child.property.type == "PrivateIdentifier"
1434
+ && privateStores[child.property.name]) {
1435
+ return weakMapGetExpression(privateStores[child.property.name], child.object);
1436
+ }
1437
+ return child;
1438
+ });
1439
+ }
1440
+
490
1441
  };