UNPKG

8.64 kBJavaScriptView Raw
1"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2
3
4var _types = require('./parser/tokenizer/types');
5var _isAsyncOperation = require('./util/isAsyncOperation'); var _isAsyncOperation2 = _interopRequireDefault(_isAsyncOperation);
6
7
8
9
10
11
12 class TokenProcessor {
13 __init() {this.resultCode = ""}
14 __init2() {this.tokenIndex = 0}
15
16 constructor(
17 code,
18 tokens,
19 isFlowEnabled,
20 helperManager,
21 ) {;this.code = code;this.tokens = tokens;this.isFlowEnabled = isFlowEnabled;this.helperManager = helperManager;TokenProcessor.prototype.__init.call(this);TokenProcessor.prototype.__init2.call(this);}
22
23 /**
24 * Make a new TokenProcessor for things like lookahead.
25 */
26 snapshot() {
27 return {resultCode: this.resultCode, tokenIndex: this.tokenIndex};
28 }
29
30 restoreToSnapshot(snapshot) {
31 this.resultCode = snapshot.resultCode;
32 this.tokenIndex = snapshot.tokenIndex;
33 }
34
35 getResultCodeIndex() {
36 return this.resultCode.length;
37 }
38
39 reset() {
40 this.resultCode = "";
41 this.tokenIndex = 0;
42 }
43
44 matchesContextualAtIndex(index, contextualKeyword) {
45 return (
46 this.matches1AtIndex(index, _types.TokenType.name) &&
47 this.tokens[index].contextualKeyword === contextualKeyword
48 );
49 }
50
51 identifierNameAtIndex(index) {
52 // TODO: We need to process escapes since technically you can have unicode escapes in variable
53 // names.
54 return this.identifierNameForToken(this.tokens[index]);
55 }
56
57 identifierName() {
58 return this.identifierNameForToken(this.currentToken());
59 }
60
61 identifierNameForToken(token) {
62 return this.code.slice(token.start, token.end);
63 }
64
65 rawCodeForToken(token) {
66 return this.code.slice(token.start, token.end);
67 }
68
69 stringValueAtIndex(index) {
70 return this.stringValueForToken(this.tokens[index]);
71 }
72
73 stringValue() {
74 return this.stringValueForToken(this.currentToken());
75 }
76
77 stringValueForToken(token) {
78 // This is used to identify when two imports are the same and to resolve TypeScript enum keys.
79 // Ideally we'd process escapes within the strings, but for now we pretty much take the raw
80 // code.
81 return this.code.slice(token.start + 1, token.end - 1);
82 }
83
84 matches1AtIndex(index, t1) {
85 return this.tokens[index].type === t1;
86 }
87
88 matches2AtIndex(index, t1, t2) {
89 return this.tokens[index].type === t1 && this.tokens[index + 1].type === t2;
90 }
91
92 matches3AtIndex(index, t1, t2, t3) {
93 return (
94 this.tokens[index].type === t1 &&
95 this.tokens[index + 1].type === t2 &&
96 this.tokens[index + 2].type === t3
97 );
98 }
99
100 matches1(t1) {
101 return this.tokens[this.tokenIndex].type === t1;
102 }
103
104 matches2(t1, t2) {
105 return this.tokens[this.tokenIndex].type === t1 && this.tokens[this.tokenIndex + 1].type === t2;
106 }
107
108 matches3(t1, t2, t3) {
109 return (
110 this.tokens[this.tokenIndex].type === t1 &&
111 this.tokens[this.tokenIndex + 1].type === t2 &&
112 this.tokens[this.tokenIndex + 2].type === t3
113 );
114 }
115
116 matches4(t1, t2, t3, t4) {
117 return (
118 this.tokens[this.tokenIndex].type === t1 &&
119 this.tokens[this.tokenIndex + 1].type === t2 &&
120 this.tokens[this.tokenIndex + 2].type === t3 &&
121 this.tokens[this.tokenIndex + 3].type === t4
122 );
123 }
124
125 matches5(t1, t2, t3, t4, t5) {
126 return (
127 this.tokens[this.tokenIndex].type === t1 &&
128 this.tokens[this.tokenIndex + 1].type === t2 &&
129 this.tokens[this.tokenIndex + 2].type === t3 &&
130 this.tokens[this.tokenIndex + 3].type === t4 &&
131 this.tokens[this.tokenIndex + 4].type === t5
132 );
133 }
134
135 matchesContextual(contextualKeyword) {
136 return this.matchesContextualAtIndex(this.tokenIndex, contextualKeyword);
137 }
138
139 matchesContextIdAndLabel(type, contextId) {
140 return this.matches1(type) && this.currentToken().contextId === contextId;
141 }
142
143 previousWhitespaceAndComments() {
144 let whitespaceAndComments = this.code.slice(
145 this.tokenIndex > 0 ? this.tokens[this.tokenIndex - 1].end : 0,
146 this.tokenIndex < this.tokens.length ? this.tokens[this.tokenIndex].start : this.code.length,
147 );
148 if (this.isFlowEnabled) {
149 whitespaceAndComments = whitespaceAndComments.replace(/@flow/g, "");
150 }
151 return whitespaceAndComments;
152 }
153
154 replaceToken(newCode) {
155 this.resultCode += this.previousWhitespaceAndComments();
156 this.appendTokenPrefix();
157 this.resultCode += newCode;
158 this.appendTokenSuffix();
159 this.tokenIndex++;
160 }
161
162 replaceTokenTrimmingLeftWhitespace(newCode) {
163 this.resultCode += this.previousWhitespaceAndComments().replace(/[^\r\n]/g, "");
164 this.appendTokenPrefix();
165 this.resultCode += newCode;
166 this.appendTokenSuffix();
167 this.tokenIndex++;
168 }
169
170 removeInitialToken() {
171 this.resultCode += this.previousWhitespaceAndComments();
172 this.tokenIndex++;
173 }
174
175 removeToken() {
176 this.resultCode += this.previousWhitespaceAndComments().replace(/[^\r\n]/g, "");
177 this.tokenIndex++;
178 }
179
180 copyExpectedToken(tokenType) {
181 if (this.tokens[this.tokenIndex].type !== tokenType) {
182 throw new Error(`Expected token ${tokenType}`);
183 }
184 this.copyToken();
185 }
186
187 copyToken() {
188 this.resultCode += this.previousWhitespaceAndComments();
189 this.appendTokenPrefix();
190 this.resultCode += this.code.slice(
191 this.tokens[this.tokenIndex].start,
192 this.tokens[this.tokenIndex].end,
193 );
194 this.appendTokenSuffix();
195 this.tokenIndex++;
196 }
197
198 copyTokenWithPrefix(prefix) {
199 this.resultCode += this.previousWhitespaceAndComments();
200 this.appendTokenPrefix();
201 this.resultCode += prefix;
202 this.resultCode += this.code.slice(
203 this.tokens[this.tokenIndex].start,
204 this.tokens[this.tokenIndex].end,
205 );
206 this.appendTokenSuffix();
207 this.tokenIndex++;
208 }
209
210 appendTokenPrefix() {
211 const token = this.currentToken();
212 if (token.numNullishCoalesceStarts || token.isOptionalChainStart) {
213 token.isAsyncOperation = _isAsyncOperation2.default.call(void 0, this);
214 }
215 if (token.numNullishCoalesceStarts) {
216 for (let i = 0; i < token.numNullishCoalesceStarts; i++) {
217 if (token.isAsyncOperation) {
218 this.resultCode += "await ";
219 this.resultCode += this.helperManager.getHelperName("asyncNullishCoalesce");
220 } else {
221 this.resultCode += this.helperManager.getHelperName("nullishCoalesce");
222 }
223 this.resultCode += "(";
224 }
225 }
226 if (token.isOptionalChainStart) {
227 if (token.isAsyncOperation) {
228 this.resultCode += "await ";
229 }
230 if (this.tokenIndex > 0 && this.tokenAtRelativeIndex(-1).type === _types.TokenType._delete) {
231 if (token.isAsyncOperation) {
232 this.resultCode += this.helperManager.getHelperName("asyncOptionalChainDelete");
233 } else {
234 this.resultCode += this.helperManager.getHelperName("optionalChainDelete");
235 }
236 } else if (token.isAsyncOperation) {
237 this.resultCode += this.helperManager.getHelperName("asyncOptionalChain");
238 } else {
239 this.resultCode += this.helperManager.getHelperName("optionalChain");
240 }
241 this.resultCode += "([";
242 }
243 }
244
245 appendTokenSuffix() {
246 const token = this.currentToken();
247 if (token.isOptionalChainEnd) {
248 this.resultCode += "])";
249 }
250 if (token.numNullishCoalesceEnds) {
251 for (let i = 0; i < token.numNullishCoalesceEnds; i++) {
252 this.resultCode += "))";
253 }
254 }
255 }
256
257 appendCode(code) {
258 this.resultCode += code;
259 }
260
261 currentToken() {
262 return this.tokens[this.tokenIndex];
263 }
264
265 currentTokenCode() {
266 const token = this.currentToken();
267 return this.code.slice(token.start, token.end);
268 }
269
270 tokenAtRelativeIndex(relativeIndex) {
271 return this.tokens[this.tokenIndex + relativeIndex];
272 }
273
274 currentIndex() {
275 return this.tokenIndex;
276 }
277
278 /**
279 * Move to the next token. Only suitable in preprocessing steps. When
280 * generating new code, you should use copyToken or removeToken.
281 */
282 nextToken() {
283 if (this.tokenIndex === this.tokens.length) {
284 throw new Error("Unexpectedly reached end of input.");
285 }
286 this.tokenIndex++;
287 }
288
289 previousToken() {
290 this.tokenIndex--;
291 }
292
293 finish() {
294 if (this.tokenIndex !== this.tokens.length) {
295 throw new Error("Tried to finish processing tokens before reaching the end.");
296 }
297 this.resultCode += this.previousWhitespaceAndComments();
298 return this.resultCode;
299 }
300
301 isAtEnd() {
302 return this.tokenIndex === this.tokens.length;
303 }
304} exports.default = TokenProcessor;