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.
- package/LICENSE +21 -0
- package/README.md +8 -0
- package/dist/detachedNode.js +128 -0
- package/dist/detachedNode.js.flow +113 -0
- package/dist/generated/TransformCloneSignatures.js.flow +19 -0
- package/dist/generated/TransformReplaceSignatures.js.flow +943 -0
- package/dist/generated/node-types.js +2071 -0
- package/dist/generated/node-types.js.flow +3149 -0
- package/dist/generated/special-case-node-types.js +178 -0
- package/dist/generated/special-case-node-types.js.flow +248 -0
- package/dist/getVisitorKeys.js +35 -0
- package/dist/getVisitorKeys.js.flow +31 -0
- package/dist/index.js +41 -0
- package/dist/index.js.flow +15 -0
- package/dist/transform/Errors.js +151 -0
- package/dist/transform/Errors.js.flow +17 -0
- package/dist/transform/MutationContext.js +94 -0
- package/dist/transform/MutationContext.js.flow +80 -0
- package/dist/transform/TransformContext.js +136 -0
- package/dist/transform/TransformContext.js.flow +378 -0
- package/dist/transform/comments/comments.js +140 -0
- package/dist/transform/comments/comments.js.flow +145 -0
- package/dist/transform/comments/prettier/README.md +6 -0
- package/dist/transform/comments/prettier/common/util.js +365 -0
- package/dist/transform/comments/prettier/common/util.js.flow +349 -0
- package/dist/transform/comments/prettier/language-js/comments.js +777 -0
- package/dist/transform/comments/prettier/language-js/comments.js.flow +950 -0
- package/dist/transform/comments/prettier/language-js/loc.js +41 -0
- package/dist/transform/comments/prettier/language-js/loc.js.flow +41 -0
- package/dist/transform/comments/prettier/language-js/printer-estree.js +31 -0
- package/dist/transform/comments/prettier/language-js/printer-estree.js.flow +37 -0
- package/dist/transform/comments/prettier/language-js/utils.js +131 -0
- package/dist/transform/comments/prettier/language-js/utils.js.flow +135 -0
- package/dist/transform/comments/prettier/main/comments.js +513 -0
- package/dist/transform/comments/prettier/main/comments.js.flow +436 -0
- package/dist/transform/comments/prettier/utils/get-last.js +15 -0
- package/dist/transform/comments/prettier/utils/get-last.js.flow +14 -0
- package/dist/transform/getTransformedAST.js +159 -0
- package/dist/transform/getTransformedAST.js.flow +128 -0
- package/dist/transform/mutations/AddLeadingComments.js +47 -0
- package/dist/transform/mutations/AddLeadingComments.js.flow +49 -0
- package/dist/transform/mutations/AddTrailingComments.js +47 -0
- package/dist/transform/mutations/AddTrailingComments.js.flow +49 -0
- package/dist/transform/mutations/CloneCommentsTo.js +46 -0
- package/dist/transform/mutations/CloneCommentsTo.js.flow +51 -0
- package/dist/transform/mutations/InsertStatement.js +92 -0
- package/dist/transform/mutations/InsertStatement.js.flow +113 -0
- package/dist/transform/mutations/RemoveComment.js +96 -0
- package/dist/transform/mutations/RemoveComment.js.flow +80 -0
- package/dist/transform/mutations/RemoveStatement.js +61 -0
- package/dist/transform/mutations/RemoveStatement.js.flow +68 -0
- package/dist/transform/mutations/ReplaceNode.js +96 -0
- package/dist/transform/mutations/ReplaceNode.js.flow +113 -0
- package/dist/transform/mutations/ReplaceStatementWithMany.js +81 -0
- package/dist/transform/mutations/ReplaceStatementWithMany.js.flow +102 -0
- package/dist/transform/mutations/utils/arrayUtils.js +41 -0
- package/dist/transform/mutations/utils/arrayUtils.js.flow +35 -0
- package/dist/transform/mutations/utils/getStatementParent.js +147 -0
- package/dist/transform/mutations/utils/getStatementParent.js.flow +143 -0
- package/dist/transform/mutations/utils/isValidModuleDeclarationParent.js +53 -0
- package/dist/transform/mutations/utils/isValidModuleDeclarationParent.js.flow +50 -0
- package/dist/transform/transform.js +69 -0
- package/dist/transform/transform.js.flow +60 -0
- package/dist/traverse/NodeEventGenerator.js +427 -0
- package/dist/traverse/NodeEventGenerator.js.flow +406 -0
- package/dist/traverse/SafeEmitter.js +70 -0
- package/dist/traverse/SafeEmitter.js.flow +46 -0
- package/dist/traverse/SimpleTraverser.js +149 -0
- package/dist/traverse/SimpleTraverser.js.flow +109 -0
- package/dist/traverse/esquery.js +37 -0
- package/dist/traverse/esquery.js.flow +173 -0
- package/dist/traverse/traverse.js +139 -0
- package/dist/traverse/traverse.js.flow +149 -0
- 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
|
+
}
|