forked from hhvm/hhast
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathappend_to_nodelist.hack
More file actions
92 lines (82 loc) · 2.89 KB
/
Copy pathappend_to_nodelist.hack
File metadata and controls
92 lines (82 loc) · 2.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/*
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
namespace Facebook\HHAST;
use namespace HH\Lib\{C, Vec};
use function Facebook\HHAST\__Private\whitespace_from_nodelist;
/**
* Returns a copy of the provided NodeList with the provided items added at the
* end, preserving whitespace before/after items as much as possible.
*/
function append_to_nodelist<T as Node>(
NodeList<ListItem<T>> $list,
vec<T> $items_to_add,
?classname<TokenWithFixedText> $separator,
): NodeList<ListItem<T>> {
if (C\is_empty($items_to_add)) {
return $list;
}
$items = $list->getChildren();
$whitespace_between = whitespace_from_nodelist($list);
if (C\is_empty($items)) {
$had_trailing_separator = false;
$trailing_whitespace = vec[];
} else {
// We want a trailing separator iff the last item previously had one.
$had_trailing_separator = C\lastx($items)->getSeparator() is nonnull;
// Add a separator after the last previously-existing item, if missing.
if ($separator is nonnull && !$had_trailing_separator) {
$last_token = C\lastx($items)->getLastTokenx();
$items[C\count($items) - 1] = C\lastx($items)
->withSeparator(new $separator(null, $last_token->getTrailing(), null))
->replace($last_token, $last_token->withTrailing(null));
}
// Trim whitespace (but not other trivia) after the last item and save it
// for later (to put after the new last item).
$last_token = C\lastx($items)->getLastTokenx();
$trivia = $last_token->getTrailing()->getChildren();
for ($take_cnt = C\count($trivia); $take_cnt > 0; --$take_cnt) {
if (
!$trivia[$take_cnt - 1] is WhiteSpace &&
!$trivia[$take_cnt - 1] is EndOfLine
) {
break;
}
}
$items[C\count($items) - 1] = C\lastx($items)->replace(
$last_token,
$last_token->withTrailing(
NodeList::createMaybeEmptyList(Vec\take($trivia, $take_cnt)),
),
);
$trailing_whitespace = Vec\drop($trivia, $take_cnt);
}
// Finally, we're done with all the preprocessing and we can actually add the
// specified items.
foreach ($items_to_add as $item) {
if (!C\is_empty($items)) {
$item = $item->replace(
$item->getFirstTokenx(),
$item->getFirstTokenx()->withLeading($whitespace_between),
);
}
$items[] = new ListItem(
$item,
$separator is nonnull ? new $separator(null, null, null) : null,
);
}
if (!$had_trailing_separator) {
$items[C\count($items) - 1] = C\lastx($items)->withSeparator(null);
}
$new_list = NodeList::createMaybeEmptyList($items);
return $new_list->replace(
$new_list->getLastTokenx(),
$new_list->getLastTokenx()
->withTrailing(NodeList::createMaybeEmptyList($trailing_whitespace)),
);
}