hermes-transform 0.8.0 → 0.9.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.
@@ -18,8 +18,9 @@ import type {
18
18
  Statement,
19
19
  TypeAnnotationType,
20
20
  } from 'hermes-estree';
21
- import type {DetachedNode} from '../detachedNode';
21
+ import type {DetachedNode, MaybeDetachedNode} from '../detachedNode';
22
22
  import type {TransformCloneSignatures} from '../generated/TransformCloneSignatures';
23
+ import type {TransformModifySignatures} from '../generated/TransformModifySignatures';
23
24
  import type {TransformReplaceSignatures} from '../generated/TransformReplaceSignatures';
24
25
  import type {TraversalContext} from '../traverse/traverse';
25
26
  import type {AddCommentsMutation} from './mutations/AddComments';
@@ -29,9 +30,12 @@ import type {RemoveCommentMutation} from './mutations/RemoveComment';
29
30
  import type {RemoveNodeMutation} from './mutations/RemoveNode';
30
31
  import type {RemoveStatementMutation} from './mutations/RemoveStatement';
31
32
  import type {ReplaceNodeMutation} from './mutations/ReplaceNode';
32
- import type {ReplaceStatementWithManyMutation} from './mutations/ReplaceStatementWithMany';
33
+ import type {
34
+ ReplaceStatementWithManyMutation,
35
+ ReplaceStatementWithManyMutationNodes,
36
+ } from './mutations/ReplaceStatementWithMany';
33
37
 
