hermes-transform 0.5.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.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +8 -0
  3. package/dist/detachedNode.js +128 -0
  4. package/dist/detachedNode.js.flow +113 -0
  5. package/dist/generated/TransformCloneSignatures.js.flow +19 -0
  6. package/dist/generated/TransformReplaceSignatures.js.flow +943 -0
  7. package/dist/generated/node-types.js +2071 -0
  8. package/dist/generated/node-types.js.flow +3149 -0
  9. package/dist/generated/special-case-node-types.js +178 -0
  10. package/dist/generated/special-case-node-types.js.flow +248 -0
  11. package/dist/getVisitorKeys.js +35 -0
  12. package/dist/getVisitorKeys.js.flow +31 -0
  13. package/dist/index.js +41 -0
  14. package/dist/index.js.flow +15 -0
  15. package/dist/transform/Errors.js +151 -0
  16. package/dist/transform/Errors.js.flow +17 -0
  17. package/dist/transform/MutationContext.js +94 -0
  18. package/dist/transform/MutationContext.js.flow +80 -0
  19. package/dist/transform/TransformContext.js +136 -0
  20. package/dist/transform/TransformContext.js.flow +378 -0
  21. package/dist/transform/comments/comments.js +140 -0
  22. package/dist/transform/comments/comments.js.flow +145 -0
  23. package/dist/transform/comments/prettier/README.md +6 -0
  24. package/dist/transform/comments/prettier/common/util.js +365 -0
  25. package/dist/transform/comments/prettier/common/util.js.flow +349 -0
  26. package/dist/transform/comments/prettier/language-js/comments.js +777 -0
  27. package/dist/transform/comments/prettier/language-js/comments.js.flow +950 -0
  28. package/dist/transform/comments/prettier/language-js/loc.js +41 -0
  29. package/dist/transform/comments/prettier/language-js/loc.js.flow +41 -0
  30. package/dist/transform/comments/prettier/language-js/printer-estree.js +31 -0
  31. package/dist/transform/comments/prettier/language-js/printer-estree.js.flow +37 -0
  32. package/dist/transform/comments/prettier/language-js/utils.js +131 -0
  33. package/dist/transform/comments/prettier/language-js/utils.js.flow +135 -0
  34. package/dist/transform/comments/prettier/main/comments.js +513 -0
  35. package/dist/transform/comments/prettier/main/comments.js.flow +436 -0
  36. package/dist/transform/comments/prettier/utils/get-last.js +15 -0
  37. package/dist/transform/comments/prettier/utils/get-last.js.flow +14 -0
  38. package/dist/transform/getTransformedAST.js +159 -0
  39. package/dist/transform/getTransformedAST.js.flow +128 -0
  40. package/dist/transform/mutations/AddLeadingComments.js +47 -0
  41. package/dist/transform/mutations/AddLeadingComments.js.flow +49 -0
  42. package/dist/transform/mutations/AddTrailingComments.js +47 -0
  43. package/dist/transform/mutations/AddTrailingComments.js.flow +49 -0
  44. package/dist/transform/mutations/CloneCommentsTo.js +46 -0
  45. package/dist/transform/mutations/CloneCommentsTo.js.flow +51 -0
  46. package/dist/transform/mutations/InsertStatement.js +92 -0
  47. package/dist/transform/mutations/InsertStatement.js.flow +113 -0
  48. package/dist/transform/mutations/RemoveComment.js +96 -0
  49. package/dist/transform/mutations/RemoveComment.js.flow +80 -0
  50. package/dist/transform/mutations/RemoveStatement.js +61 -0
  51. package/dist/transform/mutations/RemoveStatement.js.flow +68 -0
  52. package/dist/transform/mutations/ReplaceNode.js +96 -0
  53. package/dist/transform/mutations/ReplaceNode.js.flow +113 -0
  54. package/dist/transform/mutations/ReplaceStatementWithMany.js +81 -0
  55. package/dist/transform/mutations/ReplaceStatementWithMany.js.flow +102 -0
  56. package/dist/transform/mutations/utils/arrayUtils.js +41 -0
  57. package/dist/transform/mutations/utils/arrayUtils.js.flow +35 -0
  58. package/dist/transform/mutations/utils/getStatementParent.js +147 -0
  59. package/dist/transform/mutations/utils/getStatementParent.js.flow +143 -0
  60. package/dist/transform/mutations/utils/isValidModuleDeclarationParent.js +53 -0
  61. package/dist/transform/mutations/utils/isValidModuleDeclarationParent.js.flow +50 -0
  62. package/dist/transform/transform.js +69 -0
  63. package/dist/transform/transform.js.flow +60 -0
  64. package/dist/traverse/NodeEventGenerator.js +427 -0
  65. package/dist/traverse/NodeEventGenerator.js.flow +406 -0
  66. package/dist/traverse/SafeEmitter.js +70 -0
  67. package/dist/traverse/SafeEmitter.js.flow +46 -0
  68. package/dist/traverse/SimpleTraverser.js +149 -0
  69. package/dist/traverse/SimpleTraverser.js.flow +109 -0
  70. package/dist/traverse/esquery.js +37 -0
  71. package/dist/traverse/esquery.js.flow +173 -0
  72. package/dist/traverse/traverse.js +139 -0
  73. package/dist/traverse/traverse.js.flow +149 -0
  74. package/package.json +22 -0
