diff options
Diffstat (limited to 'tools/node_modules/eslint/node_modules/espree/espree.js')
-rw-r--r-- | tools/node_modules/eslint/node_modules/espree/espree.js | 565 |
1 files changed, 39 insertions, 526 deletions
diff --git a/tools/node_modules/eslint/node_modules/espree/espree.js b/tools/node_modules/eslint/node_modules/espree/espree.js index e50fc5666f..dea35ef083 100644 --- a/tools/node_modules/eslint/node_modules/espree/espree.js +++ b/tools/node_modules/eslint/node_modules/espree/espree.js @@ -58,271 +58,38 @@ "use strict"; -var astNodeTypes = require("./lib/ast-node-types"), - commentAttachment = require("./lib/comment-attachment"), - TokenTranslator = require("./lib/token-translator"), - acornJSX = require("acorn-jsx/inject"), - rawAcorn = require("acorn"); - - -var acorn = acornJSX(rawAcorn); -var DEFAULT_ECMA_VERSION = 5; -var lookahead, - extra, - lastToken; - -/** - * Resets the extra object to its default. - * @returns {void} - * @private - */ -function resetExtra() { - extra = { - tokens: null, - range: false, - loc: false, - comment: false, - comments: [], - tolerant: false, - errors: [], - strict: false, - ecmaFeatures: {}, - ecmaVersion: DEFAULT_ECMA_VERSION, - isModule: false - }; -} - - - -var tt = acorn.tokTypes, - getLineInfo = acorn.getLineInfo; - -// custom type for JSX attribute values -tt.jsxAttrValueToken = {}; - -/** - * Normalize ECMAScript version from the initial config - * @param {number} ecmaVersion ECMAScript version from the initial config - * @returns {number} normalized ECMAScript version - */ -function normalizeEcmaVersion(ecmaVersion) { - if (typeof ecmaVersion === "number") { - var version = ecmaVersion; - - // Calculate ECMAScript edition number from official year version starting with - // ES2015, which corresponds with ES6 (or a difference of 2009). - if (version >= 2015) { - version -= 2009; - } - - switch (version) { - case 3: - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - return version; - - default: - throw new Error("Invalid ecmaVersion."); - } - } else { - return DEFAULT_ECMA_VERSION; - } -} - -/** - * Determines if a node is valid given the set of ecmaFeatures. - * @param {ASTNode} node The node to check. - * @returns {boolean} True if the node is allowed, false if not. - * @private - */ -function isValidNode(node) { - switch (node.type) { - case "ImportDeclaration": - case "ExportNamedDeclaration": - case "ExportDefaultDeclaration": - case "ExportAllDeclaration": - return extra.isModule; - - default: - return true; - } -} - -/** - * Performs last-minute Esprima-specific compatibility checks and fixes. - * @param {ASTNode} result The node to check. - * @returns {ASTNode} The finished node. - * @private - * @this acorn.Parser - */ -function esprimaFinishNode(result) { - // ensure that parsed node was allowed through ecmaFeatures - if (!isValidNode(result)) { - this.unexpected(result.start); - } - - // Acorn doesn't count the opening and closing backticks as part of templates - // so we have to adjust ranges/locations appropriately. - if (result.type === "TemplateElement") { - - // additional adjustment needed if ${ is the last token - var terminalDollarBraceL = this.input.slice(result.end, result.end + 2) === "${"; - - if (result.range) { - result.range[0]--; - result.range[1] += (terminalDollarBraceL ? 2 : 1); - } - - if (result.loc) { - result.loc.start.column--; - result.loc.end.column += (terminalDollarBraceL ? 2 : 1); - } - } - - if (extra.attachComment) { - commentAttachment.processComment(result); +const acorn = require("acorn"); +const jsx = require("acorn-jsx"); +const astNodeTypes = require("./lib/ast-node-types"); +const espree = require("./lib/espree"); + +// To initialize lazily. +const parsers = { + _regular: null, + _jsx: null, + + get regular() { + if (this._regular === null) { + this._regular = acorn.Parser.extend(espree()); + } + return this._regular; + }, + + get jsx() { + if (this._jsx === null) { + this._jsx = acorn.Parser.extend(jsx(), espree()); + } + return this._jsx; + }, + + get(options) { + const useJsx = Boolean( + options && + options.ecmaFeatures && + options.ecmaFeatures.jsx + ); + return useJsx ? this.jsx : this.regular; } - - if (result.type.indexOf("Function") > -1 && !result.generator) { - result.generator = false; - } - - return result; -} - -/** - * Determines if a token is valid given the set of ecmaFeatures. - * @param {acorn.Parser} parser The parser to check. - * @returns {boolean} True if the token is allowed, false if not. - * @private - */ -function isValidToken(parser) { - var ecma = extra.ecmaFeatures; - var type = parser.type; - - switch (type) { - case tt.jsxName: - case tt.jsxText: - case tt.jsxTagStart: - case tt.jsxTagEnd: - return ecma.jsx; - - // https://github.com/ternjs/acorn/issues/363 - case tt.regexp: - if (extra.ecmaVersion < 6 && parser.value.flags && parser.value.flags.indexOf("y") > -1) { - return false; - } - - return true; - - default: - return true; - } -} - -/** - * Injects esprimaFinishNode into the finishNode process. - * @param {Function} finishNode Original finishNode function. - * @returns {ASTNode} The finished node. - * @private - */ -function wrapFinishNode(finishNode) { - return /** @this acorn.Parser */ function(node, type, pos, loc) { - var result = finishNode.call(this, node, type, pos, loc); - return esprimaFinishNode.call(this, result); - }; -} - -acorn.plugins.espree = function(instance) { - - instance.extend("finishNode", wrapFinishNode); - - instance.extend("finishNodeAt", wrapFinishNode); - - instance.extend("next", function(next) { - return /** @this acorn.Parser */ function() { - if (!isValidToken(this)) { - this.unexpected(); - } - return next.call(this); - }; - }); - - instance.extend("parseTopLevel", function(parseTopLevel) { - return /** @this acorn.Parser */ function(node) { - if (extra.ecmaFeatures.impliedStrict && this.options.ecmaVersion >= 5) { - this.strict = true; - } - return parseTopLevel.call(this, node); - }; - }); - - /** - * Overwrites the default raise method to throw Esprima-style errors. - * @param {int} pos The position of the error. - * @param {string} message The error message. - * @throws {SyntaxError} A syntax error. - * @returns {void} - */ - instance.raise = instance.raiseRecoverable = function(pos, message) { - var loc = getLineInfo(this.input, pos); - var err = new SyntaxError(message); - err.index = pos; - err.lineNumber = loc.line; - err.column = loc.column + 1; // acorn uses 0-based columns - throw err; - }; - - /** - * Overwrites the default unexpected method to throw Esprima-style errors. - * @param {int} pos The position of the error. - * @throws {SyntaxError} A syntax error. - * @returns {void} - */ - instance.unexpected = function(pos) { - var message = "Unexpected token"; - - if (pos !== null && pos !== undefined) { - this.pos = pos; - - if (this.options.locations) { - while (this.pos < this.lineStart) { - this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1; - --this.curLine; - } - } - - this.nextToken(); - } - - if (this.end > this.start) { - message += " " + this.input.slice(this.start, this.end); - } - - this.raise(this.start, message); - }; - - /* - * Esprima-FB represents JSX strings as tokens called "JSXText", but Acorn-JSX - * uses regular tt.string without any distinction between this and regular JS - * strings. As such, we intercept an attempt to read a JSX string and set a flag - * on extra so that when tokens are converted, the next token will be switched - * to JSXText via onToken. - */ - instance.extend("jsx_readString", function(jsxReadString) { - return /** @this acorn.Parser */ function(quote) { - var result = jsxReadString.call(this, quote); - if (this.type === tt.string) { - extra.jsxAttrValueToken = true; - } - - return result; - }; - }); }; //------------------------------------------------------------------------------ @@ -338,266 +105,30 @@ acorn.plugins.espree = function(instance) { * @private */ function tokenize(code, options) { - var toString, - tokens, - impliedStrict, - translator = new TokenTranslator(tt, code); + const Parser = parsers.get(options); - toString = String; - if (typeof code !== "string" && !(code instanceof String)) { - code = toString(code); + // Ensure to collect tokens. + if (!options || options.tokens !== true) { + options = Object.assign({}, options, { tokens: true }); } - lookahead = null; - - // Options matching. - options = Object.assign({}, options); - - var acornOptions = { - ecmaVersion: DEFAULT_ECMA_VERSION, - plugins: { - espree: true - } - }; - - resetExtra(); - - // Of course we collect tokens here. - options.tokens = true; - extra.tokens = []; - - extra.range = (typeof options.range === "boolean") && options.range; - acornOptions.ranges = extra.range; - - extra.loc = (typeof options.loc === "boolean") && options.loc; - acornOptions.locations = extra.loc; - - extra.comment = typeof options.comment === "boolean" && options.comment; - - if (extra.comment) { - acornOptions.onComment = function() { - var comment = convertAcornCommentToEsprimaComment.apply(this, arguments); - extra.comments.push(comment); - }; - } - - extra.tolerant = typeof options.tolerant === "boolean" && options.tolerant; - - acornOptions.ecmaVersion = extra.ecmaVersion = normalizeEcmaVersion(options.ecmaVersion); - - // apply parsing flags - if (options.ecmaFeatures && typeof options.ecmaFeatures === "object") { - extra.ecmaFeatures = Object.assign({}, options.ecmaFeatures); - impliedStrict = extra.ecmaFeatures.impliedStrict; - extra.ecmaFeatures.impliedStrict = typeof impliedStrict === "boolean" && impliedStrict; - } - - try { - var tokenizer = acorn.tokenizer(code, acornOptions); - while ((lookahead = tokenizer.getToken()).type !== tt.eof) { - translator.onToken(lookahead, extra); - } - - // filterTokenLocation(); - tokens = extra.tokens; - - if (extra.comment) { - tokens.comments = extra.comments; - } - if (extra.tolerant) { - tokens.errors = extra.errors; - } - } catch (e) { - throw e; - } - return tokens; + return new Parser(options, code).tokenize(); } //------------------------------------------------------------------------------ // Parser //------------------------------------------------------------------------------ - - -/** - * Converts an Acorn comment to a Esprima comment. - * @param {boolean} block True if it's a block comment, false if not. - * @param {string} text The text of the comment. - * @param {int} start The index at which the comment starts. - * @param {int} end The index at which the comment ends. - * @param {Location} startLoc The location at which the comment starts. - * @param {Location} endLoc The location at which the comment ends. - * @returns {Object} The comment object. - * @private - */ -function convertAcornCommentToEsprimaComment(block, text, start, end, startLoc, endLoc) { - var comment = { - type: block ? "Block" : "Line", - value: text - }; - - if (typeof start === "number") { - comment.start = start; - comment.end = end; - comment.range = [start, end]; - } - - if (typeof startLoc === "object") { - comment.loc = { - start: startLoc, - end: endLoc - }; - } - - return comment; -} - /** * Parses the given code. * @param {string} code The code to tokenize. * @param {Object} options Options defining how to tokenize. * @returns {ASTNode} The "Program" AST node. * @throws {SyntaxError} If the input code is invalid. - * @private */ function parse(code, options) { - var program, - toString = String, - translator, - impliedStrict, - acornOptions = { - ecmaVersion: DEFAULT_ECMA_VERSION, - plugins: { - espree: true - } - }; - - lastToken = null; - - if (typeof code !== "string" && !(code instanceof String)) { - code = toString(code); - } - - resetExtra(); - commentAttachment.reset(); - - if (typeof options !== "undefined") { - extra.range = (typeof options.range === "boolean") && options.range; - extra.loc = (typeof options.loc === "boolean") && options.loc; - extra.attachComment = (typeof options.attachComment === "boolean") && options.attachComment; - - if (extra.loc && options.source !== null && options.source !== undefined) { - extra.source = toString(options.source); - } - - if (typeof options.tokens === "boolean" && options.tokens) { - extra.tokens = []; - translator = new TokenTranslator(tt, code); - } - if (typeof options.comment === "boolean" && options.comment) { - extra.comment = true; - extra.comments = []; - } - if (typeof options.tolerant === "boolean" && options.tolerant) { - extra.errors = []; - } - if (extra.attachComment) { - extra.range = true; - extra.comments = []; - commentAttachment.reset(); - } - - acornOptions.ecmaVersion = extra.ecmaVersion = normalizeEcmaVersion(options.ecmaVersion); - - if (options.sourceType === "module") { - extra.isModule = true; - - // modules must be in 6 at least - if (acornOptions.ecmaVersion < 6) { - acornOptions.ecmaVersion = 6; - extra.ecmaVersion = 6; - } - - acornOptions.sourceType = "module"; - } - - // apply parsing flags after sourceType to allow overriding - if (options.ecmaFeatures && typeof options.ecmaFeatures === "object") { - extra.ecmaFeatures = Object.assign({}, options.ecmaFeatures); - impliedStrict = extra.ecmaFeatures.impliedStrict; - extra.ecmaFeatures.impliedStrict = typeof impliedStrict === "boolean" && impliedStrict; - if (options.ecmaFeatures.globalReturn) { - acornOptions.allowReturnOutsideFunction = true; - } - } - - - acornOptions.onToken = function(token) { - if (extra.tokens) { - translator.onToken(token, extra); - } - if (token.type !== tt.eof) { - lastToken = token; - } - }; - - if (extra.attachComment || extra.comment) { - acornOptions.onComment = function() { - var comment = convertAcornCommentToEsprimaComment.apply(this, arguments); - extra.comments.push(comment); - - if (extra.attachComment) { - commentAttachment.addComment(comment); - } - }; - } - - if (extra.range) { - acornOptions.ranges = true; - } - - if (extra.loc) { - acornOptions.locations = true; - } - - if (extra.ecmaFeatures.jsx) { - // Should process jsx plugin before espree plugin. - acornOptions.plugins = { - jsx: true, - espree: true - }; - } - } - - program = acorn.parse(code, acornOptions); - program.sourceType = extra.isModule ? "module" : "script"; - - if (extra.comment || extra.attachComment) { - program.comments = extra.comments; - } - - if (extra.tokens) { - program.tokens = extra.tokens; - } - - /* - * Adjust opening and closing position of program to match Esprima. - * Acorn always starts programs at range 0 whereas Esprima starts at the - * first AST node's start (the only real difference is when there's leading - * whitespace or leading comments). Acorn also counts trailing whitespace - * as part of the program whereas Esprima only counts up to the last token. - */ - if (program.range) { - program.range[0] = program.body.length ? program.body[0].range[0] : program.range[0]; - program.range[1] = lastToken ? lastToken.range[1] : program.range[1]; - } - - if (program.loc) { - program.loc.start = program.body.length ? program.body[0].loc.start : program.loc.start; - program.loc.end = lastToken ? lastToken.loc.end : program.loc.end; - } - - return program; + const Parser = parsers.get(options); + return new Parser(options, code).parse(); } //------------------------------------------------------------------------------ @@ -634,23 +165,5 @@ exports.Syntax = (function() { /* istanbul ignore next */ exports.VisitorKeys = (function() { - var visitorKeys = require("./lib/visitor-keys"); - var name, - keys = {}; - - if (typeof Object.create === "function") { - keys = Object.create(null); - } - - for (name in visitorKeys) { - if (visitorKeys.hasOwnProperty(name)) { - keys[name] = visitorKeys[name]; - } - } - - if (typeof Object.freeze === "function") { - Object.freeze(keys); - } - - return keys; + return require("eslint-visitor-keys").KEYS; }()); |