1 |
|
2 |
|
3 |
|
4 |
|
5 | "use strict";
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | module.exports = function(tokens) {
|
12 | const api = {},
|
13 | starts = Object.create(null),
|
14 | ends = Object.create(null),
|
15 | length = tokens.length;
|
16 |
|
17 | |
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 | function get(start, end) {
|
24 | const result = [];
|
25 |
|
26 | for (let i = Math.max(0, start); i < end && i < length; i++) {
|
27 | result.push(tokens[i]);
|
28 | }
|
29 |
|
30 | return result;
|
31 | }
|
32 |
|
33 | |
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 | function lastTokenIndex(node) {
|
41 | const end = node.range[1];
|
42 | let cursor = ends[end];
|
43 |
|
44 |
|
45 |
|
46 | if (typeof cursor === "undefined") {
|
47 | cursor = starts[end] - 1;
|
48 | }
|
49 |
|
50 |
|
51 |
|
52 | if (isNaN(cursor)) {
|
53 | cursor = length - 1;
|
54 | }
|
55 |
|
56 | return cursor;
|
57 | }
|
58 |
|
59 |
|
60 | for (let i = 0; i < length; i++) {
|
61 | const range = tokens[i].range;
|
62 |
|
63 | starts[range[0]] = i;
|
64 | ends[range[1]] = i;
|
65 | }
|
66 |
|
67 | |
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 | api.getTokensBefore = function(node, beforeCount) {
|
76 | const first = starts[node.range[0]];
|
77 |
|
78 | return get(first - (beforeCount || 0), first);
|
79 | };
|
80 |
|
81 | /**
|
82 | * Gets the token that precedes a given node or token in the token stream.
|
83 | * @param {(ASTNode|Token)} node The AST node or token.
|
84 | * @param {int} [skip=0] A number of tokens to skip before the given node or
|
85 | * token.
|
86 | * @returns {Token} An object representing the token.
|
87 | */
|
88 | api.getTokenBefore = function(node, skip) {
|
89 | return tokens[starts[node.range[0]] - (skip || 0) - 1];
|
90 | };
|
91 |
|
92 | |
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 | api.getTokensAfter = function(node, afterCount) {
|
101 | const start = lastTokenIndex(node) + 1;
|
102 |
|
103 | return get(start, start + (afterCount || 0));
|
104 | };
|
105 |
|
106 | /**
|
107 | * Gets the token that follows a given node or token in the token stream.
|
108 | * @param {(ASTNode|Token)} node The AST node or token.
|
109 | * @param {int} [skip=0] A number of tokens to skip after the given node or
|
110 | * token.
|
111 | * @returns {Token} An object representing the token.
|
112 | */
|
113 | api.getTokenAfter = function(node, skip) {
|
114 | return tokens[lastTokenIndex(node) + (skip || 0) + 1];
|
115 | };
|
116 |
|
117 | |
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 | api.getTokens = function(node, beforeCount, afterCount) {
|
125 | return get(
|
126 | starts[node.range[0]] - (beforeCount || 0),
|
127 | lastTokenIndex(node) + (afterCount || 0) + 1
|
128 | );
|
129 | };
|
130 |
|
131 | /**
|
132 | * Gets the first `count` tokens of the given node's token stream.
|
133 | * @param {ASTNode} node The AST node.
|
134 | * @param {int} [count=0] The number of tokens of the node to retrieve.
|
135 | * @returns {Token[]} Array of objects representing tokens.
|
136 | */
|
137 | api.getFirstTokens = function(node, count) {
|
138 | const first = starts[node.range[0]];
|
139 |
|
140 | return get(
|
141 | first,
|
142 | Math.min(lastTokenIndex(node) + 1, first + (count || 0))
|
143 | );
|
144 | };
|
145 |
|
146 | /**
|
147 | * Gets the first token of the given node's token stream.
|
148 | * @param {ASTNode} node The AST node.
|
149 | * @param {int} [skip=0] A number of tokens to skip.
|
150 | * @returns {Token} An object representing the token.
|
151 | */
|
152 | api.getFirstToken = function(node, skip) {
|
153 | return tokens[starts[node.range[0]] + (skip || 0)];
|
154 | };
|
155 |
|
156 | |
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 | api.getLastTokens = function(node, count) {
|
163 | const last = lastTokenIndex(node) + 1;
|
164 |
|
165 | return get(Math.max(starts[node.range[0]], last - (count || 0)), last);
|
166 | };
|
167 |
|
168 | /**
|
169 | * Gets the last token of the given node's token stream.
|
170 | * @param {ASTNode} node The AST node.
|
171 | * @param {int} [skip=0] A number of tokens to skip.
|
172 | * @returns {Token} An object representing the token.
|
173 | */
|
174 | api.getLastToken = function(node, skip) {
|
175 | return tokens[lastTokenIndex(node) - (skip || 0)];
|
176 | };
|
177 |
|
178 | |
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 | api.getTokensBetween = function(left, right, padding) {
|
186 | padding = padding || 0;
|
187 | return get(
|
188 | lastTokenIndex(left) + 1 - padding,
|
189 | starts[right.range[0]] + padding
|
190 | );
|
191 | };
|
192 |
|
193 | /**
|
194 | * Gets the token starting at the specified index.
|
195 | * @param {int} startIndex Index of the start of the token's range.
|
196 | * @returns {Token} The token starting at index, or null if no such token.
|
197 | */
|
198 | api.getTokenByRangeStart = function(startIndex) {
|
199 | return (tokens[starts[startIndex]] || null);
|
200 | };
|
201 |
|
202 | return api;
|
203 | };
|