/**
							 | 
						|
								 * @fileoverview Translates tokens between Acorn format and Esprima format.
							 | 
						|
								 * @author Nicholas C. Zakas
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								// Requirements
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								// none!
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								// Private
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								// Esprima Token Types
							 | 
						|
								const Token = {
							 | 
						|
								    Boolean: "Boolean",
							 | 
						|
								    EOF: "<end>",
							 | 
						|
								    Identifier: "Identifier",
							 | 
						|
								    PrivateIdentifier: "PrivateIdentifier",
							 | 
						|
								    Keyword: "Keyword",
							 | 
						|
								    Null: "Null",
							 | 
						|
								    Numeric: "Numeric",
							 | 
						|
								    Punctuator: "Punctuator",
							 | 
						|
								    String: "String",
							 | 
						|
								    RegularExpression: "RegularExpression",
							 | 
						|
								    Template: "Template",
							 | 
						|
								    JSXIdentifier: "JSXIdentifier",
							 | 
						|
								    JSXText: "JSXText"
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Converts part of a template into an Esprima token.
							 | 
						|
								 * @param {AcornToken[]} tokens The Acorn tokens representing the template.
							 | 
						|
								 * @param {string} code The source code.
							 | 
						|
								 * @returns {EsprimaToken} The Esprima equivalent of the template token.
							 | 
						|
								 * @private
							 | 
						|
								 */
							 | 
						|
								function convertTemplatePart(tokens, code) {
							 | 
						|
								    const firstToken = tokens[0],
							 | 
						|
								        lastTemplateToken = tokens[tokens.length - 1];
							 | 
						|
								
							 | 
						|
								    const token = {
							 | 
						|
								        type: Token.Template,
							 | 
						|
								        value: code.slice(firstToken.start, lastTemplateToken.end)
							 | 
						|
								    };
							 | 
						|
								
							 | 
						|
								    if (firstToken.loc) {
							 | 
						|
								        token.loc = {
							 | 
						|
								            start: firstToken.loc.start,
							 | 
						|
								            end: lastTemplateToken.loc.end
							 | 
						|
								        };
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (firstToken.range) {
							 | 
						|
								        token.start = firstToken.range[0];
							 | 
						|
								        token.end = lastTemplateToken.range[1];
							 | 
						|
								        token.range = [token.start, token.end];
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return token;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Contains logic to translate Acorn tokens into Esprima tokens.
							 | 
						|
								 * @param {Object} acornTokTypes The Acorn token types.
							 | 
						|
								 * @param {string} code The source code Acorn is parsing. This is necessary
							 | 
						|
								 *      to correct the "value" property of some tokens.
							 | 
						|
								 * @constructor
							 | 
						|
								 */
							 | 
						|
								function TokenTranslator(acornTokTypes, code) {
							 | 
						|
								
							 | 
						|
								    // token types
							 | 
						|
								    this._acornTokTypes = acornTokTypes;
							 | 
						|
								
							 | 
						|
								    // token buffer for templates
							 | 
						|
								    this._tokens = [];
							 | 
						|
								
							 | 
						|
								    // track the last curly brace
							 | 
						|
								    this._curlyBrace = null;
							 | 
						|
								
							 | 
						|
								    // the source code
							 | 
						|
								    this._code = code;
							 | 
						|
								
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								TokenTranslator.prototype = {
							 | 
						|
								    constructor: TokenTranslator,
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Translates a single Esprima token to a single Acorn token. This may be
							 | 
						|
								     * inaccurate due to how templates are handled differently in Esprima and
							 | 
						|
								     * Acorn, but should be accurate for all other tokens.
							 | 
						|
								     * @param {AcornToken} token The Acorn token to translate.
							 | 
						|
								     * @param {Object} extra Espree extra object.
							 | 
						|
								     * @returns {EsprimaToken} The Esprima version of the token.
							 | 
						|
								     */
							 | 
						|
								    translate(token, extra) {
							 | 
						|
								
							 | 
						|
								        const type = token.type,
							 | 
						|
								            tt = this._acornTokTypes;
							 | 
						|
								
							 | 
						|
								        if (type === tt.name) {
							 | 
						|
								            token.type = Token.Identifier;
							 | 
						|
								
							 | 
						|
								            // TODO: See if this is an Acorn bug
							 | 
						|
								            if (token.value === "static") {
							 | 
						|
								                token.type = Token.Keyword;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            if (extra.ecmaVersion > 5 && (token.value === "yield" || token.value === "let")) {
							 | 
						|
								                token.type = Token.Keyword;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								        } else if (type === tt.privateId) {
							 | 
						|
								            token.type = Token.PrivateIdentifier;
							 | 
						|
								
							 | 
						|
								        } else if (type === tt.semi || type === tt.comma ||
							 | 
						|
								                 type === tt.parenL || type === tt.parenR ||
							 | 
						|
								                 type === tt.braceL || type === tt.braceR ||
							 | 
						|
								                 type === tt.dot || type === tt.bracketL ||
							 | 
						|
								                 type === tt.colon || type === tt.question ||
							 | 
						|
								                 type === tt.bracketR || type === tt.ellipsis ||
							 | 
						|
								                 type === tt.arrow || type === tt.jsxTagStart ||
							 | 
						|
								                 type === tt.incDec || type === tt.starstar ||
							 | 
						|
								                 type === tt.jsxTagEnd || type === tt.prefix ||
							 | 
						|
								                 type === tt.questionDot ||
							 | 
						|
								                 (type.binop && !type.keyword) ||
							 | 
						|
								                 type.isAssign) {
							 | 
						|
								
							 | 
						|
								            token.type = Token.Punctuator;
							 | 
						|
								            token.value = this._code.slice(token.start, token.end);
							 | 
						|
								        } else if (type === tt.jsxName) {
							 | 
						|
								            token.type = Token.JSXIdentifier;
							 | 
						|
								        } else if (type.label === "jsxText" || type === tt.jsxAttrValueToken) {
							 | 
						|
								            token.type = Token.JSXText;
							 | 
						|
								        } else if (type.keyword) {
							 | 
						|
								            if (type.keyword === "true" || type.keyword === "false") {
							 | 
						|
								                token.type = Token.Boolean;
							 | 
						|
								            } else if (type.keyword === "null") {
							 | 
						|
								                token.type = Token.Null;
							 | 
						|
								            } else {
							 | 
						|
								                token.type = Token.Keyword;
							 | 
						|
								            }
							 | 
						|
								        } else if (type === tt.num) {
							 | 
						|
								            token.type = Token.Numeric;
							 | 
						|
								            token.value = this._code.slice(token.start, token.end);
							 | 
						|
								        } else if (type === tt.string) {
							 | 
						|
								
							 | 
						|
								            if (extra.jsxAttrValueToken) {
							 | 
						|
								                extra.jsxAttrValueToken = false;
							 | 
						|
								                token.type = Token.JSXText;
							 | 
						|
								            } else {
							 | 
						|
								                token.type = Token.String;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            token.value = this._code.slice(token.start, token.end);
							 | 
						|
								        } else if (type === tt.regexp) {
							 | 
						|
								            token.type = Token.RegularExpression;
							 | 
						|
								            const value = token.value;
							 | 
						|
								
							 | 
						|
								            token.regex = {
							 | 
						|
								                flags: value.flags,
							 | 
						|
								                pattern: value.pattern
							 | 
						|
								            };
							 | 
						|
								            token.value = `/${value.pattern}/${value.flags}`;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return token;
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Function to call during Acorn's onToken handler.
							 | 
						|
								     * @param {AcornToken} token The Acorn token.
							 | 
						|
								     * @param {Object} extra The Espree extra object.
							 | 
						|
								     * @returns {void}
							 | 
						|
								     */
							 | 
						|
								    onToken(token, extra) {
							 | 
						|
								
							 | 
						|
								        const tt = this._acornTokTypes,
							 | 
						|
								            tokens = extra.tokens,
							 | 
						|
								            templateTokens = this._tokens;
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Flushes the buffered template tokens and resets the template
							 | 
						|
								         * tracking.
							 | 
						|
								         * @returns {void}
							 | 
						|
								         * @private
							 | 
						|
								         */
							 | 
						|
								        const translateTemplateTokens = () => {
							 | 
						|
								            tokens.push(convertTemplatePart(this._tokens, this._code));
							 | 
						|
								            this._tokens = [];
							 | 
						|
								        };
							 | 
						|
								
							 | 
						|
								        if (token.type === tt.eof) {
							 | 
						|
								
							 | 
						|
								            // might be one last curlyBrace
							 | 
						|
								            if (this._curlyBrace) {
							 | 
						|
								                tokens.push(this.translate(this._curlyBrace, extra));
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            return;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (token.type === tt.backQuote) {
							 | 
						|
								
							 | 
						|
								            // if there's already a curly, it's not part of the template
							 | 
						|
								            if (this._curlyBrace) {
							 | 
						|
								                tokens.push(this.translate(this._curlyBrace, extra));
							 | 
						|
								                this._curlyBrace = null;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            templateTokens.push(token);
							 | 
						|
								
							 | 
						|
								            // it's the end
							 | 
						|
								            if (templateTokens.length > 1) {
							 | 
						|
								                translateTemplateTokens();
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            return;
							 | 
						|
								        }
							 | 
						|
								        if (token.type === tt.dollarBraceL) {
							 | 
						|
								            templateTokens.push(token);
							 | 
						|
								            translateTemplateTokens();
							 | 
						|
								            return;
							 | 
						|
								        }
							 | 
						|
								        if (token.type === tt.braceR) {
							 | 
						|
								
							 | 
						|
								            // if there's already a curly, it's not part of the template
							 | 
						|
								            if (this._curlyBrace) {
							 | 
						|
								                tokens.push(this.translate(this._curlyBrace, extra));
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // store new curly for later
							 | 
						|
								            this._curlyBrace = token;
							 | 
						|
								            return;
							 | 
						|
								        }
							 | 
						|
								        if (token.type === tt.template || token.type === tt.invalidTemplate) {
							 | 
						|
								            if (this._curlyBrace) {
							 | 
						|
								                templateTokens.push(this._curlyBrace);
							 | 
						|
								                this._curlyBrace = null;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            templateTokens.push(token);
							 | 
						|
								            return;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (this._curlyBrace) {
							 | 
						|
								            tokens.push(this.translate(this._curlyBrace, extra));
							 | 
						|
								            this._curlyBrace = null;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        tokens.push(this.translate(token, extra));
							 | 
						|
								    }
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								// Public
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								export default TokenTranslator;
							 |