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