source: imaps-frontend/node_modules/espree/lib/token-translator.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/**
2 * @fileoverview Translates tokens between Acorn format and Esprima format.
3 * @author Nicholas C. Zakas
4 */
5
6//------------------------------------------------------------------------------
7// Requirements
8//------------------------------------------------------------------------------
9
10// none!
11
12//------------------------------------------------------------------------------
13// Private
14//------------------------------------------------------------------------------
15
16
17// Esprima Token Types
18const Token = {
19 Boolean: "Boolean",
20 EOF: "<end>",
21 Identifier: "Identifier",
22 PrivateIdentifier: "PrivateIdentifier",
23 Keyword: "Keyword",
24 Null: "Null",
25 Numeric: "Numeric",
26 Punctuator: "Punctuator",
27 String: "String",
28 RegularExpression: "RegularExpression",
29 Template: "Template",
30 JSXIdentifier: "JSXIdentifier",
31 JSXText: "JSXText"
32};
33
34/**
35 * Converts part of a template into an Esprima token.
36 * @param {AcornToken[]} tokens The Acorn tokens representing the template.
37 * @param {string} code The source code.
38 * @returns {EsprimaToken} The Esprima equivalent of the template token.
39 * @private
40 */
41function convertTemplatePart(tokens, code) {
42 const firstToken = tokens[0],
43 lastTemplateToken = tokens[tokens.length - 1];
44
45 const token = {
46 type: Token.Template,
47 value: code.slice(firstToken.start, lastTemplateToken.end)
48 };
49
50 if (firstToken.loc) {
51 token.loc = {
52 start: firstToken.loc.start,
53 end: lastTemplateToken.loc.end
54 };
55 }
56
57 if (firstToken.range) {
58 token.start = firstToken.range[0];
59 token.end = lastTemplateToken.range[1];
60 token.range = [token.start, token.end];
61 }
62
63 return token;
64}
65
66/**
67 * Contains logic to translate Acorn tokens into Esprima tokens.
68 * @param {Object} acornTokTypes The Acorn token types.
69 * @param {string} code The source code Acorn is parsing. This is necessary
70 * to correct the "value" property of some tokens.
71 * @constructor
72 */
73function TokenTranslator(acornTokTypes, code) {
74
75 // token types
76 this._acornTokTypes = acornTokTypes;
77
78 // token buffer for templates
79 this._tokens = [];
80
81 // track the last curly brace
82 this._curlyBrace = null;
83
84 // the source code
85 this._code = code;
86
87}
88
89TokenTranslator.prototype = {
90 constructor: TokenTranslator,
91
92 /**
93 * Translates a single Esprima token to a single Acorn token. This may be
94 * inaccurate due to how templates are handled differently in Esprima and
95 * Acorn, but should be accurate for all other tokens.
96 * @param {AcornToken} token The Acorn token to translate.
97 * @param {Object} extra Espree extra object.
98 * @returns {EsprimaToken} The Esprima version of the token.
99 */
100 translate(token, extra) {
101
102 const type = token.type,
103 tt = this._acornTokTypes;
104
105 if (type === tt.name) {
106 token.type = Token.Identifier;
107
108 // TODO: See if this is an Acorn bug
109 if (token.value === "static") {
110 token.type = Token.Keyword;
111 }
112
113 if (extra.ecmaVersion > 5 && (token.value === "yield" || token.value === "let")) {
114 token.type = Token.Keyword;
115 }
116
117 } else if (type === tt.privateId) {
118 token.type = Token.PrivateIdentifier;
119
120 } else if (type === tt.semi || type === tt.comma ||
121 type === tt.parenL || type === tt.parenR ||
122 type === tt.braceL || type === tt.braceR ||
123 type === tt.dot || type === tt.bracketL ||
124 type === tt.colon || type === tt.question ||
125 type === tt.bracketR || type === tt.ellipsis ||
126 type === tt.arrow || type === tt.jsxTagStart ||
127 type === tt.incDec || type === tt.starstar ||
128 type === tt.jsxTagEnd || type === tt.prefix ||
129 type === tt.questionDot ||
130 (type.binop && !type.keyword) ||
131 type.isAssign) {
132
133 token.type = Token.Punctuator;
134 token.value = this._code.slice(token.start, token.end);
135 } else if (type === tt.jsxName) {
136 token.type = Token.JSXIdentifier;
137 } else if (type.label === "jsxText" || type === tt.jsxAttrValueToken) {
138 token.type = Token.JSXText;
139 } else if (type.keyword) {
140 if (type.keyword === "true" || type.keyword === "false") {
141 token.type = Token.Boolean;
142 } else if (type.keyword === "null") {
143 token.type = Token.Null;
144 } else {
145 token.type = Token.Keyword;
146 }
147 } else if (type === tt.num) {
148 token.type = Token.Numeric;
149 token.value = this._code.slice(token.start, token.end);
150 } else if (type === tt.string) {
151
152 if (extra.jsxAttrValueToken) {
153 extra.jsxAttrValueToken = false;
154 token.type = Token.JSXText;
155 } else {
156 token.type = Token.String;
157 }
158
159 token.value = this._code.slice(token.start, token.end);
160 } else if (type === tt.regexp) {
161 token.type = Token.RegularExpression;
162 const value = token.value;
163
164 token.regex = {
165 flags: value.flags,
166 pattern: value.pattern
167 };
168 token.value = `/${value.pattern}/${value.flags}`;
169 }
170
171 return token;
172 },
173
174 /**
175 * Function to call during Acorn's onToken handler.
176 * @param {AcornToken} token The Acorn token.
177 * @param {Object} extra The Espree extra object.
178 * @returns {void}
179 */
180 onToken(token, extra) {
181
182 const tt = this._acornTokTypes,
183 tokens = extra.tokens,
184 templateTokens = this._tokens;
185
186 /**
187 * Flushes the buffered template tokens and resets the template
188 * tracking.
189 * @returns {void}
190 * @private
191 */
192 const translateTemplateTokens = () => {
193 tokens.push(convertTemplatePart(this._tokens, this._code));
194 this._tokens = [];
195 };
196
197 if (token.type === tt.eof) {
198
199 // might be one last curlyBrace
200 if (this._curlyBrace) {
201 tokens.push(this.translate(this._curlyBrace, extra));
202 }
203
204 return;
205 }
206
207 if (token.type === tt.backQuote) {
208
209 // if there's already a curly, it's not part of the template
210 if (this._curlyBrace) {
211 tokens.push(this.translate(this._curlyBrace, extra));
212 this._curlyBrace = null;
213 }
214
215 templateTokens.push(token);
216
217 // it's the end
218 if (templateTokens.length > 1) {
219 translateTemplateTokens();
220 }
221
222 return;
223 }
224 if (token.type === tt.dollarBraceL) {
225 templateTokens.push(token);
226 translateTemplateTokens();
227 return;
228 }
229 if (token.type === tt.braceR) {
230
231 // if there's already a curly, it's not part of the template
232 if (this._curlyBrace) {
233 tokens.push(this.translate(this._curlyBrace, extra));
234 }
235
236 // store new curly for later
237 this._curlyBrace = token;
238 return;
239 }
240 if (token.type === tt.template || token.type === tt.invalidTemplate) {
241 if (this._curlyBrace) {
242 templateTokens.push(this._curlyBrace);
243 this._curlyBrace = null;
244 }
245
246 templateTokens.push(token);
247 return;
248 }
249
250 if (this._curlyBrace) {
251 tokens.push(this.translate(this._curlyBrace, extra));
252 this._curlyBrace = null;
253 }
254
255 tokens.push(this.translate(token, extra));
256 }
257};
258
259//------------------------------------------------------------------------------
260// Public
261//------------------------------------------------------------------------------
262
263export default TokenTranslator;
Note: See TracBrowser for help on using the repository browser.