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