source: frontend/node_modules/sucrase/dist/esm/TokenProcessor.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 9.9 KB
Line 
1
2
3
4import { TokenType as tt} from "./parser/tokenizer/types";
5import isAsyncOperation from "./util/isAsyncOperation";
6
7
8
9
10
11
12
13
14
15
16
17export default class TokenProcessor {
18 __init() {this.resultCode = ""}
19 // Array mapping input token index to optional string index position in the
20 // output code.
21 __init2() {this.resultMappings = new Array(this.tokens.length)}
22 __init3() {this.tokenIndex = 0}
23
24 constructor(
25 code,
26 tokens,
27 isFlowEnabled,
28 disableESTransforms,
29 helperManager,
30 ) {;this.code = code;this.tokens = tokens;this.isFlowEnabled = isFlowEnabled;this.disableESTransforms = disableESTransforms;this.helperManager = helperManager;TokenProcessor.prototype.__init.call(this);TokenProcessor.prototype.__init2.call(this);TokenProcessor.prototype.__init3.call(this);}
31
32 /**
33 * Snapshot the token state in a way that can be restored later, useful for
34 * things like lookahead.
35 *
36 * resultMappings do not need to be copied since in all use cases, they will
37 * be overwritten anyway after restore.
38 */
39 snapshot() {
40 return {
41 resultCode: this.resultCode,
42 tokenIndex: this.tokenIndex,
43 };
44 }
45
46 restoreToSnapshot(snapshot) {
47 this.resultCode = snapshot.resultCode;
48 this.tokenIndex = snapshot.tokenIndex;
49 }
50
51 /**
52 * Remove and return the code generated since the snapshot, leaving the
53 * current token position in-place. Unlike most TokenProcessor operations,
54 * this operation can result in input/output line number mismatches because
55 * the removed code may contain newlines, so this operation should be used
56 * sparingly.
57 */
58 dangerouslyGetAndRemoveCodeSinceSnapshot(snapshot) {
59 const result = this.resultCode.slice(snapshot.resultCode.length);
60 this.resultCode = snapshot.resultCode;
61 return result;
62 }
63
64 reset() {
65 this.resultCode = "";
66 this.resultMappings = new Array(this.tokens.length);
67 this.tokenIndex = 0;
68 }
69
70 matchesContextualAtIndex(index, contextualKeyword) {
71 return (
72 this.matches1AtIndex(index, tt.name) &&
73 this.tokens[index].contextualKeyword === contextualKeyword
74 );
75 }
76
77 identifierNameAtIndex(index) {
78 // TODO: We need to process escapes since technically you can have unicode escapes in variable
79 // names.
80 return this.identifierNameForToken(this.tokens[index]);
81 }
82
83 identifierNameAtRelativeIndex(relativeIndex) {
84 return this.identifierNameForToken(this.tokenAtRelativeIndex(relativeIndex));
85 }
86
87 identifierName() {
88 return this.identifierNameForToken(this.currentToken());
89 }
90
91 identifierNameForToken(token) {
92 return this.code.slice(token.start, token.end);
93 }
94
95 rawCodeForToken(token) {
96 return this.code.slice(token.start, token.end);
97 }
98
99 stringValueAtIndex(index) {
100 return this.stringValueForToken(this.tokens[index]);
101 }
102
103 stringValue() {
104 return this.stringValueForToken(this.currentToken());
105 }
106
107 stringValueForToken(token) {
108 // This is used to identify when two imports are the same and to resolve TypeScript enum keys.
109 // Ideally we'd process escapes within the strings, but for now we pretty much take the raw
110 // code.
111 return this.code.slice(token.start + 1, token.end - 1);
112 }
113
114 matches1AtIndex(index, t1) {
115 return this.tokens[index].type === t1;
116 }
117
118 matches2AtIndex(index, t1, t2) {
119 return this.tokens[index].type === t1 && this.tokens[index + 1].type === t2;
120 }
121
122 matches3AtIndex(index, t1, t2, t3) {
123 return (
124 this.tokens[index].type === t1 &&
125 this.tokens[index + 1].type === t2 &&
126 this.tokens[index + 2].type === t3
127 );
128 }
129
130 matches1(t1) {
131 return this.tokens[this.tokenIndex].type === t1;
132 }
133
134 matches2(t1, t2) {
135 return this.tokens[this.tokenIndex].type === t1 && this.tokens[this.tokenIndex + 1].type === t2;
136 }
137
138 matches3(t1, t2, t3) {
139 return (
140 this.tokens[this.tokenIndex].type === t1 &&
141 this.tokens[this.tokenIndex + 1].type === t2 &&
142 this.tokens[this.tokenIndex + 2].type === t3
143 );
144 }
145
146 matches4(t1, t2, t3, t4) {
147 return (
148 this.tokens[this.tokenIndex].type === t1 &&
149 this.tokens[this.tokenIndex + 1].type === t2 &&
150 this.tokens[this.tokenIndex + 2].type === t3 &&
151 this.tokens[this.tokenIndex + 3].type === t4
152 );
153 }
154
155 matches5(t1, t2, t3, t4, t5) {
156 return (
157 this.tokens[this.tokenIndex].type === t1 &&
158 this.tokens[this.tokenIndex + 1].type === t2 &&
159 this.tokens[this.tokenIndex + 2].type === t3 &&
160 this.tokens[this.tokenIndex + 3].type === t4 &&
161 this.tokens[this.tokenIndex + 4].type === t5
162 );
163 }
164
165 matchesContextual(contextualKeyword) {
166 return this.matchesContextualAtIndex(this.tokenIndex, contextualKeyword);
167 }
168
169 matchesContextIdAndLabel(type, contextId) {
170 return this.matches1(type) && this.currentToken().contextId === contextId;
171 }
172
173 previousWhitespaceAndComments() {
174 let whitespaceAndComments = this.code.slice(
175 this.tokenIndex > 0 ? this.tokens[this.tokenIndex - 1].end : 0,
176 this.tokenIndex < this.tokens.length ? this.tokens[this.tokenIndex].start : this.code.length,
177 );
178 if (this.isFlowEnabled) {
179 whitespaceAndComments = whitespaceAndComments.replace(/@flow/g, "");
180 }
181 return whitespaceAndComments;
182 }
183
184 replaceToken(newCode) {
185 this.resultCode += this.previousWhitespaceAndComments();
186 this.appendTokenPrefix();
187 this.resultMappings[this.tokenIndex] = this.resultCode.length;
188 this.resultCode += newCode;
189 this.appendTokenSuffix();
190 this.tokenIndex++;
191 }
192
193 replaceTokenTrimmingLeftWhitespace(newCode) {
194 this.resultCode += this.previousWhitespaceAndComments().replace(/[^\r\n]/g, "");
195 this.appendTokenPrefix();
196 this.resultMappings[this.tokenIndex] = this.resultCode.length;
197 this.resultCode += newCode;
198 this.appendTokenSuffix();
199 this.tokenIndex++;
200 }
201
202 removeInitialToken() {
203 this.replaceToken("");
204 }
205
206 removeToken() {
207 this.replaceTokenTrimmingLeftWhitespace("");
208 }
209
210 /**
211 * Remove all code until the next }, accounting for balanced braces.
212 */
213 removeBalancedCode() {
214 let braceDepth = 0;
215 while (!this.isAtEnd()) {
216 if (this.matches1(tt.braceL)) {
217 braceDepth++;
218 } else if (this.matches1(tt.braceR)) {
219 if (braceDepth === 0) {
220 return;
221 }
222 braceDepth--;
223 }
224 this.removeToken();
225 }
226 }
227
228 copyExpectedToken(tokenType) {
229 if (this.tokens[this.tokenIndex].type !== tokenType) {
230 throw new Error(`Expected token ${tokenType}`);
231 }
232 this.copyToken();
233 }
234
235 copyToken() {
236 this.resultCode += this.previousWhitespaceAndComments();
237 this.appendTokenPrefix();
238 this.resultMappings[this.tokenIndex] = this.resultCode.length;
239 this.resultCode += this.code.slice(
240 this.tokens[this.tokenIndex].start,
241 this.tokens[this.tokenIndex].end,
242 );
243 this.appendTokenSuffix();
244 this.tokenIndex++;
245 }
246
247 copyTokenWithPrefix(prefix) {
248 this.resultCode += this.previousWhitespaceAndComments();
249 this.appendTokenPrefix();
250 this.resultCode += prefix;
251 this.resultMappings[this.tokenIndex] = this.resultCode.length;
252 this.resultCode += this.code.slice(
253 this.tokens[this.tokenIndex].start,
254 this.tokens[this.tokenIndex].end,
255 );
256 this.appendTokenSuffix();
257 this.tokenIndex++;
258 }
259
260 appendTokenPrefix() {
261 const token = this.currentToken();
262 if (token.numNullishCoalesceStarts || token.isOptionalChainStart) {
263 token.isAsyncOperation = isAsyncOperation(this);
264 }
265 if (this.disableESTransforms) {
266 return;
267 }
268 if (token.numNullishCoalesceStarts) {
269 for (let i = 0; i < token.numNullishCoalesceStarts; i++) {
270 if (token.isAsyncOperation) {
271 this.resultCode += "await ";
272 this.resultCode += this.helperManager.getHelperName("asyncNullishCoalesce");
273 } else {
274 this.resultCode += this.helperManager.getHelperName("nullishCoalesce");
275 }
276 this.resultCode += "(";
277 }
278 }
279 if (token.isOptionalChainStart) {
280 if (token.isAsyncOperation) {
281 this.resultCode += "await ";
282 }
283 if (this.tokenIndex > 0 && this.tokenAtRelativeIndex(-1).type === tt._delete) {
284 if (token.isAsyncOperation) {
285 this.resultCode += this.helperManager.getHelperName("asyncOptionalChainDelete");
286 } else {
287 this.resultCode += this.helperManager.getHelperName("optionalChainDelete");
288 }
289 } else if (token.isAsyncOperation) {
290 this.resultCode += this.helperManager.getHelperName("asyncOptionalChain");
291 } else {
292 this.resultCode += this.helperManager.getHelperName("optionalChain");
293 }
294 this.resultCode += "([";
295 }
296 }
297
298 appendTokenSuffix() {
299 const token = this.currentToken();
300 if (token.isOptionalChainEnd && !this.disableESTransforms) {
301 this.resultCode += "])";
302 }
303 if (token.numNullishCoalesceEnds && !this.disableESTransforms) {
304 for (let i = 0; i < token.numNullishCoalesceEnds; i++) {
305 this.resultCode += "))";
306 }
307 }
308 }
309
310 appendCode(code) {
311 this.resultCode += code;
312 }
313
314 currentToken() {
315 return this.tokens[this.tokenIndex];
316 }
317
318 currentTokenCode() {
319 const token = this.currentToken();
320 return this.code.slice(token.start, token.end);
321 }
322
323 tokenAtRelativeIndex(relativeIndex) {
324 return this.tokens[this.tokenIndex + relativeIndex];
325 }
326
327 currentIndex() {
328 return this.tokenIndex;
329 }
330
331 /**
332 * Move to the next token. Only suitable in preprocessing steps. When
333 * generating new code, you should use copyToken or removeToken.
334 */
335 nextToken() {
336 if (this.tokenIndex === this.tokens.length) {
337 throw new Error("Unexpectedly reached end of input.");
338 }
339 this.tokenIndex++;
340 }
341
342 previousToken() {
343 this.tokenIndex--;
344 }
345
346 finish() {
347 if (this.tokenIndex !== this.tokens.length) {
348 throw new Error("Tried to finish processing tokens before reaching the end.");
349 }
350 this.resultCode += this.previousWhitespaceAndComments();
351 return {code: this.resultCode, mappings: this.resultMappings};
352 }
353
354 isAtEnd() {
355 return this.tokenIndex === this.tokens.length;
356 }
357}
Note: See TracBrowser for help on using the repository browser.