summaryrefslogtreecommitdiff
path: root/tools/node_modules/eslint/node_modules/espree/espree.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/node_modules/eslint/node_modules/espree/espree.js')
-rw-r--r--tools/node_modules/eslint/node_modules/espree/espree.js799
1 files changed, 799 insertions, 0 deletions
diff --git a/tools/node_modules/eslint/node_modules/espree/espree.js b/tools/node_modules/eslint/node_modules/espree/espree.js
new file mode 100644
index 0000000000..b2f0a185bd
--- /dev/null
+++ b/tools/node_modules/eslint/node_modules/espree/espree.js
@@ -0,0 +1,799 @@
+/**
+ * @fileoverview Main Espree file that converts Acorn into Esprima output.
+ *
+ * This file contains code from the following MIT-licensed projects:
+ * 1. Acorn
+ * 2. Babylon
+ * 3. Babel-ESLint
+ *
+ * This file also contains code from Esprima, which is BSD licensed.
+ *
+ * Acorn is Copyright 2012-2015 Acorn Contributors (https://github.com/marijnh/acorn/blob/master/AUTHORS)
+ * Babylon is Copyright 2014-2015 various contributors (https://github.com/babel/babel/blob/master/packages/babylon/AUTHORS)
+ * Babel-ESLint is Copyright 2014-2015 Sebastian McKenzie <sebmck@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Esprima is Copyright (c) jQuery Foundation, Inc. and Contributors, All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* eslint no-undefined:0, no-use-before-define: 0 */
+
+"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;
+
+/**
+ * Object.assign polyfill for Node < 4
+ * @param {Object} target The target object
+ * @param {...Object} sources Sources for the object
+ * @returns {Object} `target` after being mutated
+ */
+var assign = Object.assign || function assign(target) {
+ for (var argIndex = 1; argIndex < arguments.length; argIndex++) {
+ if (arguments[argIndex] !== null && typeof arguments[argIndex] === "object") {
+ var keys = Object.keys(arguments[argIndex]);
+
+ for (var keyIndex = 0; keyIndex < keys.length; keyIndex++) {
+ target[keys[keyIndex]] = arguments[argIndex][keys[keyIndex]];
+ }
+ }
+ }
+
+ return target;
+};
+
+/**
+ * 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:
+ 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) {
+ var ecma = extra.ecmaFeatures;
+
+ switch (node.type) {
+ case "ExperimentalSpreadProperty":
+ case "ExperimentalRestProperty":
+ return ecma.experimentalObjectRestSpread;
+
+ 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);
+ }
+
+ // https://github.com/marijnh/acorn/issues/323
+ if (result.type === "TryStatement") {
+ delete result.guardedHandlers;
+ } else if (result.type === "CatchClause") {
+ delete result.guard;
+ }
+
+ // 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);
+ }
+ }
+
+ // Acorn uses undefined instead of null, which affects serialization
+ if (result.type === "Literal" && result.value === undefined) {
+ result.value = null;
+ }
+
+ if (extra.attachComment) {
+ commentAttachment.processComment(result);
+ }
+
+ 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);
+ };
+ });
+
+ // needed for experimental object rest/spread
+ instance.extend("checkLVal", function(checkLVal) {
+
+ return /** @this acorn.Parser */ function(expr, isBinding, checkClashes) {
+
+ if (extra.ecmaFeatures.experimentalObjectRestSpread && expr.type === "ObjectPattern") {
+ for (var i = 0; i < expr.properties.length; i++) {
+ if (expr.properties[i].type.indexOf("Experimental") === -1) {
+ this.checkLVal(expr.properties[i].value, isBinding, checkClashes);
+ }
+ }
+ return undefined;
+ }
+
+ return checkLVal.call(this, expr, isBinding, checkClashes);
+ };
+ });
+
+ 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);
+ };
+ });
+
+ instance.extend("toAssignable", function(toAssignable) {
+
+ return /** @this acorn.Parser */ function(node, isBinding) {
+
+ if (extra.ecmaFeatures.experimentalObjectRestSpread &&
+ node.type === "ObjectExpression"
+ ) {
+ node.type = "ObjectPattern";
+
+ for (var i = 0; i < node.properties.length; i++) {
+ var prop = node.properties[i];
+
+ if (prop.type === "ExperimentalSpreadProperty") {
+ prop.type = "ExperimentalRestProperty";
+ } else if (prop.kind !== "init") {
+ this.raise(prop.key.start, "Object pattern can't contain getter or setter");
+ } else {
+ this.toAssignable(prop.value, isBinding);
+ }
+ }
+
+ return node;
+ } else {
+ return toAssignable.call(this, node, isBinding);
+ }
+ };
+
+ });
+
+ /**
+ * Method to parse an object rest or object spread.
+ * @returns {ASTNode} The node representing object rest or object spread.
+ * @this acorn.Parser
+ */
+ instance.parseObjectRest = function() {
+ var node = this.startNode();
+ this.next();
+ node.argument = this.parseIdent();
+
+ if (this.type === tt.comma) {
+ this.raise(this.start, "Unexpected trailing comma after rest property");
+ }
+
+ return this.finishNode(node, "ExperimentalRestProperty");
+ };
+
+ instance.extend("parseProperty", function(parseProperty) {
+ /**
+ * Override `parseProperty` method to parse rest/spread properties.
+ * @param {boolean} isPattern True if the object is a destructuring pattern.
+ * @param {Object} refDestructuringErrors ?
+ * @returns {ASTNode} The node representing a rest/spread property.
+ * @this acorn.Parser
+ */
+ return function(isPattern, refDestructuringErrors) {
+ if (extra.ecmaFeatures.experimentalObjectRestSpread && this.type === tt.ellipsis) {
+ var prop;
+
+ if (isPattern) {
+ prop = this.parseObjectRest();
+ } else {
+ prop = this.parseSpread();
+ prop.type = "ExperimentalSpreadProperty";
+ }
+
+ return prop;
+ }
+
+ return parseProperty.call(this, isPattern, refDestructuringErrors);
+ };
+ });
+
+ instance.extend("checkPropClash", function(checkPropClash) {
+ /**
+ * Override `checkPropClash` method to avoid clash on rest/spread properties.
+ * @param {ASTNode} prop A property node to check.
+ * @param {Object} propHash Names map.
+ * @returns {void}
+ * @this acorn.Parser
+ */
+ return function(prop, propHash) {
+ if (prop.type === "ExperimentalRestProperty" || prop.type === "ExperimentalSpreadProperty") {
+ return;
+ }
+ checkPropClash.call(this, prop, propHash);
+ };
+ });
+
+ /**
+ * 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;
+ };
+ });
+};
+
+//------------------------------------------------------------------------------
+// Tokenizer
+//------------------------------------------------------------------------------
+
+/**
+ * Tokenizes the given code.
+ * @param {string} code The code to tokenize.
+ * @param {Object} options Options defining how to tokenize.
+ * @returns {Token[]} An array of tokens.
+ * @throws {SyntaxError} If the input code is invalid.
+ * @private
+ */
+function tokenize(code, options) {
+ var toString,
+ tokens,
+ impliedStrict,
+ translator = new TokenTranslator(tt, code);
+
+ toString = String;
+ if (typeof code !== "string" && !(code instanceof String)) {
+ code = toString(code);
+ }
+
+ lookahead = null;
+
+ // Options matching.
+ options = 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 = 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;
+}
+
+//------------------------------------------------------------------------------
+// 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 = 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;
+}
+
+//------------------------------------------------------------------------------
+// Public
+//------------------------------------------------------------------------------
+
+exports.version = require("./package.json").version;
+
+exports.tokenize = tokenize;
+
+exports.parse = parse;
+
+// Deep copy.
+/* istanbul ignore next */
+exports.Syntax = (function() {
+ var name, types = {};
+
+ if (typeof Object.create === "function") {
+ types = Object.create(null);
+ }
+
+ for (name in astNodeTypes) {
+ if (astNodeTypes.hasOwnProperty(name)) {
+ types[name] = astNodeTypes[name];
+ }
+ }
+
+ if (typeof Object.freeze === "function") {
+ Object.freeze(types);
+ }
+
+ return types;
+}());
+
+/* 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;
+}());