34
- import {deepCloneNode, shallowCloneNode} from '../detachedNode';
38
+ import {asDetachedNode, deepCloneNode, shallowCloneNode} from '../detachedNode';
35
39
  import {
36
40
  CommentPlacement,
37
41
  getCommentsForNode,
@@ -103,6 +107,8 @@ type TransformCloneAPIs = $ReadOnly<{
103
107
  shallowCloneArray: {
104
108
  <T: ESNode>(node: $ReadOnlyArray<T>): $ReadOnlyArray<DetachedNode<T>>,
105
109
  <T: ESNode>(node: ?$ReadOnlyArray<T>): ?$ReadOnlyArray<DetachedNode<T>>,
110
+ <T: ESNode>(node: $ReadOnlyArray<?T>): $ReadOnlyArray<DetachedNode<?T>>,
111
+ <T: ESNode>(node: ?$ReadOnlyArray<?T>): ?$ReadOnlyArray<DetachedNode<?T>>,
106
112
  },
107
113
 
108
114
  /**
@@ -148,14 +154,14 @@ type TransformCommentAPIs = $ReadOnly<{
148
154
  */
149
155
  cloneCommentsTo: (
150
156
  target: ESNode,
151
- destination: ESNode | DetachedNode<ESNode>,
157
+ destination: MaybeDetachedNode<ESNode>,
152
158
  ) => void,
153
159
 
154
160
  /**
155
161
  * Add comments on the line before a specified node.
156
162
  */
157
163
  addLeadingComments: (
158
- node: ESNode | DetachedNode<ESNode>,
164
+ node: MaybeDetachedNode<ESNode>,
159
165
  comments: SingleOrArray<Comment>,
160
166
  ) => void,
161
167
 
@@ -163,7 +169,7 @@ type TransformCommentAPIs = $ReadOnly<{
163
169
  * Add comments inline before a specified node.
164
170
  */
165
171
  addLeadingInlineComments: (
166
- node: ESNode | DetachedNode<ESNode>,
172
+ node: MaybeDetachedNode<ESNode>,
167
173
  comments: SingleOrArray<Comment>,
168
174
  ) => void,
169
175
 
@@ -171,7 +177,7 @@ type TransformCommentAPIs = $ReadOnly<{
171
177
  * Add comments on the line after a specified node.
172
178
  */
173
179
  addTrailingComments: (
174
- node: ESNode | DetachedNode<ESNode>,
180
+ node: MaybeDetachedNode<ESNode>,
175
181
  comments: SingleOrArray<Comment>,
176
182
  ) => void,
177
183
 
@@ -179,7 +185,7 @@ type TransformCommentAPIs = $ReadOnly<{
179
185
  * Add comments inline after a specified node.
180
186
  */
181
187
  addTrailingInlineComments: (
182
- node: ESNode | DetachedNode<ESNode>,
188
+ node: MaybeDetachedNode<ESNode>,
183
189
  comments: SingleOrArray<Comment>,
184
190
  ) => void,
185
191
 
@@ -197,7 +203,7 @@ type TransformInsertAPIs = $ReadOnly<{
197
203
  insertAfterStatement: (
198
204
  target: InsertStatementMutation['target'],
199
205
  nodeToInsert: SingleOrArray<
200
- DetachedNode<InsertStatementMutation['target']>,
206
+ MaybeDetachedNode<InsertStatementMutation['target']>,
201
207
  >,
202
208
  ) => void,
203
209
 
@@ -208,11 +214,19 @@ type TransformInsertAPIs = $ReadOnly<{
208
214
  insertBeforeStatement: (
209
215
  target: InsertStatementMutation['target'],
210
216
  nodeToInsert: SingleOrArray<
211
- DetachedNode<InsertStatementMutation['target']>,
217
+ MaybeDetachedNode<InsertStatementMutation['target']>,
212
218
  >,
213
219
  ) => void,
214
220
  }>;
215
221
 
222
+ type TransformModifyAPIs = $ReadOnly<{
223
+ /**
224
+ * Modifies a given node in place.
225
+ * This is equivalent to doing a replace with a shallow clone with overrides.
226
+ */
227
+ modifyNodeInPlace: TransformModifySignatures,
228
+ }>;
229
+
216
230
  type TransformRemoveAPIs = $ReadOnly<{
217
231
  /**
218
232
  * Removes a given node from the AST.
@@ -236,37 +250,37 @@ type TransformReplaceAPIs = $ReadOnly<{
236
250
  // Expressions may be replaced with other expressions
237
251
  (
238
252
  target: Expression,
239
- nodeToReplaceWith: DetachedNode<Expression>,
253
+ nodeToReplaceWith: MaybeDetachedNode<Expression>,
240
254
  options?: ReplaceNodeOptions,
241
255
  ): void,
242
256
  // Module declarations may be replaced with statements or other module declarations
243
257
  (
244
258
  target: ModuleDeclaration,
245
- nodeToReplaceWith: DetachedNode<ModuleDeclaration | Statement>,
259
+ nodeToReplaceWith: MaybeDetachedNode<ModuleDeclaration | Statement>,
246
260
  options?: ReplaceNodeOptions,
247
261
  ): void,
248
262
  // Statement maybe be replaced with statements or module declarations
249
263
  (
250
264
  target: Statement,
251
- nodeToReplaceWith: DetachedNode<ModuleDeclaration | Statement>,
265
+ nodeToReplaceWith: MaybeDetachedNode<ModuleDeclaration | Statement>,
252
266
  options?: ReplaceNodeOptions,
253
267
  ): void,
254
268
  // Types maybe be replaced with other types
255
269
  (
256
270
  target: TypeAnnotationType,
257
- nodeToReplaceWith: DetachedNode<TypeAnnotationType>,
271
+ nodeToReplaceWith: MaybeDetachedNode<TypeAnnotationType>,
258
272
  options?: ReplaceNodeOptions,
259
273
  ): void,
260
274
  // Class members may be replaced with other class members
261
275
  (
262
276
  target: ClassMember,
263
- nodeToReplaceWith: DetachedNode<ClassMember>,
277
+ nodeToReplaceWith: MaybeDetachedNode<ClassMember>,
264
278
  options?: ReplaceNodeOptions,
265
279
  ): void,
266
280
  // Function params amy be replace with other function params
267
281
  (
268
282
  target: FunctionParameter,
269
- nodeToReplaceWith: DetachedNode<FunctionParameter>,
283
+ nodeToReplaceWith: MaybeDetachedNode<FunctionParameter>,
270
284
  options?: ReplaceNodeOptions,
271
285
  ): void,
272
286
  } & TransformReplaceSignatures, // allow like-for-like replacements as well
@@ -277,7 +291,9 @@ type TransformReplaceAPIs = $ReadOnly<{
277
291
  */
278
292
  replaceStatementWithMany: (
279
293
  target: ReplaceStatementWithManyMutation['target'],
280
- nodesToReplaceWith: ReplaceStatementWithManyMutation['nodesToReplaceWith'],
294
+ nodesToReplaceWith: $ReadOnlyArray<
295
+ MaybeDetachedNode<ReplaceStatementWithManyMutationNodes>,
296
+ >,
281
297
  options?: {
282
298
  /**
283
299
  * Moves the comments from the target node to the first node in the array.
@@ -296,6 +312,7 @@ export type TransformContextAdditions = $ReadOnly<{
296
312
  ...TransformCommentAPIs,
297
313
  ...TransformCloneAPIs,
298
314
  ...TransformInsertAPIs,
315
+ ...TransformModifyAPIs,
299
316
  ...TransformRemoveAPIs,
300
317
  ...TransformReplaceAPIs,
301
318
  }>;
@@ -321,14 +338,15 @@ export function getTransformContext(): TransformContextAdditions {
321
338
  return null;
322
339
  }
323
340
 
324
- return shallowCloneNode(node);
341
+ return shallowCloneNode(node, {});
325
342
  }: TransformCloneAPIs['shallowCloneNode']),
326
343
 
327
- // $FlowExpectedError[incompatible-exact]
328
344
  shallowCloneNodeWithOverrides: ((
329
345
  node: ?ESNode,
330
- newProps?: $ReadOnly<{...}>,
331
- ): ?DetachedNode<ESNode> => {
346
+ newProps?: $ReadOnly<{...}> = {},
347
+ ): // $FlowExpectedError[incompatible-cast]
348
+ // $FlowExpectedError[prop-missing]
349
+ ?DetachedNode<ESNode> => {
332
350
  if (node == null) {
333
351
  return null;
334
352
  }
@@ -337,14 +355,20 @@ export function getTransformContext(): TransformContextAdditions {
337
355
  }: TransformCloneAPIs['shallowCloneNodeWithOverrides']),
338
356
 
339
357
  shallowCloneArray: (<T: ESNode>(
340
- nodes: ?$ReadOnlyArray<T>,
358
+ nodes: ?$ReadOnlyArray<?T>,
341
359
  ): // $FlowExpectedError[incompatible-cast]
342
- ?$ReadOnlyArray<DetachedNode<ESNode>> => {
360
+ ?$ReadOnlyArray<DetachedNode<?ESNode>> => {
343
361
  if (nodes == null) {
344
362
  return null;
345
363
  }
346
364
 
347
- return nodes.map(node => shallowCloneNode<T>(node));
365
+ return nodes.map(node => {
366
+ if (node == null) {
367
+ // $FlowExpectedError[incompatible-call]
368
+ return node;
369
+ }
370
+ return shallowCloneNode<T>(node, {});
371
+ });
348
372
  }: TransformCloneAPIs['shallowCloneArray']),
349
373
 
350
374
  deepCloneNode: ((
@@ -355,14 +379,15 @@ export function getTransformContext(): TransformContextAdditions {
355
379
  return null;
356
380
  }
357
381
 
358
- return deepCloneNode(node);
382
+ return deepCloneNode(node, {});
359
383
  }: TransformCloneAPIs['deepCloneNode']),
360
384
 
361
- // $FlowExpectedError[incompatible-exact]
362
385
  deepCloneNodeWithOverrides: ((
363
386
  node: ?ESNode,
364
- newProps?: $ReadOnly<{...}>,
365
- ): ?DetachedNode<ESNode> => {
387
+ newProps?: $ReadOnly<{...}> = {},
388
+ ): // $FlowExpectedError[incompatible-cast]
389
+ // $FlowExpectedError[prop-missing]
390
+ ?DetachedNode<ESNode> => {
366
391
  if (node == null) {
367
392
  return null;
368
393
  }
@@ -444,13 +469,25 @@ export function getTransformContext(): TransformContextAdditions {
444
469
  const insertAPIs: TransformInsertAPIs = {
445
470
  insertAfterStatement: ((target, nodesToInsert): void => {
446
471
  pushMutation(
447
- createInsertStatementMutation('after', target, toArray(nodesToInsert)),
472
+ createInsertStatementMutation(
473
+ 'after',
474
+ target,
475
+ toArray(nodesToInsert).map(n =>
476
+ asDetachedNode(n, {useDeepClone: true}),
477
+ ),
478
+ ),
448
479
  );
449
480
  }: TransformInsertAPIs['insertBeforeStatement']),
450
481
 
451
482
  insertBeforeStatement: ((target, nodesToInsert): void => {
452
483
  pushMutation(
453
- createInsertStatementMutation('before', target, toArray(nodesToInsert)),
484
+ createInsertStatementMutation(
485
+ 'before',
486
+ target,
487
+ toArray(nodesToInsert).map(n =>
488
+ asDetachedNode(n, {useDeepClone: true}),
489
+ ),
490
+ ),
454
491
  );
455
492
  }: TransformInsertAPIs['insertBeforeStatement']),
456
493
  };
@@ -466,11 +503,15 @@ export function getTransformContext(): TransformContextAdditions {
466
503
  const replaceAPIs: TransformReplaceAPIs = {
467
504
  replaceNode: ((
468
505
  target: ESNode,
469
- nodeToReplaceWith: DetachedNode<ESNode>,
506
+ nodeToReplaceWith: MaybeDetachedNode<ESNode>,
470
507
  options?: ReplaceNodeOptions,
471
508
  ): void => {
472
509
  pushMutation(
473
- createReplaceNodeMutation(target, nodeToReplaceWith, options),
510
+ createReplaceNodeMutation(
511
+ target,
512
+ asDetachedNode(nodeToReplaceWith),
513
+ options,
514
+ ),
474
515
  );
475
516
  }: TransformReplaceAPIs['replaceNode']),
476
517
 
@@ -482,12 +523,27 @@ export function getTransformContext(): TransformContextAdditions {
482
523
  pushMutation(
483
524
  createReplaceStatementWithManyMutation(
484
525
  target,
485
- nodesToReplaceWith,
526
+ nodesToReplaceWith.map(n => asDetachedNode(n)),
486
527
  options,
487
528
  ),
488
529
  );
489
530
  }: TransformReplaceAPIs['replaceStatementWithMany']),
490
531
  };
532
+ const modifyAPIs: TransformModifyAPIs = {
533
+ modifyNodeInPlace: ((
534
+ node: ?ESNode,
535
+ newProps?: $ReadOnly<{...}> = {},
536
+ options?: ReplaceNodeOptions,
537
+ ): void => {
538
+ if (node == null) {
539
+ return;
540
+ }
541
+
542
+ const cloned = shallowCloneNode(node, newProps, {preserveLocation: true});
543
+ // $FlowExpectedError[incompatible-call]
544
+ replaceAPIs.replaceNode(node, cloned, options);
545
+ }: TransformModifyAPIs['modifyNodeInPlace']),
546
+ };
491
547
 
492
548
  return {
493
549
  mutations,
@@ -500,6 +556,7 @@ export function getTransformContext(): TransformContextAdditions {
500
556
  ...cloneAPIs,
501
557
  ...commentAPIs,
502
558
  ...insertAPIs,
559
+ ...modifyAPIs,
503
560
  ...removeAPIs,
504
561
  ...replaceAPIs,
505
562
  };
@@ -11,6 +11,8 @@ exports.attachComments = attachComments;
11
11
  exports.cloneComment = cloneComment;
12
12
  exports.cloneCommentWithMarkers = cloneCommentWithMarkers;
13
13
  exports.getCommentsForNode = getCommentsForNode;
14
+ exports.getLeadingCommentsForNode = getLeadingCommentsForNode;
15
+ exports.getTrailingCommentsForNode = getTrailingCommentsForNode;
14
16
  exports.isLeadingComment = isLeadingComment;
15
17
  exports.isTrailingComment = isTrailingComment;
16
18
  exports.moveCommentsToNewNode = moveCommentsToNewNode;
@@ -62,13 +64,21 @@ function setCommentsOnNode(node, comments) {
62
64
  node.comments = comments;
63
65
  }
64
66
 
65
- function addCommentsToNode(node, comments) {
67
+ function addCommentsToNode(node, comments, side = 'trailing') {
66
68
  var _node$comments;
67
69
 
68
- // $FlowExpectedError - this property is secretly added by prettier.
69
- node.comments = (_node$comments = node.comments) != null ? _node$comments : []; // $FlowExpectedError
70
-
71
- node.comments.push(...comments);
70
+ // $FlowExpectedError[prop-missing] - this property is secretly added by prettier.
71
+ // $FlowExpectedError[cannot-write]
72
+ // $FlowExpectedError[incompatible-use]
73
+ node.comments = (_node$comments = node.comments) != null ? _node$comments : [];
74
+
75
+ if (side === 'leading') {
76
+ // $FlowExpectedError[incompatible-cast]
77
+ node.comments.unshift(...comments);
78
+ } else {
79
+ // $FlowExpectedError[incompatible-cast]
80
+ node.comments.push(...comments);
81
+ }
72
82
  }
73
83
 
74
84
  function getCommentsForNode(node) {
@@ -88,6 +98,14 @@ function isTrailingComment(comment) {
88
98
  return comment.trailing === true;
89
99
  }
90
100
 
101
+ function getLeadingCommentsForNode(node) {
102
+ return getCommentsForNode(node).filter(isLeadingComment);
103
+ }
104
+
105
+ function getTrailingCommentsForNode(node) {
106
+ return getCommentsForNode(node).filter(isTrailingComment);
107
+ }
108
+
91
109
  function addComment(node, comment, placement) {
92
110
  switch (placement) {
93
111
  case CommentPlacement.LEADING_OWN_LINE:
@@ -65,11 +65,19 @@ export function setCommentsOnNode(
65
65
  export function addCommentsToNode(
66
66
  node: ESNode | DetachedNode<ESNode>,
67
67
  comments: $ReadOnlyArray<Comment>,
68
+ side?: 'leading' | 'trailing' = 'trailing',
68
69
  ): void {
69
- // $FlowExpectedError - this property is secretly added by prettier.
70
+ // $FlowExpectedError[prop-missing] - this property is secretly added by prettier.
71
+ // $FlowExpectedError[cannot-write]
72
+ // $FlowExpectedError[incompatible-use]
70
73
  node.comments = node.comments ?? [];
71
- // $FlowExpectedError
72
- (node.comments: Array<Comment>).push(...comments);
74
+ if (side === 'leading') {
75
+ // $FlowExpectedError[incompatible-cast]
76
+ (node.comments: Array<Comment>).unshift(...comments);
77
+ } else {
78
+ // $FlowExpectedError[incompatible-cast]
79
+ (node.comments: Array<Comment>).push(...comments);
80
+ }
73
81
  }
74
82
 
75
83
  export function getCommentsForNode(
@@ -88,6 +96,18 @@ export function isTrailingComment(comment: Comment): boolean {
88
96
  return comment.trailing === true;
89
97
  }
90
98
 
99
+ export function getLeadingCommentsForNode(
100
+ node: ESNode | DetachedNode<ESNode>,
101
+ ): $ReadOnlyArray<Comment> {
102
+ return getCommentsForNode(node).filter(isLeadingComment);
103
+ }
104
+
105
+ export function getTrailingCommentsForNode(
106
+ node: ESNode | DetachedNode<ESNode>,
107
+ ): $ReadOnlyArray<Comment> {
108
+ return getCommentsForNode(node).filter(isTrailingComment);
109
+ }
110
+
91
111
  export function addComment(
92
112
  node: ESNode | DetachedNode<ESNode>,
93
113
  comment: Comment,
@@ -122,6 +122,21 @@ function getTransformedAST(code, visitors) {
122
122
  if (mutationRoot) {
123
123
  (0, _detachedNode.updateAllParentPointers)(mutationRoot);
124
124
  }
125
+ } // if the very first node in the program is replaced, it will take the docblock with it
126
+ // this is bad as it means we'll lose `@format`, ``, licence, etc.
127
+ // so this hack just makes sure that we keep the docblock
128
+ // note that we do this **BEFORE** the comment mutations in case someone intentionally
129
+ // wants to remove the docblock comment for some weird reason
130
+
131
+
132
+ if (ast.docblock != null && ast.body.length > 0) {
133
+ const firstNode = ast.body[0];
134
+ const docblockComment = ast.docblock.comment;
135
+ const leadingComments = (0, _comments.getLeadingCommentsForNode)(firstNode);
136
+
137
+ if (!leadingComments.includes(docblockComment)) {
138
+ (0, _comments.addCommentsToNode)(firstNode, [docblockComment], 'leading');
139
+ }
125
140
  } // remove the comments
126
141
  // this is done at the end because it requires a complete traversal of the AST
127
142
  // so that we can find relevant node's attachment array
@@ -19,7 +19,11 @@ import {updateAllParentPointers} from '../detachedNode';
19
19
  import {traverseWithContext} from '../traverse/traverse';
20
20
  import {MutationContext} from './MutationContext';
21
21
  import {getTransformContext} from './TransformContext';
22
- import {attachComments} from './comments/comments';
22
+ import {
23
+ addCommentsToNode,
24
+ attachComments,
25
+ getLeadingCommentsForNode,
26
+ } from './comments/comments';
23
27
  import {performAddCommentsMutation} from './mutations/AddComments';
24
28
  import {performCloneCommentsToMutation} from './mutations/CloneCommentsTo';
25
29
  import {performInsertStatementMutation} from './mutations/InsertStatement';
@@ -120,6 +124,20 @@ export function getTransformedAST(
120
124
  }
121
125
  }
122
126
 
127
+ // if the very first node in the program is replaced, it will take the docblock with it
128
+ // this is bad as it means we'll lose `@format`, `@flow`, licence, etc.
129
+ // so this hack just makes sure that we keep the docblock
130
+ // note that we do this **BEFORE** the comment mutations in case someone intentionally
131
+ // wants to remove the docblock comment for some weird reason
132
+ if (ast.docblock != null && ast.body.length > 0) {
133
+ const firstNode = ast.body[0];
134
+ const docblockComment = ast.docblock.comment;
135
+ const leadingComments = getLeadingCommentsForNode(firstNode);
136
+ if (!leadingComments.includes(docblockComment)) {
137
+ addCommentsToNode(firstNode, [docblockComment], 'leading');
138
+ }
139
+ }
140
+
123
141
  // remove the comments
124
142
  // this is done at the end because it requires a complete traversal of the AST
125
143
  // so that we can find relevant node's attachment array
@@ -86,5 +86,6 @@ function performInsertStatementMutation(mutationContext, mutation) {
86
86
  parent: insertionParent.parent
87
87
  });
88
88
  insertionParent.parent[insertionParent.key] = blockStatement;
89
+ statementToWrap.parent = blockStatement;
89
90
  return insertionParent.parent;
90
91
  }
@@ -113,6 +113,7 @@ export function performInsertStatementMutation(
113
113
 
114
114
  (insertionParent.parent: interface {[string]: mixed})[insertionParent.key] =
115
115
  blockStatement;
116
+ statementToWrap.parent = blockStatement;
116
117
 
117
118
  return insertionParent.parent;
118
119
  }
@@ -12,6 +12,8 @@ var _comments = require("../comments/comments");
12
12
 
13
13
  var _Errors = require("../Errors");
14
14
 
15
+ var _detachedNode = require("../../detachedNode");
16
+
15
17
  var _getVisitorKeys = require("../../getVisitorKeys");
16
18
 
17
19
  /**
@@ -71,7 +73,10 @@ function getParentKey(target) {
71
73
  }
72
74
  } else if (Array.isArray(parent[key])) {
73
75
  for (let i = 0; i < parent[key].length; i += 1) {
74
- if (parent[key][i] === target) {
76
+ const current = parent[key][i];
77
+ const originalNode = (0, _detachedNode.getOriginalNode)(current);
78
+
79
+ if (current === target || originalNode === target) {
75
80
  return {
76
81
  type: 'array',
77
82
  parent,
@@ -84,5 +89,5 @@ function getParentKey(target) {
84
89
  } // this shouldn't happen ever
85
90
 
86
91
 
87
- throw new _Errors.InvalidReplacementError(`Expected to find the ${target.type} as a direct child of the ${target.type}.`);
92
+ throw new _Errors.InvalidReplacementError(`Expected to find the ${target.type} as a direct child of the ${parent.type}.`);
88
93
  }
@@ -15,6 +15,7 @@ import type {DetachedNode} from '../../detachedNode';
15
15
  import {replaceInArray} from './utils/arrayUtils';
16
16
  import {moveCommentsToNewNode} from '../comments/comments';
17
17
  import {InvalidReplacementError} from '../Errors';
18
+ import {getOriginalNode} from '../../detachedNode';
18
19
  import {getVisitorKeys, isNode} from '../../getVisitorKeys';
19
20
 
20
21
  export type ReplaceNodeMutation = $ReadOnly<{
@@ -99,7 +100,9 @@ function getParentKey(target: ESNode): $ReadOnly<
99
100
  }
100
101
  } else if (Array.isArray(parent[key])) {
101
102
  for (let i = 0; i < parent[key].length; i += 1) {
102
- if (parent[key][i] === target) {
103
+ const current = parent[key][i];
104
+ const originalNode = getOriginalNode(current);
105
+ if (current === target || originalNode === target) {
103
106
  return {type: 'array', parent, key, targetIndex: i};
104
107
  }
105
108
  }
@@ -108,6 +111,6 @@ function getParentKey(target: ESNode): $ReadOnly<
108
111
 
109
112
  // this shouldn't happen ever
110
113
  throw new InvalidReplacementError(
111
- `Expected to find the ${target.type} as a direct child of the ${target.type}.`,
114
+ `Expected to find the ${target.type} as a direct child of the ${parent.type}.`,
112
115
  );
113
116
  }
@@ -19,11 +19,14 @@ import {moveCommentsToNewNode} from '../comments/comments';
19
19
  import {InvalidReplacementError} from '../Errors';
20
20
  import * as t from '../../generated/node-types';
21
21
 
22
+ export type ReplaceStatementWithManyMutationNodes =
23
+ | ModuleDeclaration
24
+ | Statement;
22
25
  export type ReplaceStatementWithManyMutation = $ReadOnly<{
23
26
  type: 'replaceStatementWithMany',
24
- target: ModuleDeclaration | Statement,
27
+ target: ReplaceStatementWithManyMutationNodes,
25
28
  nodesToReplaceWith: $ReadOnlyArray<
26
- DetachedNode<ModuleDeclaration | Statement>,
29
+ DetachedNode<ReplaceStatementWithManyMutationNodes>,
27
30
  >,
28
31
  keepComments: boolean,
29
32
  }>;
@@ -34,7 +34,7 @@ type ParsedSelector = $ReadOnly<{
34
34
 
35
35
  const ESQUERY_OPTIONS: ESQueryOptions = Object.freeze({
36
36
  visitorKeys: VisitorKeys,
37
- fallback: node => {
37
+ fallback: (node: ESNode) => {
38
38
  throw new Error(`No visitor keys found for node type "${node.type}".`);
39
39
  },
40
40
  });
@@ -140,7 +140,7 @@ export function traverseWithContext<T = TraversalContextBase>(
140
140
  scopeManager.getDeclaredVariables(node),
141
141
 
142
142
  getBinding: (name: string) => {
143
- let currentScope = getScope();
143
+ let currentScope: null | Scope = getScope();
144
144
 
145
145
  while (currentScope != null) {
146
146
  for (const variable of currentScope.variables) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hermes-transform",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Tools built on top of Hermes-ESTree to enable codebase transformation",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",
@@ -12,13 +12,17 @@
12
12
  "@babel/code-frame": "^7.16.0",
13
13
  "esquery": "^1.4.0",
14
14
  "flow-enums-runtime": "^0.0.6",
15
- "hermes-eslint": "0.8.0",
16
- "hermes-estree": "0.8.0"
15
+ "hermes-eslint": "0.9.0",
16
+ "hermes-estree": "0.9.0"
17
17
  },
18
18
  "peerDependencies": {
19
19
  "prettier": "^2.4.1"
20
20
  },
21
21
  "files": [
22
- "dist"
22
+ "dist",
23
+ "LICENCE",
24
+ "ESLINT_LICENCE",
25
+ "PRETTIER_LICENCE",
26
+ "README.md"
23
27
  ]
24
28
  }