@haneullabs/prettier-plugin-move 0.3.3
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/CHANGELOG.md +67 -0
- package/CONTRIBUTING.md +31 -0
- package/README.md +96 -0
- package/bin/prettier-move.js +29 -0
- package/out/cst/annotation.js +64 -0
- package/out/cst/annotation.js.map +1 -0
- package/out/cst/common.js +376 -0
- package/out/cst/common.js.map +1 -0
- package/out/cst/constant.js +92 -0
- package/out/cst/constant.js.map +1 -0
- package/out/cst/enum_definition.js +69 -0
- package/out/cst/enum_definition.js.map +1 -0
- package/out/cst/expression/abort_expression.js +32 -0
- package/out/cst/expression/abort_expression.js.map +1 -0
- package/out/cst/expression/annotation_expression.js +35 -0
- package/out/cst/expression/annotation_expression.js.map +1 -0
- package/out/cst/expression/assign_expression.js +51 -0
- package/out/cst/expression/assign_expression.js.map +1 -0
- package/out/cst/expression/binary_expression.js +70 -0
- package/out/cst/expression/binary_expression.js.map +1 -0
- package/out/cst/expression/block.js +58 -0
- package/out/cst/expression/block.js.map +1 -0
- package/out/cst/expression/block_item.js +25 -0
- package/out/cst/expression/block_item.js.map +1 -0
- package/out/cst/expression/borrow_expression.js +26 -0
- package/out/cst/expression/borrow_expression.js.map +1 -0
- package/out/cst/expression/break_expression.js +27 -0
- package/out/cst/expression/break_expression.js.map +1 -0
- package/out/cst/expression/call_expression.js +25 -0
- package/out/cst/expression/call_expression.js.map +1 -0
- package/out/cst/expression/cast_expression.js +31 -0
- package/out/cst/expression/cast_expression.js.map +1 -0
- package/out/cst/expression/continue_expression.js +26 -0
- package/out/cst/expression/continue_expression.js.map +1 -0
- package/out/cst/expression/dereference_expression.js +27 -0
- package/out/cst/expression/dereference_expression.js.map +1 -0
- package/out/cst/expression/dot_expression.js +66 -0
- package/out/cst/expression/dot_expression.js.map +1 -0
- package/out/cst/expression/expression_list.js +26 -0
- package/out/cst/expression/expression_list.js.map +1 -0
- package/out/cst/expression/identified_expression.js +28 -0
- package/out/cst/expression/identified_expression.js.map +1 -0
- package/out/cst/expression/if_expression.js +133 -0
- package/out/cst/expression/if_expression.js.map +1 -0
- package/out/cst/expression/index.js +74 -0
- package/out/cst/expression/index.js.map +1 -0
- package/out/cst/expression/index_expression.js +28 -0
- package/out/cst/expression/index_expression.js.map +1 -0
- package/out/cst/expression/lambda_expression.js +72 -0
- package/out/cst/expression/lambda_expression.js.map +1 -0
- package/out/cst/expression/let_statement.js +59 -0
- package/out/cst/expression/let_statement.js.map +1 -0
- package/out/cst/expression/loop_expression.js +27 -0
- package/out/cst/expression/loop_expression.js.map +1 -0
- package/out/cst/expression/macro_call_expression.js +66 -0
- package/out/cst/expression/macro_call_expression.js.map +1 -0
- package/out/cst/expression/match_expression.js +86 -0
- package/out/cst/expression/match_expression.js.map +1 -0
- package/out/cst/expression/move_or_copy_expression.js +27 -0
- package/out/cst/expression/move_or_copy_expression.js.map +1 -0
- package/out/cst/expression/name_expression.js +26 -0
- package/out/cst/expression/name_expression.js.map +1 -0
- package/out/cst/expression/pack_expression.js +27 -0
- package/out/cst/expression/pack_expression.js.map +1 -0
- package/out/cst/expression/return_expression.js +44 -0
- package/out/cst/expression/return_expression.js.map +1 -0
- package/out/cst/expression/unary_expression.js +26 -0
- package/out/cst/expression/unary_expression.js.map +1 -0
- package/out/cst/expression/unit_expression.js +17 -0
- package/out/cst/expression/unit_expression.js.map +1 -0
- package/out/cst/expression/vector_expression.js +80 -0
- package/out/cst/expression/vector_expression.js.map +1 -0
- package/out/cst/expression/while_expression.js +42 -0
- package/out/cst/expression/while_expression.js.map +1 -0
- package/out/cst/formatting.js +100 -0
- package/out/cst/formatting.js.map +1 -0
- package/out/cst/function_definition.js +248 -0
- package/out/cst/function_definition.js.map +1 -0
- package/out/cst/literal.js +68 -0
- package/out/cst/literal.js.map +1 -0
- package/out/cst/module.js +158 -0
- package/out/cst/module.js.map +1 -0
- package/out/cst/source_file.js +38 -0
- package/out/cst/source_file.js.map +1 -0
- package/out/cst/struct_definition.js +209 -0
- package/out/cst/struct_definition.js.map +1 -0
- package/out/cst/use_declaration.js +212 -0
- package/out/cst/use_declaration.js.map +1 -0
- package/out/imports-grouping.js +259 -0
- package/out/imports-grouping.js.map +1 -0
- package/out/index.js +97 -0
- package/out/index.js.map +1 -0
- package/out/printer.js +69 -0
- package/out/printer.js.map +1 -0
- package/out/tree.js +371 -0
- package/out/tree.js.map +1 -0
- package/out/utilities.js +251 -0
- package/out/utilities.js.map +1 -0
- package/package.json +34 -0
- package/prettier.config.js +12 -0
- package/src/cst/annotation.ts +71 -0
- package/src/cst/common.ts +430 -0
- package/src/cst/constant.ts +110 -0
- package/src/cst/enum_definition.ts +73 -0
- package/src/cst/expression/abort_expression.ts +35 -0
- package/src/cst/expression/annotation_expression.ts +38 -0
- package/src/cst/expression/assign_expression.ts +66 -0
- package/src/cst/expression/binary_expression.ts +75 -0
- package/src/cst/expression/block.ts +72 -0
- package/src/cst/expression/block_item.ts +29 -0
- package/src/cst/expression/borrow_expression.ts +28 -0
- package/src/cst/expression/break_expression.ts +33 -0
- package/src/cst/expression/call_expression.ts +28 -0
- package/src/cst/expression/cast_expression.ts +35 -0
- package/src/cst/expression/continue_expression.ts +29 -0
- package/src/cst/expression/dereference_expression.ts +33 -0
- package/src/cst/expression/dot_expression.ts +89 -0
- package/src/cst/expression/expression_list.ts +28 -0
- package/src/cst/expression/identified_expression.ts +30 -0
- package/src/cst/expression/if_expression.ts +177 -0
- package/src/cst/expression/index.ts +85 -0
- package/src/cst/expression/index_expression.ts +37 -0
- package/src/cst/expression/lambda_expression.ts +84 -0
- package/src/cst/expression/let_statement.ts +73 -0
- package/src/cst/expression/loop_expression.ts +29 -0
- package/src/cst/expression/macro_call_expression.ts +79 -0
- package/src/cst/expression/match_expression.ts +102 -0
- package/src/cst/expression/move_or_copy_expression.ts +29 -0
- package/src/cst/expression/name_expression.ts +28 -0
- package/src/cst/expression/pack_expression.ts +29 -0
- package/src/cst/expression/return_expression.ts +50 -0
- package/src/cst/expression/unary_expression.ts +28 -0
- package/src/cst/expression/unit_expression.ts +18 -0
- package/src/cst/expression/vector_expression.ts +97 -0
- package/src/cst/expression/while_expression.ts +45 -0
- package/src/cst/formatting.ts +100 -0
- package/src/cst/function_definition.ts +300 -0
- package/src/cst/literal.ts +69 -0
- package/src/cst/module.ts +191 -0
- package/src/cst/source_file.ts +38 -0
- package/src/cst/struct_definition.ts +267 -0
- package/src/cst/use_declaration.ts +238 -0
- package/src/imports-grouping.ts +300 -0
- package/src/index.ts +119 -0
- package/src/printer.ts +93 -0
- package/src/tree.ts +438 -0
- package/src/utilities.ts +387 -0
- package/tree-sitter-move.wasm +0 -0
- package/tsconfig.json +26 -0
package/src/tree.ts
ADDED
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
// Copyright (c) The Move Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import Parser = require('web-tree-sitter');
|
|
5
|
+
import { isFormatting } from './cst/formatting';
|
|
6
|
+
import { isUseImport } from './cst/use_declaration';
|
|
7
|
+
|
|
8
|
+
export interface Comment {
|
|
9
|
+
type: 'line_comment' | 'block_comment';
|
|
10
|
+
text: string;
|
|
11
|
+
newline: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class Tree {
|
|
15
|
+
public type: string;
|
|
16
|
+
public text: string;
|
|
17
|
+
public isNamed: boolean;
|
|
18
|
+
public children: Tree[];
|
|
19
|
+
public leadingComment: Comment[];
|
|
20
|
+
public trailingComment: Comment | null;
|
|
21
|
+
public enableLeadingComment: boolean = true;
|
|
22
|
+
public enableTrailingComment: boolean = true;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A reference lock to the parent node. This is a function that returns the
|
|
26
|
+
* parent node. This way we remove the duplicate reference to the parent node
|
|
27
|
+
* and avoid circular references.
|
|
28
|
+
*/
|
|
29
|
+
private getParent: () => Tree | null;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Marks if the comment has been used. This is useful to avoid using the same
|
|
33
|
+
* comment multiple times + filter out comments that are already used.
|
|
34
|
+
*/
|
|
35
|
+
private isUsedComment: boolean = false;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Construct the `Tree` node from the `Parser.SyntaxNode`, additionally, run
|
|
39
|
+
* some passes to clean-up the tree and make the structure more manageable and
|
|
40
|
+
* easier to work with.
|
|
41
|
+
*
|
|
42
|
+
* Passes:
|
|
43
|
+
* - Sum-up pairs of newlines into a single empty line.
|
|
44
|
+
* - Filter out sequential empty lines.
|
|
45
|
+
* - Filter out leading and trailing empty lines.
|
|
46
|
+
* - Assign trailing comments to the node.
|
|
47
|
+
* - Assign leading comments to the node.
|
|
48
|
+
* - Filter out all assigned comments.
|
|
49
|
+
*
|
|
50
|
+
* @param node
|
|
51
|
+
* @param parent
|
|
52
|
+
*/
|
|
53
|
+
constructor(node: Parser.SyntaxNode, parent: Tree | null = null) {
|
|
54
|
+
this.type = node.type;
|
|
55
|
+
this.text = node.text;
|
|
56
|
+
this.isNamed = node.isNamed();
|
|
57
|
+
this.leadingComment = [];
|
|
58
|
+
this.trailingComment = null;
|
|
59
|
+
this.getParent = () => parent;
|
|
60
|
+
|
|
61
|
+
// === Clean-up passes ===
|
|
62
|
+
|
|
63
|
+
// turn every node into a `Tree` node.
|
|
64
|
+
this.children = node.children.map((child) => new Tree(child, this));
|
|
65
|
+
|
|
66
|
+
// sum-up pairs of newlines into a single empty line.
|
|
67
|
+
this.children = this.children.reduce((acc, node) => {
|
|
68
|
+
if (node.isNewline && node.nextSibling?.isNewline) node.type = 'empty_line';
|
|
69
|
+
if (node.isNewline && acc[acc.length - 1]?.isEmptyLine) return acc;
|
|
70
|
+
return [...acc, node];
|
|
71
|
+
}, [] as Tree[]);
|
|
72
|
+
|
|
73
|
+
// filter out sequential empty lines.
|
|
74
|
+
this.children = this.children.filter((node) => {
|
|
75
|
+
return !node.isEmptyLine || !node.previousNamedSibling?.isEmptyLine;
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// filter out leading and trailing empty lines.
|
|
79
|
+
this.children = this.children.filter((node) => {
|
|
80
|
+
if (!node.isEmptyLine) return true; // we only filter out empty lines
|
|
81
|
+
if (!node.previousNamedSibling) return false; // remove leading empty lines
|
|
82
|
+
if (!node.nextNamedSibling) return false; // remove trailing empty lines
|
|
83
|
+
return true;
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// assign trailing comments to the node. modifies the tree in place.
|
|
87
|
+
this.children.forEach((child) => child.assignTrailingComments());
|
|
88
|
+
|
|
89
|
+
// assign leading comments to the node. modifies the tree in place.
|
|
90
|
+
this.children.forEach((child) => child.assignLeadingComments());
|
|
91
|
+
|
|
92
|
+
// filter out all leading comments.
|
|
93
|
+
this.children = this.children.filter((child) => !child.isUsedComment);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Disable the trailing comment for the current node.
|
|
98
|
+
*/
|
|
99
|
+
disableTrailingComment() {
|
|
100
|
+
this.enableTrailingComment = false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Special case for lists, where we want to print the leading character (eg `dot_expression`).
|
|
105
|
+
*/
|
|
106
|
+
disableLeadingComment() {
|
|
107
|
+
this.enableLeadingComment = false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Find the parent node of a specific type. Optionally, break on a specific type.
|
|
112
|
+
*/
|
|
113
|
+
findParentUntil(type: string, breakOn: string[]): Tree | null {
|
|
114
|
+
let parent = this.parent;
|
|
115
|
+
while (parent) {
|
|
116
|
+
if (parent.type === type) return parent;
|
|
117
|
+
if (breakOn.includes(parent.type)) return null;
|
|
118
|
+
parent = parent.parent;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Check if the previous sibling is an annotation node. Ignore formatting nodes.
|
|
126
|
+
*/
|
|
127
|
+
get hasAnnotation(): boolean {
|
|
128
|
+
let prev = this.previousNamedSibling;
|
|
129
|
+
while (prev) {
|
|
130
|
+
if (prev.type === 'annotation') return true;
|
|
131
|
+
if (!prev.isFormatting) return false;
|
|
132
|
+
prev = prev.previousNamedSibling;
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* A flag to skip formatting for a specific node. A manual instruction from
|
|
139
|
+
* the user is `prettier-ignore`. When placed above (leading comment) a node,
|
|
140
|
+
* it will skip formatting for that node.
|
|
141
|
+
*/
|
|
142
|
+
get skipFormattingNode(): boolean {
|
|
143
|
+
return (
|
|
144
|
+
!!this.leadingComment.find((comment) => comment.text.includes('prettier-ignore')) ||
|
|
145
|
+
false
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get the number of named children.
|
|
151
|
+
*/
|
|
152
|
+
get namedChildCount(): number {
|
|
153
|
+
return this.namedChildren.length;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
get isFunctionCall(): boolean {
|
|
157
|
+
return this.type === 'call_expression' || this.type === 'macro_call_expression';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Tells whether a `Node` knows how to break itself.
|
|
162
|
+
* Nodes that match the following types are considered breakable:
|
|
163
|
+
* - `dot_expression`
|
|
164
|
+
* - `vector_expression`
|
|
165
|
+
* - `expression_list`
|
|
166
|
+
* - `if_expression` (?)
|
|
167
|
+
* - `pack_expression`
|
|
168
|
+
* - `match_expression`
|
|
169
|
+
* - `block`
|
|
170
|
+
*/
|
|
171
|
+
get isBreakableExpression(): boolean {
|
|
172
|
+
return [
|
|
173
|
+
// TODO: consider revisiting `call_expression` and `macro_call_expression`
|
|
174
|
+
// 'call_expression',
|
|
175
|
+
// 'macro_call_expression',
|
|
176
|
+
'dot_expression',
|
|
177
|
+
'index_expression',
|
|
178
|
+
'vector_expression',
|
|
179
|
+
'expression_list',
|
|
180
|
+
'if_expression',
|
|
181
|
+
'pack_expression',
|
|
182
|
+
'match_expression',
|
|
183
|
+
'block',
|
|
184
|
+
].includes(this.type);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Whether a node is a list node, like `vector_expression`, `expression_list`, or `block`.
|
|
189
|
+
* Lists are typical breakable nodes, where each element is separated by a newline.
|
|
190
|
+
*/
|
|
191
|
+
get isList(): boolean {
|
|
192
|
+
return ['vector_expression', 'expression_list', 'block'].includes(this.type);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Whether a node is a control flow node, like `if_expression`, `while_expression`,
|
|
197
|
+
* `loop_expression`, `abort_expression`, or `return_expression`.
|
|
198
|
+
*/
|
|
199
|
+
get isControlFlow(): boolean {
|
|
200
|
+
return [
|
|
201
|
+
'identified_expression',
|
|
202
|
+
'if_expression',
|
|
203
|
+
'while_expression',
|
|
204
|
+
'loop_expression',
|
|
205
|
+
'abort_expression',
|
|
206
|
+
'return_expression',
|
|
207
|
+
].includes(this.type);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Important part of the `imports-grouping` functionality. This flag is used to
|
|
212
|
+
* determine whether a node is an `use_module`, `use_module_members` or
|
|
213
|
+
* `use_module_member` node to skip their printing if they're printed as grouped.
|
|
214
|
+
*/
|
|
215
|
+
get isGroupedImport(): boolean {
|
|
216
|
+
return isUseImport(this) && !this.hasAnnotation;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Whether a node is a `Formatting` node, like `line_comment`, `block_comment`,
|
|
221
|
+
* `empty_line`, or `next_line`.
|
|
222
|
+
*/
|
|
223
|
+
get isFormatting(): boolean {
|
|
224
|
+
return isFormatting(this);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
child(index: number): Tree | null {
|
|
228
|
+
return this.children[index] || null;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
get isEmptyLine(): boolean {
|
|
232
|
+
return this.type === 'empty_line';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
get isNewline(): boolean {
|
|
236
|
+
return this.type === 'newline';
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
get isComment(): boolean {
|
|
240
|
+
return this.type === 'line_comment' || this.type === 'block_comment';
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
get isTypeParam(): boolean {
|
|
244
|
+
return ['apply_type', 'ref_type', 'tuple_type', 'function_type', 'primitive_type'].includes(
|
|
245
|
+
this.type,
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
get previousSibling(): Tree | null {
|
|
250
|
+
const parent = this.getParent();
|
|
251
|
+
if (!parent) {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const index = parent.children.indexOf(this);
|
|
256
|
+
if (index === 0) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return parent.children[index - 1] || null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
get previousNamedSibling(): Tree | null {
|
|
264
|
+
let node = this.previousSibling;
|
|
265
|
+
while (node && !node.isNamed) {
|
|
266
|
+
node = node.previousSibling;
|
|
267
|
+
}
|
|
268
|
+
return node;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
get startsOnNewLine(): boolean {
|
|
272
|
+
return this.previousSibling?.isNewline || false;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
get nonFormattingChildren(): Tree[] {
|
|
276
|
+
return this.namedChildren.filter((child) => !child.isFormatting);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
get namedChildren(): Tree[] {
|
|
280
|
+
return this.children.filter((child) => child.isNamed);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
get firstNamedChild(): Tree | null {
|
|
284
|
+
return this.namedChildren[0] || null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
get namedAndEmptyLineChildren(): Tree[] {
|
|
288
|
+
return this.namedChildren.filter((child) => {
|
|
289
|
+
return (
|
|
290
|
+
child.isNamed &&
|
|
291
|
+
(child.isEmptyLine ||
|
|
292
|
+
(child.isComment && !child.isUsedComment) ||
|
|
293
|
+
!child.isFormatting)
|
|
294
|
+
);
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
get nextSibling(): Tree | null {
|
|
299
|
+
const parent = this.getParent();
|
|
300
|
+
if (!parent) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const index = parent.children.indexOf(this);
|
|
305
|
+
if (index === parent.children.length - 1) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return parent.children[index + 1] || null;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
get nextNamedSibling(): Tree | null {
|
|
313
|
+
let node = this.nextSibling;
|
|
314
|
+
while (node && !node.isNamed) {
|
|
315
|
+
node = node.nextSibling;
|
|
316
|
+
}
|
|
317
|
+
return node;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
get parent() {
|
|
321
|
+
return this.getParent();
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Print the Node as a JSON object. Remove the fields that are not necessary
|
|
326
|
+
* for printing. May be extended shall one need to debug deeper.
|
|
327
|
+
*/
|
|
328
|
+
toJSON(): any {
|
|
329
|
+
return {
|
|
330
|
+
type: this.type,
|
|
331
|
+
isNamed: this.isNamed,
|
|
332
|
+
children: this.children.map((child) => child.toJSON()),
|
|
333
|
+
leadingComment: this.leadingComment,
|
|
334
|
+
trailingComment: this.trailingComment,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Checks the following node and assigns it as a trailing comment if it is a comment.
|
|
340
|
+
* The comment is then marked as used and will not be used again.
|
|
341
|
+
*/
|
|
342
|
+
private assignTrailingComments(): Tree {
|
|
343
|
+
if (!this.isNamed) return this;
|
|
344
|
+
if (this.isFormatting) return this;
|
|
345
|
+
|
|
346
|
+
const nextNamed = this.nextNamedSibling;
|
|
347
|
+
|
|
348
|
+
if (!nextNamed?.isComment) return this;
|
|
349
|
+
if (nextNamed.isUsedComment) return this;
|
|
350
|
+
|
|
351
|
+
const comment = nextNamed;
|
|
352
|
+
|
|
353
|
+
// if it's a block comment, we need to make sure there's nothing in
|
|
354
|
+
// between the current node and the comment, otherwise block comment is
|
|
355
|
+
// associated with the next node.
|
|
356
|
+
if (comment.type == 'block_comment') {
|
|
357
|
+
// any non-named node between the current node and the comment
|
|
358
|
+
// breaks the association.
|
|
359
|
+
if (comment.previousSibling != this && !!comment.nextNamedSibling) return this;
|
|
360
|
+
const addSpace = !!comment.nextNamedSibling ? ' ' : '';
|
|
361
|
+
|
|
362
|
+
this.trailingComment = {
|
|
363
|
+
type: comment.type as 'line_comment' | 'block_comment',
|
|
364
|
+
text: comment.text + addSpace,
|
|
365
|
+
newline: false,
|
|
366
|
+
};
|
|
367
|
+
this.nextNamedSibling!.isUsedComment = true;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (comment.type == 'line_comment') {
|
|
371
|
+
this.trailingComment = {
|
|
372
|
+
type: comment.type as 'line_comment' | 'block_comment',
|
|
373
|
+
text: comment.text,
|
|
374
|
+
newline: false,
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
this.nextNamedSibling!.isUsedComment = true;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return this;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Walks backwards through the siblings and searches for comments preceding
|
|
385
|
+
* the current node. If a comment is found, it is assigned to the `leadingComment`
|
|
386
|
+
* property of the node, and the comment is marked as used.
|
|
387
|
+
*
|
|
388
|
+
* Used comments are filtered out and not used again.
|
|
389
|
+
*
|
|
390
|
+
* Motivation for this is to avoid duplicate association of a comment both as
|
|
391
|
+
* a trailing comment and a leading comment.
|
|
392
|
+
*/
|
|
393
|
+
private assignLeadingComments(): Tree {
|
|
394
|
+
let comments = [];
|
|
395
|
+
let prev = this.previousNamedSibling;
|
|
396
|
+
let newline = false;
|
|
397
|
+
|
|
398
|
+
if (!this.isNamed) return this;
|
|
399
|
+
if (this.isFormatting) return this;
|
|
400
|
+
|
|
401
|
+
while (prev?.isNewline) {
|
|
402
|
+
newline = true;
|
|
403
|
+
prev = prev.previousNamedSibling;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (prev?.type == 'block_comment') {
|
|
407
|
+
if (prev.isUsedComment) return this;
|
|
408
|
+
|
|
409
|
+
comments.unshift({
|
|
410
|
+
type: prev.type as 'line_comment' | 'block_comment',
|
|
411
|
+
text: prev.text,
|
|
412
|
+
newline,
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
prev.isUsedComment = true;
|
|
416
|
+
this.leadingComment = comments;
|
|
417
|
+
return this;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
while (prev?.isComment || (prev?.isNewline && !prev?.isUsedComment)) {
|
|
421
|
+
if (prev.isUsedComment) break;
|
|
422
|
+
if (prev.isComment) {
|
|
423
|
+
comments.unshift({
|
|
424
|
+
type: prev.type as 'line_comment' | 'block_comment',
|
|
425
|
+
text: prev.text,
|
|
426
|
+
newline: true,
|
|
427
|
+
});
|
|
428
|
+
prev.isUsedComment = true;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
prev = prev.previousNamedSibling; // move to the previous comment
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
this.leadingComment = comments;
|
|
435
|
+
|
|
436
|
+
return this;
|
|
437
|
+
}
|
|
438
|
+
}
|