@@ -0,0 +1,436 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const assert = require('assert');
13
+
14
+ const {
15
+ hasNewline,
16
+ addLeadingComment,
17
+ addDanglingComment,
18
+ addTrailingComment,
19
+ } = require('../common/util.js');
20
+
21
+ const childNodesCache = new WeakMap();
22
+ function getSortedChildNodes(node, options, resultArray) {
23
+ if (!node) {
24
+ return;
25
+ }
26
+ const {printer, locStart, locEnd} = options;
27
+
28
+ if (resultArray) {
29
+ if (printer.canAttachComment && printer.canAttachComment(node)) {
30
+ // This reverse insertion sort almost always takes constant
31
+ // time because we almost always (maybe always?) append the
32
+ // nodes in order anyway.
33
+ let i;
34
+ for (i = resultArray.length - 1; i >= 0; --i) {
35
+ if (
36
+ locStart(resultArray[i]) <= locStart(node) &&
37
+ locEnd(resultArray[i]) <= locEnd(node)
38
+ ) {
39
+ break;
40
+ }
41
+ }
42
+ resultArray.splice(i + 1, 0, node);
43
+ return;
44
+ }
45
+ } else if (childNodesCache.has(node)) {
46
+ return childNodesCache.get(node);
47
+ }
48
+
49
+ const childNodes =
50
+ (printer.getCommentChildNodes &&
51
+ printer.getCommentChildNodes(node, options)) ||
52
+ (typeof node === 'object' &&
53
+ Object.entries(node)
54
+ .filter(
55
+ ([key]) =>
56
+ key !== 'enclosingNode' &&
57
+ key !== 'precedingNode' &&
58
+ key !== 'followingNode' &&
59
+ key !== 'tokens' &&
60
+ key !== 'comments',
61
+ )
62
+ .map(([, value]) => value));
63
+
64
+ if (!childNodes) {
65
+ return;
66
+ }
67
+
68
+ if (!resultArray) {
69
+ resultArray = [];
70
+ childNodesCache.set(node, resultArray);
71
+ }
72
+
73
+ for (const childNode of childNodes) {
74
+ getSortedChildNodes(childNode, options, resultArray);
75
+ }
76
+
77
+ return resultArray;
78
+ }
79
+
80
+ // As efficiently as possible, decorate the comment object with
81
+ // .precedingNode, .enclosingNode, and/or .followingNode properties, at
82
+ // least one of which is guaranteed to be defined.
83
+ function decorateComment(node, comment, options, enclosingNode) {
84
+ const {locStart, locEnd} = options;
85
+ const commentStart = locStart(comment);
86
+ const commentEnd = locEnd(comment);
87
+
88
+ const childNodes = getSortedChildNodes(node, options);
89
+ let precedingNode;
90
+ let followingNode;
91
+ // Time to dust off the old binary search robes and wizard hat.
92
+ let left = 0;
93
+ let right = childNodes.length;
94
+ while (left < right) {
95
+ const middle = (left + right) >> 1;
96
+ const child = childNodes[middle];
97
+ const start = locStart(child);
98
+ const end = locEnd(child);
99
+
100
+ // The comment is completely contained by this child node.
101
+ if (start <= commentStart && commentEnd <= end) {
102
+ // Abandon the binary search at this level.
103
+ return decorateComment(child, comment, options, child);
104
+ }
105
+
106
+ if (end <= commentStart) {
107
+ // This child node falls completely before the comment.
108
+ // Because we will never consider this node or any nodes
109
+ // before it again, this node must be the closest preceding
110
+ // node we have encountered so far.
111
+ precedingNode = child;
112
+ left = middle + 1;
113
+ continue;
114
+ }
115
+
116
+ if (commentEnd <= start) {
117
+ // This child node falls completely after the comment.
118
+ // Because we will never consider this node or any nodes after
119
+ // it again, this node must be the closest following node we
120
+ // have encountered so far.
121
+ followingNode = child;
122
+ right = middle;
123
+ continue;
124
+ }
125
+
126
+ /* istanbul ignore next */
127
+ throw new Error('Comment location overlaps with node location');
128
+ }
129
+
130
+ // We don't want comments inside of different expressions inside of the same
131
+ // template literal to move to another expression.
132
+ if (enclosingNode && enclosingNode.type === 'TemplateLiteral') {
133
+ const {quasis} = enclosingNode;
134
+ const commentIndex = findExpressionIndexForComment(
135
+ quasis,
136
+ comment,
137
+ options,
138
+ );
139
+
140
+ if (
141
+ precedingNode &&
142
+ findExpressionIndexForComment(quasis, precedingNode, options) !==
143
+ commentIndex
144
+ ) {
145
+ precedingNode = null;
146
+ }
147
+ if (
148
+ followingNode &&
149
+ findExpressionIndexForComment(quasis, followingNode, options) !==
150
+ commentIndex
151
+ ) {
152
+ followingNode = null;
153
+ }
154
+ }
155
+
156
+ return {enclosingNode, precedingNode, followingNode};
157
+ }
158
+
159
+ const returnFalse = () => false;
160
+ function attach(comments, ast, text, options) {
161
+ if (!Array.isArray(comments)) {
162
+ return;
163
+ }
164
+
165
+ const tiesToBreak = [];
166
+ const {
167
+ locStart,
168
+ locEnd,
169
+ printer: {handleComments = {}},
170
+ } = options;
171
+ // TODO: Make this as default behavior
172
+ const {
173
+ avoidAstMutation,
174
+ ownLine: handleOwnLineComment = returnFalse,
175
+ endOfLine: handleEndOfLineComment = returnFalse,
176
+ remaining: handleRemainingComment = returnFalse,
177
+ } = handleComments;
178
+
179
+ const decoratedComments = comments.map((comment, index) => ({
180
+ ...decorateComment(ast, comment, options),
181
+ comment,
182
+ text,
183
+ options,
184
+ ast,
185
+ isLastComment: comments.length - 1 === index,
186
+ }));
187
+
188
+ for (const [index, context] of decoratedComments.entries()) {
189
+ const {
190
+ comment,
191
+ precedingNode,
192
+ enclosingNode,
193
+ followingNode,
194
+ text,
195
+ options,
196
+ ast,
197
+ isLastComment,
198
+ } = context;
199
+
200
+ if (
201
+ options.parser === 'json' ||
202
+ options.parser === 'json5' ||
203
+ options.parser === '__js_expression' ||
204
+ options.parser === '__vue_expression'
205
+ ) {
206
+ if (locStart(comment) - locStart(ast) <= 0) {
207
+ addLeadingComment(ast, comment);
208
+ continue;
209
+ }
210
+ if (locEnd(comment) - locEnd(ast) >= 0) {
211
+ addTrailingComment(ast, comment);
212
+ continue;
213
+ }
214
+ }
215
+
216
+ let args;
217
+ if (avoidAstMutation) {
218
+ args = [context];
219
+ } else {
220
+ comment.enclosingNode = enclosingNode;
221
+ comment.precedingNode = precedingNode;
222
+ comment.followingNode = followingNode;
223
+ args = [comment, text, options, ast, isLastComment];
224
+ }
225
+
226
+ if (isOwnLineComment(text, options, decoratedComments, index)) {
227
+ comment.placement = 'ownLine';
228
+ // If a comment exists on its own line, prefer a leading comment.
229
+ // We also need to check if it's the first line of the file.
230
+ if (handleOwnLineComment(...args)) {
231
+ // We're good
232
+ } else if (followingNode) {
233
+ // Always a leading comment.
234
+ addLeadingComment(followingNode, comment);
235
+ } else if (precedingNode) {
236
+ addTrailingComment(precedingNode, comment);
237
+ } else if (enclosingNode) {
238
+ addDanglingComment(enclosingNode, comment);
239
+ } else {
240
+ // There are no nodes, let's attach it to the root of the ast
241
+ /* istanbul ignore next */
242
+ addDanglingComment(ast, comment);
243
+ }
244
+ } else if (isEndOfLineComment(text, options, decoratedComments, index)) {
245
+ comment.placement = 'endOfLine';
246
+ if (handleEndOfLineComment(...args)) {
247
+ // We're good
248
+ } else if (precedingNode) {
249
+ // There is content before this comment on the same line, but
250
+ // none after it, so prefer a trailing comment of the previous node.
251
+ addTrailingComment(precedingNode, comment);
252
+ } else if (followingNode) {
253
+ addLeadingComment(followingNode, comment);
254
+ } else if (enclosingNode) {
255
+ addDanglingComment(enclosingNode, comment);
256
+ } else {
257
+ // There are no nodes, let's attach it to the root of the ast
258
+ /* istanbul ignore next */
259
+ addDanglingComment(ast, comment);
260
+ }
261
+ } else {
262
+ comment.placement = 'remaining';
263
+ if (handleRemainingComment(...args)) {
264
+ // We're good
265
+ } else if (precedingNode && followingNode) {
266
+ // Otherwise, text exists both before and after the comment on
267
+ // the same line. If there is both a preceding and following
268
+ // node, use a tie-breaking algorithm to determine if it should
269
+ // be attached to the next or previous node. In the last case,
270
+ // simply attach the right node;
271
+ const tieCount = tiesToBreak.length;
272
+ if (tieCount > 0) {
273
+ const lastTie = tiesToBreak[tieCount - 1];
274
+ if (lastTie.followingNode !== followingNode) {
275
+ breakTies(tiesToBreak, text, options);
276
+ }
277
+ }
278
+ tiesToBreak.push(context);
279
+ } else if (precedingNode) {
280
+ addTrailingComment(precedingNode, comment);
281
+ } else if (followingNode) {
282
+ addLeadingComment(followingNode, comment);
283
+ } else if (enclosingNode) {
284
+ addDanglingComment(enclosingNode, comment);
285
+ } else {
286
+ // There are no nodes, let's attach it to the root of the ast
287
+ /* istanbul ignore next */
288
+ addDanglingComment(ast, comment);
289
+ }
290
+ }
291
+ }
292
+
293
+ breakTies(tiesToBreak, text, options);
294
+
295
+ if (!avoidAstMutation) {
296
+ for (const comment of comments) {
297
+ // These node references were useful for breaking ties, but we
298
+ // don't need them anymore, and they create cycles in the AST that
299
+ // may lead to infinite recursion if we don't delete them here.
300
+ delete comment.precedingNode;
301
+ delete comment.enclosingNode;
302
+ delete comment.followingNode;
303
+ }
304
+ }
305
+ }
306
+
307
+ const isAllEmptyAndNoLineBreak = text => !/[\S\n\u2028\u2029]/.test(text);
308
+ function isOwnLineComment(text, options, decoratedComments, commentIndex) {
309
+ const {comment, precedingNode} = decoratedComments[commentIndex];
310
+ const {locStart, locEnd} = options;
311
+ let start = locStart(comment);
312
+
313
+ if (precedingNode) {
314
+ // Find first comment on the same line
315
+ for (let index = commentIndex - 1; index >= 0; index--) {
316
+ const {comment, precedingNode: currentCommentPrecedingNode} =
317
+ decoratedComments[index];
318
+ if (
319
+ currentCommentPrecedingNode !== precedingNode ||
320
+ !isAllEmptyAndNoLineBreak(text.slice(locEnd(comment), start))
321
+ ) {
322
+ break;
323
+ }
324
+ start = locStart(comment);
325
+ }
326
+ }
327
+
328
+ return hasNewline(text, start, {backwards: true});
329
+ }
330
+
331
+ function isEndOfLineComment(text, options, decoratedComments, commentIndex) {
332
+ const {comment, followingNode} = decoratedComments[commentIndex];
333
+ const {locStart, locEnd} = options;
334
+ let end = locEnd(comment);
335
+
336
+ if (followingNode) {
337
+ // Find last comment on the same line
338
+ for (
339
+ let index = commentIndex + 1;
340
+ index < decoratedComments.length;
341
+ index++
342
+ ) {
343
+ const {comment, followingNode: currentCommentFollowingNode} =
344
+ decoratedComments[index];
345
+ if (
346
+ currentCommentFollowingNode !== followingNode ||
347
+ !isAllEmptyAndNoLineBreak(text.slice(end, locStart(comment)))
348
+ ) {
349
+ break;
350
+ }
351
+ end = locEnd(comment);
352
+ }
353
+ }
354
+
355
+ return hasNewline(text, end);
356
+ }
357
+
358
+ function breakTies(tiesToBreak, text, options) {
359
+ const tieCount = tiesToBreak.length;
360
+ if (tieCount === 0) {
361
+ return;
362
+ }
363
+ const {precedingNode, followingNode, enclosingNode} = tiesToBreak[0];
364
+
365
+ const gapRegExp =
366
+ (options.printer.getGapRegex &&
367
+ options.printer.getGapRegex(enclosingNode)) ||
368
+ /^[\s(]*$/;
369
+
370
+ let gapEndPos = options.locStart(followingNode);
371
+
372
+ // Iterate backwards through tiesToBreak, examining the gaps
373
+ // between the tied comments. In order to qualify as leading, a
374
+ // comment must be separated from followingNode by an unbroken series of
375
+ // gaps (or other comments). Gaps should only contain whitespace or open
376
+ // parentheses.
377
+ let indexOfFirstLeadingComment;
378
+ for (
379
+ indexOfFirstLeadingComment = tieCount;
380
+ indexOfFirstLeadingComment > 0;
381
+ --indexOfFirstLeadingComment
382
+ ) {
383
+ const {
384
+ comment,
385
+ precedingNode: currentCommentPrecedingNode,
386
+ followingNode: currentCommentFollowingNode,
387
+ } = tiesToBreak[indexOfFirstLeadingComment - 1];
388
+ assert.strictEqual(currentCommentPrecedingNode, precedingNode);
389
+ assert.strictEqual(currentCommentFollowingNode, followingNode);
390
+
391
+ const gap = text.slice(options.locEnd(comment), gapEndPos);
392
+
393
+ if (gapRegExp.test(gap)) {
394
+ gapEndPos = options.locStart(comment);
395
+ } else {
396
+ // The gap string contained something other than whitespace or open
397
+ // parentheses.
398
+ break;
399
+ }
400
+ }
401
+
402
+ for (const [i, {comment}] of tiesToBreak.entries()) {
403
+ if (i < indexOfFirstLeadingComment) {
404
+ addTrailingComment(precedingNode, comment);
405
+ } else {
406
+ addLeadingComment(followingNode, comment);
407
+ }
408
+ }
409
+
410
+ for (const node of [precedingNode, followingNode]) {
411
+ if (node.comments && node.comments.length > 1) {
412
+ node.comments.sort((a, b) => options.locStart(a) - options.locStart(b));
413
+ }
414
+ }
415
+
416
+ tiesToBreak.length = 0;
417
+ }
418
+
419
+ function findExpressionIndexForComment(quasis, comment, options) {
420
+ const startPos = options.locStart(comment) - 1;
421
+
422
+ for (let i = 1; i < quasis.length; ++i) {
423
+ if (startPos < options.locStart(quasis[i])) {
424
+ return i - 1;
425
+ }
426
+ }
427
+
428
+ // We haven't found it, it probably means that some of the locations are off.
429
+ // Let's just return the first one.
430
+ /* istanbul ignore next */
431
+ return 0;
432
+ }
433
+
434
+ module.exports = {
435
+ attach,
436
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ */
9
+ 'use strict';
10
+
11
+ var getLast = function getLast(arr) {
12
+ return arr[arr.length - 1];
13
+ };
14
+
15
+ module.exports = getLast;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const getLast = arr => arr[arr.length - 1];
13
+
14
+ module.exports = getLast;
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ *
8
+ * @format
9
+ */
10
+ 'use strict';
11
+
12
+ Object.defineProperty(exports, "__esModule", {
13
+ value: true
14
+ });
15
+ exports.getTransformedAST = getTransformedAST;
16
+
17
+ var _hermesEslint = require("hermes-eslint");
18
+
19
+ var _detachedNode = require("../detachedNode");
20
+
21
+ var _traverse = require("../traverse/traverse");
22
+
23
+ var _MutationContext = require("./MutationContext");
24
+
25
+ var _TransformContext = require("./TransformContext");
26
+
27
+ var _comments = require("./comments/comments");
28
+
29
+ var _AddLeadingComments = require("./mutations/AddLeadingComments");
30
+
31
+ var _AddTrailingComments = require("./mutations/AddTrailingComments");
32
+
33
+ var _CloneCommentsTo = require("./mutations/CloneCommentsTo");
34
+
35
+ var _InsertStatement = require("./mutations/InsertStatement");
36
+
37
+ var _RemoveComment = require("./mutations/RemoveComment");
38
+
39
+ var _RemoveStatement = require("./mutations/RemoveStatement");
40
+
41
+ var _ReplaceNode = require("./mutations/ReplaceNode");
42
+
43
+ var _ReplaceStatementWithMany = require("./mutations/ReplaceStatementWithMany");
44
+
45
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
46
+
47
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
48
+
49
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
50
+
51
+ function getTransformedAST(code, visitors) {
52
+ var _parseForESLint = (0, _hermesEslint.parseForESLint)(code, {
53
+ sourceType: 'module'
54
+ }),
55
+ ast = _parseForESLint.ast,
56
+ scopeManager = _parseForESLint.scopeManager; // attach comments before mutation. this will ensure that as nodes are
57
+ // cloned / moved around - comments remain in the correct place with respect to the node
58
+
59
+
60
+ (0, _comments.attachComments)(ast.comments, ast, code); // traverse the AST and colllect the mutations
61
+
62
+ var transformContext = (0, _TransformContext.getTransformContext)();
63
+ (0, _traverse.traverseWithContext)(ast, scopeManager, function () {
64
+ return transformContext;
65
+ }, visitors); // apply the mutations to the AST
66
+
67
+ var mutationContext = new _MutationContext.MutationContext(code);
68
+ var removeCommentMutations = [];
69
+
70
+ var _iterator = _createForOfIteratorHelper(transformContext.mutations),
71
+ _step;
72
+
73
+ try {
74
+ var _loop = function _loop() {
75
+ var mutation = _step.value;
76
+
77
+ var mutationRoot = function () {
78
+ switch (mutation.type) {
79
+ case 'insertStatement':
80
+ {
81
+ return (0, _InsertStatement.performInsertStatementMutation)(mutationContext, mutation);
82
+ }
83
+
84
+ case 'replaceNode':
85
+ {
86
+ return (0, _ReplaceNode.performReplaceNodeMutation)(mutationContext, mutation);
87
+ }
88
+
89
+ case 'replaceStatementWithMany':
90
+ {
91
+ return (0, _ReplaceStatementWithMany.performReplaceStatementWithManyMutation)(mutationContext, mutation);
92
+ }
93
+
94
+ case 'removeStatement':
95
+ {
96
+ return (0, _RemoveStatement.performRemoveStatementMutation)(mutationContext, mutation);
97
+ }
98
+
99
+ case 'removeComment':
100
+ {
101
+ // these are handled later
102
+ removeCommentMutations.push(mutation);
103
+ return null;
104
+ }
105
+
106
+ case 'addLeadingComments':
107
+ {
108
+ return (0, _AddLeadingComments.performAddLeadingCommentsMutation)(mutationContext, mutation);
109
+ }
110
+
111
+ case 'addTrailingComments':
112
+ {
113
+ return (0, _AddTrailingComments.performAddTrailingCommentsMutation)(mutationContext, mutation);
114
+ }
115
+
116
+ case 'cloneCommentsTo':
117
+ {
118
+ return (0, _CloneCommentsTo.performCloneCommentsToMutation)(mutationContext, mutation);
119
+ }
120
+ }
121
+ }(); // ensure the subtree's parent pointers are correct
122
+ // this is required for two reasons:
123
+ // 1) The userland transform is just JS - so there's nothing stopping them
124
+ // from doing anything dodgy. The flow types have some enforcement, but
125
+ // ofc that can just be ignored with a suppression.
126
+ // 2) Shallow clones are a necessary evil in the transform because they
127
+ // allow codemods to do simple changes to just one node without the
128
+ // weight that comes with deeply cloning the entire AST.
129
+ // However we can't update the parent pointers of the cloned node's
130
+ // children until the mutation step or else we would be mutating
131
+ // real AST nodes and potentially break the traverse step.
132
+ //
133
+ // Being strict here just helps us ensure we keep everything in sync
134
+
135
+
136
+ if (mutationRoot) {
137
+ (0, _detachedNode.updateAllParentPointers)(mutationRoot);
138
+ }
139
+ };
140
+
141
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
142
+ _loop();
143
+ } // remove the comments
144
+ // this is done at the end because it requires a complete traversal of the AST
145
+ // so that we can find relevant node's attachment array
146
+
147
+ } catch (err) {
148
+ _iterator.e(err);
149
+ } finally {
150
+ _iterator.f();
151
+ }
152
+
153
+ (0, _RemoveComment.performRemoveCommentMutations)(ast, removeCommentMutations);
154
+ return {
155
+ ast: ast,
156
+ astWasMutated: transformContext.astWasMutated,
157
+ mutatedCode: mutationContext.code
158
+ };
159
+ }