hermes-transform 0.28.0 → 0.29.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/dist/detachedNode.js +1 -0
- package/dist/detachedNode.js.flow +1 -0
- package/dist/generated/node-types.js +1 -12
- package/dist/generated/node-types.js.flow +2 -19
- package/dist/generated/special-case-node-types/misc.js +11 -0
- package/dist/generated/special-case-node-types/misc.js.flow +18 -0
- package/dist/src/detachedNode.js +178 -0
- package/dist/src/generated/node-types.js +2212 -0
- package/dist/src/generated/special-case-node-types/Comment.js +36 -0
- package/dist/src/generated/special-case-node-types/DeclareExportDeclaration.js +58 -0
- package/dist/src/generated/special-case-node-types/DeclareHook.js +33 -0
- package/dist/src/generated/special-case-node-types/ExportNamedDeclaration.js +44 -0
- package/dist/src/generated/special-case-node-types/Literal.js +97 -0
- package/dist/src/generated/special-case-node-types/ObjectTypeProperty.js +74 -0
- package/dist/src/generated/special-case-node-types/Property.js +136 -0
- package/dist/src/generated/special-case-node-types/misc.js +158 -0
- package/dist/src/generated/special-case-node-types.js +69 -0
- package/dist/src/index.js +53 -0
- package/dist/src/transform/Errors.js +43 -0
- package/dist/src/transform/MutationContext.js +81 -0
- package/dist/src/transform/TransformContext.js +213 -0
- package/dist/src/transform/comments/comments.js +308 -0
- package/dist/src/transform/comments/prettier/common/util.js +364 -0
- package/dist/src/transform/comments/prettier/language-js/comments.js +788 -0
- package/dist/src/transform/comments/prettier/language-js/loc.js +42 -0
- package/dist/src/transform/comments/prettier/language-js/printer-estree.js +32 -0
- package/dist/src/transform/comments/prettier/language-js/utils.js +119 -0
- package/dist/src/transform/comments/prettier/main/comments.js +440 -0
- package/dist/src/transform/comments/prettier/utils/get-last.js +13 -0
- package/dist/src/transform/mutations/AddComments.js +43 -0
- package/dist/src/transform/mutations/CloneCommentsTo.js +31 -0
- package/dist/src/transform/mutations/InsertStatement.js +91 -0
- package/dist/src/transform/mutations/ModifyNodeInPlace.js +59 -0
- package/dist/src/transform/mutations/RemoveComment.js +78 -0
- package/dist/src/transform/mutations/RemoveNode.js +205 -0
- package/dist/src/transform/mutations/RemoveStatement.js +59 -0
- package/dist/src/transform/mutations/ReplaceNode.js +92 -0
- package/dist/src/transform/mutations/ReplaceStatementWithMany.js +79 -0
- package/dist/src/transform/mutations/utils/getStatementParent.js +143 -0
- package/dist/src/transform/mutations/utils/isValidModuleDeclarationParent.js +43 -0
- package/dist/src/transform/parse.js +56 -0
- package/dist/src/transform/print.js +134 -0
- package/dist/src/transform/transform.js +36 -0
- package/dist/src/transform/transformAST.js +134 -0
- package/dist/src/traverse/NodeEventGenerator.js +353 -0
- package/dist/src/traverse/SafeEmitter.js +52 -0
- package/dist/src/traverse/esquery.js +37 -0
- package/dist/src/traverse/traverse.js +150 -0
- package/dist/transform/comments/prettier/language-js/comments.js +29 -1
- package/dist/transform/mutations/utils/getStatementParent.js.flow +7 -5
- package/package.json +5 -5
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and 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
|
+
const {
|
|
12
|
+
isNonEmptyArray
|
|
13
|
+
} = require('../common/util.js');
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {import("./types/estree").Node} Node
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
function locStart(node, opts) {
|
|
20
|
+
const {
|
|
21
|
+
ignoreDecorators
|
|
22
|
+
} = opts || {}; // Handle nodes with decorators. They should start at the first decorator
|
|
23
|
+
|
|
24
|
+
if (!ignoreDecorators) {
|
|
25
|
+
const decorators = node.declaration && node.declaration.decorators || node.decorators;
|
|
26
|
+
|
|
27
|
+
if (isNonEmptyArray(decorators)) {
|
|
28
|
+
return locStart(decorators[0]);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return node.range ? node.range[0] : node.start;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function locEnd(node) {
|
|
36
|
+
return node.range ? node.range[1] : node.end;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
locStart,
|
|
41
|
+
locEnd
|
|
42
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and 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
|
+
const handleComments = require('./comments.js');
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
isBlockComment,
|
|
15
|
+
isLineComment
|
|
16
|
+
} = require('./utils.js');
|
|
17
|
+
|
|
18
|
+
function canAttachComment(node) {
|
|
19
|
+
return node.type && !isBlockComment(node) && !isLineComment(node) && node.type !== 'EmptyStatement' && node.type !== 'TemplateElement' && node.type !== 'Import' && // `babel-ts` don't have similar node for `class Foo { bar() /* bat */; }`
|
|
20
|
+
node.type !== 'TSEmptyBodyFunctionExpression';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = {
|
|
24
|
+
canAttachComment,
|
|
25
|
+
handleComments: {
|
|
26
|
+
avoidAstMutation: true,
|
|
27
|
+
ownLine: handleComments.handleOwnLineComment,
|
|
28
|
+
endOfLine: handleComments.handleEndOfLineComment,
|
|
29
|
+
remaining: handleComments.handleRemainingComment
|
|
30
|
+
},
|
|
31
|
+
getCommentChildNodes: handleComments.getCommentChildNodes
|
|
32
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and 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
|
+
* @param {Comment} comment
|
|
12
|
+
* @returns {boolean}
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
function isBlockComment(comment) {
|
|
16
|
+
return comment.type === 'Block' || comment.type === 'CommentBlock' || // `meriyah`
|
|
17
|
+
comment.type === 'MultiLine';
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* @param {Comment} comment
|
|
21
|
+
* @returns {boolean}
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
function isLineComment(comment) {
|
|
26
|
+
return comment.type === 'Line' || comment.type === 'CommentLine' || // `meriyah` has `SingleLine`, `HashbangComment`, `HTMLOpen`, and `HTMLClose`
|
|
27
|
+
comment.type === 'SingleLine' || comment.type === 'HashbangComment' || comment.type === 'HTMLOpen' || comment.type === 'HTMLClose';
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* @param {Node} node
|
|
31
|
+
* @returns {boolean}
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
function isCallExpression(node) {
|
|
36
|
+
return node && (node.type === 'CallExpression' || node.type === 'OptionalCallExpression');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* @param {Node} node
|
|
40
|
+
* @returns {boolean}
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
function isMemberExpression(node) {
|
|
45
|
+
return node && (node.type === 'MemberExpression' || node.type === 'OptionalMemberExpression');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const functionParametersCache = new WeakMap();
|
|
49
|
+
|
|
50
|
+
function getFunctionParameters(node) {
|
|
51
|
+
if (functionParametersCache.has(node)) {
|
|
52
|
+
return functionParametersCache.get(node);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const parameters = [];
|
|
56
|
+
|
|
57
|
+
if (node.this) {
|
|
58
|
+
parameters.push(node.this);
|
|
59
|
+
} // `params` vs `parameters` - see https://github.com/babel/babel/issues/9231
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if (Array.isArray(node.parameters)) {
|
|
63
|
+
parameters.push(...node.parameters);
|
|
64
|
+
} else if (Array.isArray(node.params)) {
|
|
65
|
+
parameters.push(...node.params);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (node.rest) {
|
|
69
|
+
parameters.push(node.rest);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
functionParametersCache.set(node, parameters);
|
|
73
|
+
return parameters;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const callArgumentsCache = new WeakMap();
|
|
77
|
+
|
|
78
|
+
function getCallArguments(node) {
|
|
79
|
+
if (callArgumentsCache.has(node)) {
|
|
80
|
+
return callArgumentsCache.get(node);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let args = node.arguments;
|
|
84
|
+
|
|
85
|
+
if (node.type === 'ImportExpression') {
|
|
86
|
+
args = [node.source];
|
|
87
|
+
|
|
88
|
+
if (node.attributes) {
|
|
89
|
+
args.push(node.attributes);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
callArgumentsCache.set(node, args);
|
|
94
|
+
return args;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function isPrettierIgnoreComment(comment) {
|
|
98
|
+
return comment.value.trim() === 'prettier-ignore' && !comment.unignore;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function isCallLikeExpression(node) {
|
|
102
|
+
return isCallExpression(node) || node.type === 'NewExpression' || node.type === 'ImportExpression';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isObjectProperty(node) {
|
|
106
|
+
return node && (node.type === 'ObjectProperty' || node.type === 'Property' && !node.method && node.kind === 'init');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = {
|
|
110
|
+
getFunctionParameters,
|
|
111
|
+
getCallArguments,
|
|
112
|
+
isBlockComment,
|
|
113
|
+
isCallLikeExpression,
|
|
114
|
+
isLineComment,
|
|
115
|
+
isPrettierIgnoreComment,
|
|
116
|
+
isCallExpression,
|
|
117
|
+
isMemberExpression,
|
|
118
|
+
isObjectProperty
|
|
119
|
+
};
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and 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
|
+
const assert = require('assert');
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
hasNewline,
|
|
15
|
+
addLeadingComment,
|
|
16
|
+
addDanglingComment,
|
|
17
|
+
addTrailingComment
|
|
18
|
+
} = require('../common/util.js');
|
|
19
|
+
|
|
20
|
+
const childNodesCache = new WeakMap();
|
|
21
|
+
|
|
22
|
+
function getSortedChildNodes(node, options, resultArray) {
|
|
23
|
+
if (!node) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const {
|
|
28
|
+
printer,
|
|
29
|
+
locStart,
|
|
30
|
+
locEnd
|
|
31
|
+
} = options;
|
|
32
|
+
|
|
33
|
+
if (resultArray) {
|
|
34
|
+
if (printer.canAttachComment && printer.canAttachComment(node)) {
|
|
35
|
+
// This reverse insertion sort almost always takes constant
|
|
36
|
+
// time because we almost always (maybe always?) append the
|
|
37
|
+
// nodes in order anyway.
|
|
38
|
+
let i;
|
|
39
|
+
|
|
40
|
+
for (i = resultArray.length - 1; i >= 0; --i) {
|
|
41
|
+
if (locStart(resultArray[i]) <= locStart(node) && locEnd(resultArray[i]) <= locEnd(node)) {
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
resultArray.splice(i + 1, 0, node);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
} else if (childNodesCache.has(node)) {
|
|
50
|
+
return childNodesCache.get(node);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const childNodes = printer.getCommentChildNodes && printer.getCommentChildNodes(node, options) || typeof node === 'object' && Object.entries(node).filter(([key]) => key !== 'enclosingNode' && key !== 'precedingNode' && key !== 'followingNode' && key !== 'tokens' && key !== 'comments' && key !== 'parent').map(([, value]) => value);
|
|
54
|
+
|
|
55
|
+
if (!childNodes) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!resultArray) {
|
|
60
|
+
resultArray = [];
|
|
61
|
+
childNodesCache.set(node, resultArray);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for (const childNode of childNodes) {
|
|
65
|
+
getSortedChildNodes(childNode, options, resultArray);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return resultArray;
|
|
69
|
+
} // As efficiently as possible, decorate the comment object with
|
|
70
|
+
// .precedingNode, .enclosingNode, and/or .followingNode properties, at
|
|
71
|
+
// least one of which is guaranteed to be defined.
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
function decorateComment(node, comment, options, enclosingNode) {
|
|
75
|
+
const {
|
|
76
|
+
locStart,
|
|
77
|
+
locEnd
|
|
78
|
+
} = options;
|
|
79
|
+
const commentStart = locStart(comment);
|
|
80
|
+
const commentEnd = locEnd(comment);
|
|
81
|
+
const childNodes = getSortedChildNodes(node, options);
|
|
82
|
+
let precedingNode;
|
|
83
|
+
let followingNode; // Time to dust off the old binary search robes and wizard hat.
|
|
84
|
+
|
|
85
|
+
let left = 0;
|
|
86
|
+
let right = childNodes.length;
|
|
87
|
+
|
|
88
|
+
while (left < right) {
|
|
89
|
+
const middle = left + right >> 1;
|
|
90
|
+
const child = childNodes[middle];
|
|
91
|
+
const start = locStart(child);
|
|
92
|
+
const end = locEnd(child); // The comment is completely contained by this child node.
|
|
93
|
+
|
|
94
|
+
if (start <= commentStart && commentEnd <= end) {
|
|
95
|
+
// Abandon the binary search at this level.
|
|
96
|
+
return decorateComment(child, comment, options, child);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (end <= commentStart) {
|
|
100
|
+
// This child node falls completely before the comment.
|
|
101
|
+
// Because we will never consider this node or any nodes
|
|
102
|
+
// before it again, this node must be the closest preceding
|
|
103
|
+
// node we have encountered so far.
|
|
104
|
+
precedingNode = child;
|
|
105
|
+
left = middle + 1;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (commentEnd <= start) {
|
|
110
|
+
// This child node falls completely after the comment.
|
|
111
|
+
// Because we will never consider this node or any nodes after
|
|
112
|
+
// it again, this node must be the closest following node we
|
|
113
|
+
// have encountered so far.
|
|
114
|
+
followingNode = child;
|
|
115
|
+
right = middle;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
/* istanbul ignore next */
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
throw new Error('Comment location overlaps with node location');
|
|
122
|
+
} // We don't want comments inside of different expressions inside of the same
|
|
123
|
+
// template literal to move to another expression.
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
if (enclosingNode && enclosingNode.type === 'TemplateLiteral') {
|
|
127
|
+
const {
|
|
128
|
+
quasis
|
|
129
|
+
} = enclosingNode;
|
|
130
|
+
const commentIndex = findExpressionIndexForComment(quasis, comment, options);
|
|
131
|
+
|
|
132
|
+
if (precedingNode && findExpressionIndexForComment(quasis, precedingNode, options) !== commentIndex) {
|
|
133
|
+
precedingNode = null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (followingNode && findExpressionIndexForComment(quasis, followingNode, options) !== commentIndex) {
|
|
137
|
+
followingNode = null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
enclosingNode,
|
|
143
|
+
precedingNode,
|
|
144
|
+
followingNode
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const returnFalse = () => false;
|
|
149
|
+
|
|
150
|
+
function attach(comments, ast, text, options) {
|
|
151
|
+
if (!Array.isArray(comments)) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const tiesToBreak = [];
|
|
156
|
+
const {
|
|
157
|
+
locStart,
|
|
158
|
+
locEnd,
|
|
159
|
+
printer: {
|
|
160
|
+
handleComments = {}
|
|
161
|
+
}
|
|
162
|
+
} = options; // TODO: Make this as default behavior
|
|
163
|
+
|
|
164
|
+
const {
|
|
165
|
+
avoidAstMutation,
|
|
166
|
+
ownLine: handleOwnLineComment = returnFalse,
|
|
167
|
+
endOfLine: handleEndOfLineComment = returnFalse,
|
|
168
|
+
remaining: handleRemainingComment = returnFalse
|
|
169
|
+
} = handleComments;
|
|
170
|
+
const decoratedComments = comments.map((comment, index) => ({ ...decorateComment(ast, comment, options),
|
|
171
|
+
comment,
|
|
172
|
+
text,
|
|
173
|
+
options,
|
|
174
|
+
ast,
|
|
175
|
+
isLastComment: comments.length - 1 === index
|
|
176
|
+
}));
|
|
177
|
+
|
|
178
|
+
for (const [index, context] of decoratedComments.entries()) {
|
|
179
|
+
const {
|
|
180
|
+
comment,
|
|
181
|
+
precedingNode,
|
|
182
|
+
enclosingNode,
|
|
183
|
+
followingNode,
|
|
184
|
+
text,
|
|
185
|
+
options,
|
|
186
|
+
ast,
|
|
187
|
+
isLastComment
|
|
188
|
+
} = context;
|
|
189
|
+
|
|
190
|
+
if (options.parser === 'json' || options.parser === 'json5' || options.parser === '__js_expression' || options.parser === '__vue_expression') {
|
|
191
|
+
if (locStart(comment) - locStart(ast) <= 0) {
|
|
192
|
+
addLeadingComment(ast, comment);
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (locEnd(comment) - locEnd(ast) >= 0) {
|
|
197
|
+
addTrailingComment(ast, comment);
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
let args;
|
|
203
|
+
|
|
204
|
+
if (avoidAstMutation) {
|
|
205
|
+
args = [context];
|
|
206
|
+
} else {
|
|
207
|
+
comment.enclosingNode = enclosingNode;
|
|
208
|
+
comment.precedingNode = precedingNode;
|
|
209
|
+
comment.followingNode = followingNode;
|
|
210
|
+
args = [comment, text, options, ast, isLastComment];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (isOwnLineComment(text, options, decoratedComments, index)) {
|
|
214
|
+
comment.placement = 'ownLine'; // If a comment exists on its own line, prefer a leading comment.
|
|
215
|
+
// We also need to check if it's the first line of the file.
|
|
216
|
+
|
|
217
|
+
if (handleOwnLineComment(...args)) {// We're good
|
|
218
|
+
} else if (followingNode) {
|
|
219
|
+
// Always a leading comment.
|
|
220
|
+
addLeadingComment(followingNode, comment);
|
|
221
|
+
} else if (precedingNode) {
|
|
222
|
+
addTrailingComment(precedingNode, comment);
|
|
223
|
+
} else if (enclosingNode) {
|
|
224
|
+
addDanglingComment(enclosingNode, comment);
|
|
225
|
+
} else {
|
|
226
|
+
// There are no nodes, let's attach it to the root of the ast
|
|
227
|
+
|
|
228
|
+
/* istanbul ignore next */
|
|
229
|
+
addDanglingComment(ast, comment);
|
|
230
|
+
}
|
|
231
|
+
} else if (isEndOfLineComment(text, options, decoratedComments, index)) {
|
|
232
|
+
comment.placement = 'endOfLine';
|
|
233
|
+
|
|
234
|
+
if (handleEndOfLineComment(...args)) {// We're good
|
|
235
|
+
} else if (precedingNode) {
|
|
236
|
+
// There is content before this comment on the same line, but
|
|
237
|
+
// none after it, so prefer a trailing comment of the previous node.
|
|
238
|
+
addTrailingComment(precedingNode, comment);
|
|
239
|
+
} else if (followingNode) {
|
|
240
|
+
addLeadingComment(followingNode, comment);
|
|
241
|
+
} else if (enclosingNode) {
|
|
242
|
+
addDanglingComment(enclosingNode, comment);
|
|
243
|
+
} else {
|
|
244
|
+
// There are no nodes, let's attach it to the root of the ast
|
|
245
|
+
|
|
246
|
+
/* istanbul ignore next */
|
|
247
|
+
addDanglingComment(ast, comment);
|
|
248
|
+
}
|
|
249
|
+
} else {
|
|
250
|
+
comment.placement = 'remaining';
|
|
251
|
+
|
|
252
|
+
if (handleRemainingComment(...args)) {// We're good
|
|
253
|
+
} else if (precedingNode && followingNode) {
|
|
254
|
+
// Otherwise, text exists both before and after the comment on
|
|
255
|
+
// the same line. If there is both a preceding and following
|
|
256
|
+
// node, use a tie-breaking algorithm to determine if it should
|
|
257
|
+
// be attached to the next or previous node. In the last case,
|
|
258
|
+
// simply attach the right node;
|
|
259
|
+
const tieCount = tiesToBreak.length;
|
|
260
|
+
|
|
261
|
+
if (tieCount > 0) {
|
|
262
|
+
const lastTie = tiesToBreak[tieCount - 1];
|
|
263
|
+
|
|
264
|
+
if (lastTie.followingNode !== followingNode) {
|
|
265
|
+
breakTies(tiesToBreak, text, options);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
tiesToBreak.push(context);
|
|
270
|
+
} else if (precedingNode) {
|
|
271
|
+
addTrailingComment(precedingNode, comment);
|
|
272
|
+
} else if (followingNode) {
|
|
273
|
+
addLeadingComment(followingNode, comment);
|
|
274
|
+
} else if (enclosingNode) {
|
|
275
|
+
addDanglingComment(enclosingNode, comment);
|
|
276
|
+
} else {
|
|
277
|
+
// There are no nodes, let's attach it to the root of the ast
|
|
278
|
+
|
|
279
|
+
/* istanbul ignore next */
|
|
280
|
+
addDanglingComment(ast, comment);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
breakTies(tiesToBreak, text, options);
|
|
286
|
+
|
|
287
|
+
if (!avoidAstMutation) {
|
|
288
|
+
for (const comment of comments) {
|
|
289
|
+
// These node references were useful for breaking ties, but we
|
|
290
|
+
// don't need them anymore, and they create cycles in the AST that
|
|
291
|
+
// may lead to infinite recursion if we don't delete them here.
|
|
292
|
+
delete comment.precedingNode;
|
|
293
|
+
delete comment.enclosingNode;
|
|
294
|
+
delete comment.followingNode;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const isAllEmptyAndNoLineBreak = text => !/[\S\n\u2028\u2029]/.test(text);
|
|
300
|
+
|
|
301
|
+
function isOwnLineComment(text, options, decoratedComments, commentIndex) {
|
|
302
|
+
const {
|
|
303
|
+
comment,
|
|
304
|
+
precedingNode
|
|
305
|
+
} = decoratedComments[commentIndex];
|
|
306
|
+
const {
|
|
307
|
+
locStart,
|
|
308
|
+
locEnd
|
|
309
|
+
} = options;
|
|
310
|
+
let start = locStart(comment);
|
|
311
|
+
|
|
312
|
+
if (precedingNode) {
|
|
313
|
+
// Find first comment on the same line
|
|
314
|
+
for (let index = commentIndex - 1; index >= 0; index--) {
|
|
315
|
+
const {
|
|
316
|
+
comment,
|
|
317
|
+
precedingNode: currentCommentPrecedingNode
|
|
318
|
+
} = decoratedComments[index];
|
|
319
|
+
|
|
320
|
+
if (currentCommentPrecedingNode !== precedingNode || !isAllEmptyAndNoLineBreak(text.slice(locEnd(comment), start))) {
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
start = locStart(comment);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return hasNewline(text, start, {
|
|
329
|
+
backwards: true
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function isEndOfLineComment(text, options, decoratedComments, commentIndex) {
|
|
334
|
+
const {
|
|
335
|
+
comment,
|
|
336
|
+
followingNode
|
|
337
|
+
} = decoratedComments[commentIndex];
|
|
338
|
+
const {
|
|
339
|
+
locStart,
|
|
340
|
+
locEnd
|
|
341
|
+
} = options;
|
|
342
|
+
let end = locEnd(comment);
|
|
343
|
+
|
|
344
|
+
if (followingNode) {
|
|
345
|
+
// Find last comment on the same line
|
|
346
|
+
for (let index = commentIndex + 1; index < decoratedComments.length; index++) {
|
|
347
|
+
const {
|
|
348
|
+
comment,
|
|
349
|
+
followingNode: currentCommentFollowingNode
|
|
350
|
+
} = decoratedComments[index];
|
|
351
|
+
|
|
352
|
+
if (currentCommentFollowingNode !== followingNode || !isAllEmptyAndNoLineBreak(text.slice(end, locStart(comment)))) {
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
end = locEnd(comment);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return hasNewline(text, end);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function breakTies(tiesToBreak, text, options) {
|
|
364
|
+
const tieCount = tiesToBreak.length;
|
|
365
|
+
|
|
366
|
+
if (tieCount === 0) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const {
|
|
371
|
+
precedingNode,
|
|
372
|
+
followingNode,
|
|
373
|
+
enclosingNode
|
|
374
|
+
} = tiesToBreak[0];
|
|
375
|
+
const gapRegExp = options.printer.getGapRegex && options.printer.getGapRegex(enclosingNode) || /^[\s(]*$/;
|
|
376
|
+
let gapEndPos = options.locStart(followingNode); // Iterate backwards through tiesToBreak, examining the gaps
|
|
377
|
+
// between the tied comments. In order to qualify as leading, a
|
|
378
|
+
// comment must be separated from followingNode by an unbroken series of
|
|
379
|
+
// gaps (or other comments). Gaps should only contain whitespace or open
|
|
380
|
+
// parentheses.
|
|
381
|
+
|
|
382
|
+
let indexOfFirstLeadingComment;
|
|
383
|
+
|
|
384
|
+
for (indexOfFirstLeadingComment = tieCount; indexOfFirstLeadingComment > 0; --indexOfFirstLeadingComment) {
|
|
385
|
+
const {
|
|
386
|
+
comment,
|
|
387
|
+
precedingNode: currentCommentPrecedingNode,
|
|
388
|
+
followingNode: currentCommentFollowingNode
|
|
389
|
+
} = tiesToBreak[indexOfFirstLeadingComment - 1];
|
|
390
|
+
assert.strictEqual(currentCommentPrecedingNode, precedingNode);
|
|
391
|
+
assert.strictEqual(currentCommentFollowingNode, followingNode);
|
|
392
|
+
const gap = text.slice(options.locEnd(comment), gapEndPos);
|
|
393
|
+
|
|
394
|
+
if (gapRegExp.test(gap)) {
|
|
395
|
+
gapEndPos = options.locStart(comment);
|
|
396
|
+
} else {
|
|
397
|
+
// The gap string contained something other than whitespace or open
|
|
398
|
+
// parentheses.
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
for (const [i, {
|
|
404
|
+
comment
|
|
405
|
+
}] of tiesToBreak.entries()) {
|
|
406
|
+
if (i < indexOfFirstLeadingComment) {
|
|
407
|
+
addTrailingComment(precedingNode, comment);
|
|
408
|
+
} else {
|
|
409
|
+
addLeadingComment(followingNode, comment);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
for (const node of [precedingNode, followingNode]) {
|
|
414
|
+
if (node.comments && node.comments.length > 1) {
|
|
415
|
+
node.comments.sort((a, b) => options.locStart(a) - options.locStart(b));
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
tiesToBreak.length = 0;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function findExpressionIndexForComment(quasis, comment, options) {
|
|
423
|
+
const startPos = options.locStart(comment) - 1;
|
|
424
|
+
|
|
425
|
+
for (let i = 1; i < quasis.length; ++i) {
|
|
426
|
+
if (startPos < options.locStart(quasis[i])) {
|
|
427
|
+
return i - 1;
|
|
428
|
+
}
|
|
429
|
+
} // We haven't found it, it probably means that some of the locations are off.
|
|
430
|
+
// Let's just return the first one.
|
|
431
|
+
|
|
432
|
+
/* istanbul ignore next */
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
return 0;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
module.exports = {
|
|
439
|
+
attach
|
|
440
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and 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
|
+
const getLast = arr => arr[arr.length - 1];
|
|
12
|
+
|
|
13
|
+
module.exports = getLast;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createAddCommentsMutation = createAddCommentsMutation;
|
|
7
|
+
exports.performAddCommentsMutation = performAddCommentsMutation;
|
|
8
|
+
|
|
9
|
+
var _comments = require("../comments/comments");
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
13
|
+
*
|
|
14
|
+
* This source code is licensed under the MIT license found in the
|
|
15
|
+
* LICENSE file in the root directory of this source tree.
|
|
16
|
+
*
|
|
17
|
+
*
|
|
18
|
+
* @format
|
|
19
|
+
*/
|
|
20
|
+
function createAddCommentsMutation(node, comments) {
|
|
21
|
+
if (comments.length === 0) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
type: 'addComments',
|
|
27
|
+
comments,
|
|
28
|
+
node
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function performAddCommentsMutation(mutationContext, mutation) {
|
|
33
|
+
for (const {
|
|
34
|
+
comment: originalComment,
|
|
35
|
+
placement
|
|
36
|
+
} of mutation.comments) {
|
|
37
|
+
const comment = (0, _comments.cloneComment)(originalComment);
|
|
38
|
+
mutationContext.appendCommentToSource(comment, placement);
|
|
39
|
+
(0, _comments.addComment)(mutation.node, comment, placement);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return null;
|
|
43
|
+
}
|