diff --git a/lib/jsdoc/src/astbuilder.js b/lib/jsdoc/src/astbuilder.js index 48a8251f..a2869fbb 100644 --- a/lib/jsdoc/src/astbuilder.js +++ b/lib/jsdoc/src/astbuilder.js @@ -63,12 +63,14 @@ var parserOptions = exports.parserOptions = { arrowFunctions: true, binaryLiterals: true, blockBindings: true, + classes: true, defaultParams: true, destructuring: true, forOf: true, generators: true, globalReturn: true, jsx: false, + modules: true, objectLiteralComputedProperties: true, objectLiteralDuplicateProperties: true, objectLiteralShorthandMethods: true, diff --git a/lib/jsdoc/src/syntax.js b/lib/jsdoc/src/syntax.js index 3780129d..94e2d70f 100644 --- a/lib/jsdoc/src/syntax.js +++ b/lib/jsdoc/src/syntax.js @@ -6,6 +6,7 @@ exports.Syntax = { ArrayPattern: 'ArrayPattern', ArrowFunctionExpression: 'ArrowFunctionExpression', AssignmentExpression: 'AssignmentExpression', + AssignmentPattern: 'AssignmentPattern', BinaryExpression: 'BinaryExpression', BlockStatement: 'BlockStatement', BreakStatement: 'BreakStatement', @@ -21,8 +22,9 @@ exports.Syntax = { DebuggerStatement: 'DebuggerStatement', DoWhileStatement: 'DoWhileStatement', EmptyStatement: 'EmptyStatement', - ExportBatchSpecifier: 'ExportBatchSpecifier', - ExportDeclaration: 'ExportDeclaration', + ExportAllDeclaration: 'ExportAllDeclaration', + ExportDefaultDeclaration: 'ExportDefaultDeclaration', + ExportNamedDeclaration: 'ExportNamedDeclaration', ExportSpecifier: 'ExportSpecifier', ExpressionStatement: 'ExpressionStatement', ForInStatement: 'ForInStatement', @@ -33,6 +35,8 @@ exports.Syntax = { Identifier: 'Identifier', IfStatement: 'IfStatement', ImportDeclaration: 'ImportDeclaration', + ImportDefaultSpecifier: 'ImportDefaultSpecifier', + ImportNamespaceSpecifier: 'ImportNamespaceSpecifier', ImportSpecifier: 'ImportSpecifier', LabeledStatement: 'LabeledStatement', LetStatement: 'LetStatement', // TODO: update Rhino to use VariableDeclaration diff --git a/lib/jsdoc/src/visitor.js b/lib/jsdoc/src/visitor.js index 9c081bce..35439373 100644 --- a/lib/jsdoc/src/visitor.js +++ b/lib/jsdoc/src/visitor.js @@ -515,10 +515,13 @@ Visitor.prototype.makeSymbolFoundEvent = function(node, parser, filename) { case Syntax.ClassBody: case Syntax.ClassDeclaration: case Syntax.ClassExpression: - case Syntax.ExportBatchSpecifier: - case Syntax.ExportDeclaration: + case Syntax.ExportAllDeclaration: + case Syntax.ExportDefaultDeclaration: + case Syntax.ExportNamedDeclaration: case Syntax.ExportSpecifier: case Syntax.ImportDeclaration: + case Syntax.ImportDefaultSpecifier: + case Syntax.ImportNamespaceSpecifier: case Syntax.ImportSpecifier: case Syntax.MethodDefinition: case Syntax.ModuleDeclaration: diff --git a/lib/jsdoc/src/walker.js b/lib/jsdoc/src/walker.js index 8042ad41..6e9914ca 100644 --- a/lib/jsdoc/src/walker.js +++ b/lib/jsdoc/src/walker.js @@ -93,6 +93,8 @@ walkers[Syntax.AssignmentExpression] = function(node, parent, state, cb) { cb(node.right, node, state); }; +walkers[Syntax.AssignmentPattern] = walkers[Syntax.AssignmentExpression]; + walkers[Syntax.BinaryExpression] = function(node, parent, state, cb) { cb(node.left, node, state); cb(node.right, node, state); @@ -171,22 +173,28 @@ walkers[Syntax.DoWhileStatement] = function(node, parent, state, cb) { walkers[Syntax.EmptyStatement] = leafNode; -walkers[Syntax.ExportBatchSpecifier] = leafNode; +walkers[Syntax.ExportAllDeclaration] = function(node, parent, state, cb) { + if (node.source) { + cb(node.source, node, state); + } +}; -walkers[Syntax.ExportDeclaration] = function(node, parent, state, cb) { +walkers[Syntax.ExportDefaultDeclaration] = function(node, parent, state, cb) { + if (node.declaration) { + cb(node.declaration, node, state); + } +}; + +walkers[Syntax.ExportNamedDeclaration] = function(node, parent, state, cb) { var i; var l; if (node.declaration) { - for (i = 0, l = node.declaration.length; i < l; i++) { - cb(node.declaration[i], node, state); - } + cb(node.declaration, node, state); } - if (node.specifiers) { - for (i = 0, l = node.specifiers.length; i < l; i++) { - cb(node.specifiers[i], node, state); - } + for (i = 0, l = node.specifiers.length; i < l; i++) { + cb(node.specifiers[i], node, state); } if (node.source) { @@ -195,12 +203,12 @@ walkers[Syntax.ExportDeclaration] = function(node, parent, state, cb) { }; walkers[Syntax.ExportSpecifier] = function(node, parent, state, cb) { - if (node.id) { - cb(node.id, node, state); + if (node.exported) { + cb(node.exported, node, state); } - if (node.name) { - cb(node.name, node, state); + if (node.local) { + cb(node.local, node, state); } }; @@ -261,6 +269,14 @@ walkers[Syntax.ImportDeclaration] = function(node, parent, state, cb) { } }; +walkers[Syntax.ImportDefaultSpecifier] = function(node, parent, state, cb) { + if (node.local) { + cb(node.local, node, state); + } +}; + +walkers[Syntax.ImportNamespaceSpecifier] = walkers[Syntax.ImportDefaultSpecifier]; + walkers[Syntax.ImportSpecifier] = walkers[Syntax.ExportSpecifier]; walkers[Syntax.LabeledStatement] = function(node, parent, state, cb) { diff --git a/node_modules/espree/espree.js b/node_modules/espree/espree.js index c5b08649..97e11b58 100644 --- a/node_modules/espree/espree.js +++ b/node_modules/espree/espree.js @@ -42,7 +42,8 @@ var syntax = require("./lib/syntax"), defaultFeatures = require("./lib/features"), Messages = require("./lib/messages"), XHTMLEntities = require("./lib/xhtml-entities"), - StringMap = require("./lib/string-map"); + StringMap = require("./lib/string-map"), + commentAttachment = require("./lib/comment-attachment"); var Token = tokenInfo.Token, TokenName = tokenInfo.TokenName, @@ -105,9 +106,9 @@ function addComment(type, value, start, end, loc) { comment.loc = loc; } extra.comments.push(comment); + if (extra.attachComment) { - extra.leadingComments.push(comment); - extra.trailingComments.push(comment); + commentAttachment.addComment(comment); } } @@ -441,6 +442,14 @@ function scanPunctuator() { extra.openCurlyToken = extra.tokens.length; } } + + // 123 is {, 125 is } + if (code === 123) { + state.curlyStack.push("{"); + } else if (code === 125) { + state.curlyStack.pop(); + } + return { type: Token.Punctuator, value: String.fromCharCode(code), @@ -695,7 +704,6 @@ function scanOctalLiteral(prefix, start) { number = ""; } - while (index < length) { if (!syntax.isOctalDigit(source[index])) { break; @@ -715,7 +723,7 @@ function scanOctalLiteral(prefix, start) { return { type: Token.NumericLiteral, value: parseInt(number, 8), - octal: true, + octal: octal, lineNumber: lineNumber, lineStart: lineStart, range: [start, index] @@ -993,6 +1001,14 @@ function scanTemplate() { throwError({}, Messages.UnexpectedToken, "ILLEGAL"); } + if (!tail) { + state.curlyStack.push("template"); + } + + if (!head) { + state.curlyStack.pop(); + } + return { type: Token.Template, value: { @@ -1030,10 +1046,6 @@ function scanTemplateElement(options) { template = scanTemplate(); - if (!template.tail) { - extra.curlies.push("template"); - } - peek(); return template; @@ -1385,8 +1397,7 @@ function advance() { // template strings start with backtick (96) or open curly (125) but only if the open // curly closes a previously opened curly from a template. - if (ch === 96 || (ch === 125 && extra.curlies[extra.curlies.length - 1] === "template")) { - extra.curlies.pop(); + if (ch === 96 || (ch === 125 && state.curlyStack[state.curlyStack.length - 1] === "template")) { return scanTemplate(); } } @@ -1475,18 +1486,18 @@ function lex() { if (token.type === Token.Template) { if (token.tail) { - extra.curlies.pop(); + state.curlyStack.pop(); } else { - extra.curlies.push("template"); + state.curlyStack.push("template"); } } if (token.value === "{") { - extra.curlies.push("{"); + state.curlyStack.push("{"); } if (token.value === "}") { - extra.curlies.pop(); + state.curlyStack.pop(); } return token; @@ -1957,7 +1968,7 @@ function parseJSXElement() { * Applies location information to the given node by using the given marker. * The marker indicates the point at which the node is said to have to begun * in the source code. - * @param {Object} marker The market to use for the node. + * @param {Object} marker The marker to use for the node. * @param {ASTNode} node The AST node to apply location information to. * @returns {ASTNode} The node that was passed in. * @private @@ -1989,7 +2000,7 @@ function markerApply(marker, node) { // attach leading and trailing comments if requested if (extra.attachComment) { - processComment(node); + commentAttachment.processComment(node); } return node; @@ -2043,115 +2054,6 @@ function markerCreatePreserveWhitespace() { // Syntax Tree Delegate //------------------------------------------------------------------------------ - -function processComment(node) { - var lastChild, - trailingComments, - i; - - if (node.type === astNodeTypes.Program) { - if (node.body.length > 0) { - return; - } - } - - if (extra.trailingComments.length > 0) { - - /* - * If the first comment in trailingComments comes after the - * current node, then we're good - all comments in the array will - * come after the node and so it's safe to add then as official - * trailingComments. - */ - if (extra.trailingComments[0].range[0] >= node.range[1]) { - trailingComments = extra.trailingComments; - extra.trailingComments = []; - } else { - - /* - * Otherwise, if the first comment doesn't come after the - * current node, that means we have a mix of leading and trailing - * comments in the array and that leadingComments contains the - * same items as trailingComments. Reset trailingComments to - * zero items and we'll handle this by evaluating leadingComments - * later. - */ - extra.trailingComments.length = 0; - } - } else { - if (extra.bottomRightStack.length > 0 && - extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments && - extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) { - trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; - delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; - } - } - - // Eating the stack. - while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) { - lastChild = extra.bottomRightStack.pop(); - } - - if (lastChild) { - if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) { - node.leadingComments = lastChild.leadingComments; - delete lastChild.leadingComments; - } - } else if (extra.leadingComments.length > 0) { - - if (extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) { - node.leadingComments = extra.leadingComments; - extra.leadingComments = []; - } else { - - // https://github.com/eslint/espree/issues/2 - - /* - * In special cases, such as return (without a value) and - * debugger, all comments will end up as leadingComments and - * will otherwise be eliminated. This extra step runs when the - * bottomRightStack is empty and there are comments left - * in leadingComments. - * - * This loop figures out the stopping point between the actual - * leading and trailing comments by finding the location of the - * first comment that comes after the given node. - */ - for (i = 0; i < extra.leadingComments.length; i++) { - if (extra.leadingComments[i].range[1] > node.range[0]) { - break; - } - } - - /* - * Split the array based on the location of the first comment - * that comes after the node. Keep in mind that this could - * result in an empty array, and if so, the array must be - * deleted. - */ - node.leadingComments = extra.leadingComments.slice(0, i); - if (node.leadingComments.length === 0) { - delete node.leadingComments; - } - - /* - * Similarly, trailing comments are attached later. The variable - * must be reset to null if there are no trailing comments. - */ - trailingComments = extra.leadingComments.slice(i); - if (trailingComments.length === 0) { - trailingComments = null; - } - } - } - - if (trailingComments) { - node.trailingComments = trailingComments; - } - - extra.bottomRightStack.push(node); -} - // Return true if there is a line terminator before the next token. function peekLineTerminator() { @@ -2172,6 +2074,7 @@ function peekLineTerminator() { // Throw an exception function throwError(token, messageFormat) { + var error, args = Array.prototype.slice.call(arguments, 2), msg = messageFormat.replace( @@ -2353,11 +2256,7 @@ function parseArrayInitialiser() { } else { tmp = parseSpreadOrAssignmentExpression(); elements.push(tmp); - if (tmp && tmp.type === astNodeTypes.SpreadElement) { - if (!match("]")) { - throwError({}, Messages.ElementAfterSpreadElement); - } - } else if (!(match("]"))) { + if (!(match("]"))) { expect(","); // handles the common case of comma-separated values } } @@ -2370,14 +2269,13 @@ function parseArrayInitialiser() { // 11.1.5 Object Initialiser -function parsePropertyFunction(options) { +function parsePropertyFunction(paramInfo, options) { var previousStrict = strict, previousYieldAllowed = state.yieldAllowed, - params = options.params || [], - defaults = options.defaults || [], + generator = options ? options.generator : false, body; - state.yieldAllowed = options.generator; + state.yieldAllowed = generator; /* * Esprima uses parseConciseBody() here, which is incorrect. Object literal @@ -2385,8 +2283,12 @@ function parsePropertyFunction(options) { */ body = parseFunctionSourceElements(); - if (options.name && strict && syntax.isRestrictedWord(params[0].name)) { - throwErrorTolerant(options.name, Messages.StrictParamName); + if (strict && paramInfo.firstRestricted) { + throwErrorTolerant(paramInfo.firstRestricted, Messages.StrictParamName); + } + + if (strict && paramInfo.stricted) { + throwErrorTolerant(paramInfo.stricted, paramInfo.message); } strict = previousStrict; @@ -2394,11 +2296,11 @@ function parsePropertyFunction(options) { return markerApply(options.marker, astNodeFactory.createFunctionExpression( null, - params, - defaults, + paramInfo.params, + paramInfo.defaults, body, - options.rest || null, - options.generator, + paramInfo.rest, + generator, body.type !== astNodeTypes.BlockStatement )); } @@ -2406,21 +2308,18 @@ function parsePropertyFunction(options) { function parsePropertyMethodFunction(options) { var previousStrict = strict, marker = markerCreate(), - tmp, + params, method; strict = true; - tmp = parseParams(); + params = parseParams(); - if (tmp.stricted) { - throwErrorTolerant(tmp.stricted, tmp.message); + if (params.stricted) { + throwErrorTolerant(params.stricted, params.message); } - method = parsePropertyFunction({ - params: tmp.params, - defaults: tmp.defaults, - rest: tmp.rest, + method = parsePropertyFunction(params, { generator: options ? options.generator : false, marker: marker }); @@ -2433,36 +2332,162 @@ function parsePropertyMethodFunction(options) { function parseObjectPropertyKey() { var marker = markerCreate(), token = lex(), - propertyKey, + allowObjectLiteralComputed = extra.ecmaFeatures.objectLiteralComputedProperties, + expr, result; // Note: This function is called only from parseObjectProperty(), where // EOF and Punctuator tokens are already filtered out. - if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { - if (strict && token.octal) { - throwErrorTolerant(token, Messages.StrictOctalLiteral); - } - return markerApply(marker, astNodeFactory.createLiteralFromSource(token, source)); + switch (token.type) { + case Token.StringLiteral: + case Token.NumericLiteral: + if (strict && token.octal) { + throwErrorTolerant(token, Messages.StrictOctalLiteral); + } + return markerApply(marker, astNodeFactory.createLiteralFromSource(token, source)); + + case Token.Identifier: + case Token.BooleanLiteral: + case Token.NullLiteral: + case Token.Keyword: + return markerApply(marker, astNodeFactory.createIdentifier(token.value)); + + case Token.Punctuator: + if ((!state.inObjectLiteral || allowObjectLiteralComputed) && + token.value === "[") { + // For computed properties we should skip the [ and ], and + // capture in marker only the assignment expression itself. + marker = markerCreate(); + expr = parseAssignmentExpression(); + result = markerApply(marker, expr); + expect("]"); + return result; + } + + // no default } - if (extra.ecmaFeatures.objectLiteralComputedProperties && - token.type === Token.Punctuator && token.value === "[" - ) { - // For computed properties we should skip the [ and ], and - // capture in marker only the assignment expression itself. - marker = markerCreate(); - propertyKey = parseAssignmentExpression(); - result = markerApply(marker, propertyKey); - expect("]"); - return result; - } - - return markerApply(marker, astNodeFactory.createIdentifier(token.value)); + throwUnexpected(token); } +function lookaheadPropertyName() { + switch (lookahead.type) { + case Token.Identifier: + case Token.StringLiteral: + case Token.BooleanLiteral: + case Token.NullLiteral: + case Token.NumericLiteral: + case Token.Keyword: + return true; + case Token.Punctuator: + return lookahead.value === "["; + // no default + } + return false; +} + +// This function is to try to parse a MethodDefinition as defined in 14.3. But in the case of object literals, +// it might be called at a position where there is in fact a short hand identifier pattern or a data property. +// This can only be determined after we consumed up to the left parentheses. +// In order to avoid back tracking, it returns `null` if the position is not a MethodDefinition and the caller +// is responsible to visit other options. +function tryParseMethodDefinition(token, key, computed, marker) { + var value, options, methodMarker; + + if (token.type === Token.Identifier) { + // check for `get` and `set`; + + if (token.value === "get" && lookaheadPropertyName()) { + + computed = match("["); + key = parseObjectPropertyKey(); + methodMarker = markerCreate(); + expect("("); + expect(")"); + + value = parsePropertyFunction({ + params: [], + defaults: [], + stricted: null, + firstRestricted: null, + message: null, + rest: null + }, { + marker: methodMarker + }); + + return markerApply(marker, astNodeFactory.createProperty("get", key, value, false, false, computed)); + + } else if (token.value === "set" && lookaheadPropertyName()) { + computed = match("["); + key = parseObjectPropertyKey(); + methodMarker = markerCreate(); + expect("("); + + options = { + params: [], + defaultCount: 0, + defaults: [], + stricted: null, + firstRestricted: null, + paramSet: new StringMap(), + rest: null + }; + if (match(")")) { + throwErrorTolerant(lookahead, Messages.UnexpectedToken); + } else { + parseParam(options); + if (options.defaultCount === 0) { + options.defaults = []; + } + } + expect(")"); + + value = parsePropertyFunction(options, { marker: methodMarker }); + return markerApply(marker, astNodeFactory.createProperty("set", key, value, false, false, computed)); + } + } + + if (match("(")) { + value = parsePropertyMethodFunction(); + return markerApply(marker, astNodeFactory.createProperty("init", key, value, true, false, computed)); + } + + // Not a MethodDefinition. + return null; +} + +/** + * Parses Generator Properties + * @param {ASTNode} key The property key (usually an identifier). + * @param {Object} marker The marker to use for the node. + * @returns {ASTNode} The generator property node. + */ +function parseGeneratorProperty(key, marker) { + + var computed = (lookahead.type === Token.Punctuator && lookahead.value === "["); + + if (!match("(")) { + throwUnexpected(lex()); + } + + return markerApply( + marker, + astNodeFactory.createProperty( + "init", + key, + parsePropertyMethodFunction({ generator: true }), + true, + false, + computed + ) + ); +} + +// TODO(nzakas): Update to match Esprima function parseObjectProperty() { - var token, key, id, param, computed, methodMarker; + var token, key, id, computed, methodMarker, options; var allowComputed = extra.ecmaFeatures.objectLiteralComputedProperties, allowMethod = extra.ecmaFeatures.objectLiteralShorthandMethods, allowShorthand = extra.ecmaFeatures.objectLiteralShorthandProperties, @@ -2487,13 +2512,15 @@ function parseObjectProperty() { methodMarker = markerCreate(); expect("("); expect(")"); + return markerApply( marker, astNodeFactory.createProperty( "get", key, parsePropertyFunction({ - generator: false, + generator: false + }, { marker: methodMarker }), false, @@ -2508,18 +2535,34 @@ function parseObjectProperty() { key = parseObjectPropertyKey(); methodMarker = markerCreate(); expect("("); - token = lookahead; - param = [ parseVariableIdentifier() ]; + + options = { + params: [], + defaultCount: 0, + defaults: [], + stricted: null, + firstRestricted: null, + paramSet: new StringMap(), + rest: null + }; + + if (match(")")) { + throwErrorTolerant(lookahead, Messages.UnexpectedToken, lookahead.value); + } else { + parseParam(options); + if (options.defaultCount === 0) { + options.defaults = []; + } + } + expect(")"); + return markerApply( marker, astNodeFactory.createProperty( "set", key, - parsePropertyFunction({ - params: param, - generator: false, - name: token, + parsePropertyFunction(options, { marker: methodMarker }), false, @@ -2560,6 +2603,23 @@ function parseObjectProperty() { ); } + // destructuring defaults (shorthand syntax) + if (allowDestructuring && match("=")) { + lex(); + var value = parseAssignmentExpression(); + var prop = markerApply(marker, astNodeFactory.createAssignmentExpression("=", id, value)); + prop.type = astNodeTypes.AssignmentPattern; + var fullProperty = astNodeFactory.createProperty( + "init", + id, + prop, + false, + true, // shorthand + computed + ); + return markerApply(marker, fullProperty); + } + /* * Only other possibility is that this is a shorthand property. Computed * properties cannot use shorthand notation, so that's a syntax error. @@ -2584,32 +2644,17 @@ function parseObjectProperty() { ); } - // only possibility in this branch is a generator + // only possibility in this branch is a shorthand generator if (token.type === Token.EOF || token.type === Token.Punctuator) { - if (!allowGenerators || !match("*")) { + if (!allowGenerators || !match("*") || !allowMethod) { throwUnexpected(token); } - lex(); - computed = (lookahead.type === Token.Punctuator && lookahead.value === "["); + lex(); id = parseObjectPropertyKey(); - if (!match("(")) { - throwUnexpected(lex()); - } - - return markerApply( - marker, - astNodeFactory.createProperty( - "init", - id, - parsePropertyMethodFunction({ generator: true }), - true, - false, - computed - ) - ); + return parseGeneratorProperty(id, marker); } @@ -2672,8 +2717,11 @@ function parseObjectInitialiser() { propertyFn, kind, storedKind, + previousInObjectLiteral = state.inObjectLiteral, kindMap = new StringMap(); + state.inObjectLiteral = true; + expect("{"); while (!match("}")) { @@ -2720,6 +2768,8 @@ function parseObjectInitialiser() { expect("}"); + state.inObjectLiteral = previousInObjectLiteral; + return markerApply(marker, astNodeFactory.createObjectExpression(properties)); } @@ -2784,7 +2834,8 @@ function parsePrimaryExpression() { var type, token, expr, marker, allowJSX = extra.ecmaFeatures.jsx, - allowSuper = extra.ecmaFeatures.superInFunctions; + allowClasses = extra.ecmaFeatures.classes, + allowSuper = allowClasses || extra.ecmaFeatures.superInFunctions; if (match("(")) { return parseGroupExpression(); @@ -2824,11 +2875,16 @@ function parsePrimaryExpression() { } if (matchKeyword("this")) { + marker = markerCreate(); lex(); - expr = astNodeFactory.createThisExpression(); - } else { - throwUnexpected(lex()); + return markerApply(marker, astNodeFactory.createThisExpression()); } + + if (allowClasses && matchKeyword("class")) { + return parseClassExpression(); + } + + throwUnexpected(lex()); } else if (type === Token.BooleanLiteral) { token = lex(); token.value = (token.value === "true"); @@ -2867,8 +2923,6 @@ function parseArguments() { if (match(")")) { break; - } else if (arg.type === astNodeTypes.SpreadElement) { - throwError({}, Messages.ElementAfterSpreadElement); } expect(","); @@ -3350,9 +3404,15 @@ function reinterpretAsAssignmentBindingPattern(expr) { if (expr.argument.type === astNodeTypes.ObjectPattern) { throwErrorTolerant({}, Messages.ObjectPatternAsSpread); } + } else if (expr.type === "AssignmentExpression" && expr.operator === "=") { + expr.type = astNodeTypes.AssignmentPattern; } else { /* istanbul ignore else */ - if (expr.type !== astNodeTypes.MemberExpression && expr.type !== astNodeTypes.CallExpression && expr.type !== astNodeTypes.NewExpression) { + if (expr.type !== astNodeTypes.MemberExpression && + expr.type !== astNodeTypes.CallExpression && + expr.type !== astNodeTypes.NewExpression && + expr.type !== astNodeTypes.AssignmentPattern + ) { throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } } @@ -3393,7 +3453,9 @@ function reinterpretAsDestructuredParameter(options, expr) { throwErrorTolerant({}, Messages.InvalidLHSInFormalsList); } validateParam(options, expr.argument, expr.argument.name); - } else { + } else if (expr.type === astNodeTypes.AssignmentExpression && expr.operator === "=") { + expr.type = astNodeTypes.AssignmentPattern; + } else if (expr.type !== astNodeTypes.AssignmentPattern) { throwError({}, Messages.InvalidLHSInFormalsList); } } @@ -3552,7 +3614,11 @@ function parseVariableIdentifier() { token = lex(); if (token.type !== Token.Identifier) { - throwUnexpected(token); + if (strict && token.type === Token.Keyword && syntax.isStrictModeReservedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictReservedWord); + } else { + throwUnexpected(token); + } } return markerApply(marker, astNodeFactory.createIdentifier(token.value)); @@ -4092,14 +4158,14 @@ function parseCatchClause() { } function parseTryStatement() { - var block, handlers = [], finalizer = null; + var block, handler = null, finalizer = null; expectKeyword("try"); block = parseBlock(); if (matchKeyword("catch")) { - handlers.push(parseCatchClause()); + handler = parseCatchClause(); } if (matchKeyword("finally")) { @@ -4107,11 +4173,11 @@ function parseTryStatement() { finalizer = parseBlock(); } - if (handlers.length === 0 && !finalizer) { + if (!handler && !finalizer) { throwError({}, Messages.NoCatchOrFinally); } - return astNodeFactory.createTryStatement(block, [], handlers, finalizer); + return astNodeFactory.createTryStatement(block, handler, finalizer); } // 12.15 The debugger statement @@ -4245,6 +4311,7 @@ function parseFunctionSourceElements() { directive = source.slice(token.range[0] + 1, token.range[1] - 1); if (directive === "use strict") { strict = true; + if (firstRestricted) { throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); } @@ -4293,11 +4360,13 @@ function parseFunctionSourceElements() { } function validateParam(options, param, name) { + if (strict) { if (syntax.isRestrictedWord(name)) { options.stricted = param; options.message = Messages.StrictParamName; } + if (options.paramSet.has(name)) { options.stricted = param; options.message = Messages.StrictParamDupe; @@ -4323,6 +4392,7 @@ function parseParam(options) { allowDestructuring = extra.ecmaFeatures.destructuring, allowDefaultParams = extra.ecmaFeatures.defaultParams; + token = lookahead; if (token.value === "...") { if (!allowRestParams) { @@ -4356,12 +4426,13 @@ function parseParam(options) { if (rest) { throwErrorTolerant(lookahead, Messages.DefaultRestParameter); } - if (!allowDefaultParams) { + if (allowDefaultParams || allowDestructuring) { + lex(); + def = parseAssignmentExpression(); + ++options.defaultCount; + } else { throwUnexpected(lookahead); } - lex(); - def = parseAssignmentExpression(); - ++options.defaultCount; } if (rest) { @@ -4380,7 +4451,7 @@ function parseParam(options) { function parseParams(firstRestricted) { - var options, marker = markerCreate(); + var options; options = { params: [], @@ -4408,11 +4479,18 @@ function parseParams(firstRestricted) { options.defaults = []; } - return markerApply(marker, options); + return { + params: options.params, + defaults: options.defaults, + rest: options.rest, + stricted: options.stricted, + firstRestricted: options.firstRestricted, + message: options.message + }; } -function parseFunctionDeclaration() { - var id, body, token, tmp, firstRestricted, message, previousStrict, previousYieldAllowed, generator, +function parseFunctionDeclaration(identifierIsOptional) { + var id = null, body, token, tmp, firstRestricted, message, previousStrict, previousYieldAllowed, generator, marker = markerCreate(), allowGenerators = extra.ecmaFeatures.generators; @@ -4424,21 +4502,24 @@ function parseFunctionDeclaration() { generator = true; } - token = lookahead; + if (!identifierIsOptional || !match("(")) { - id = parseVariableIdentifier(); + token = lookahead; - if (strict) { - if (syntax.isRestrictedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictFunctionName); - } - } else { - if (syntax.isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictFunctionName; - } else if (syntax.isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; + id = parseVariableIdentifier(); + + if (strict) { + if (syntax.isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (syntax.isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (syntax.isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } } } @@ -4565,17 +4646,458 @@ function parseYieldExpression() { return markerApply(marker, astNodeFactory.createYieldExpression(expr, delegateFlag)); } +// Modules grammar from: +// people.mozilla.org/~jorendorff/es6-draft.html -// 14 Program +function parseModuleSpecifier() { + var marker = markerCreate(), + specifier; + + if (lookahead.type !== Token.StringLiteral) { + throwError({}, Messages.InvalidModuleSpecifier); + } + specifier = astNodeFactory.createLiteralFromSource(lex(), source); + return markerApply(marker, specifier); +} + +function parseExportSpecifier() { + var exported, local, marker = markerCreate(); + if (matchKeyword("default")) { + lex(); + local = markerApply(marker, astNodeFactory.createIdentifier("default")); + // export {default} from "something"; + } else { + local = parseVariableIdentifier(); + } + if (matchContextualKeyword("as")) { + lex(); + exported = parseNonComputedProperty(); + } + return markerApply(marker, astNodeFactory.createExportSpecifier(local, exported)); +} + +function parseExportNamedDeclaration() { + var declaration = null, + isExportFromIdentifier, + src = null, specifiers = [], + marker = markerCreate(); + + expectKeyword("export"); + + // non-default export + if (lookahead.type === Token.Keyword) { + // covers: + // export var f = 1; + switch (lookahead.value) { + case "let": + case "const": + case "var": + case "class": + case "function": + declaration = parseSourceElement(); + return markerApply(marker, astNodeFactory.createExportNamedDeclaration(declaration, specifiers, null)); + default: + break; + } + } + + expect("{"); + if (!match("}")) { + do { + isExportFromIdentifier = isExportFromIdentifier || matchKeyword("default"); + specifiers.push(parseExportSpecifier()); + } while (match(",") && lex()); + } + expect("}"); + + if (matchContextualKeyword("from")) { + // covering: + // export {default} from "foo"; + // export {foo} from "foo"; + lex(); + src = parseModuleSpecifier(); + consumeSemicolon(); + } else if (isExportFromIdentifier) { + // covering: + // export {default}; // missing fromClause + throwError({}, lookahead.value ? + Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value); + } else { + // cover + // export {foo}; + consumeSemicolon(); + } + return markerApply(marker, astNodeFactory.createExportNamedDeclaration(declaration, specifiers, src)); +} + +function parseExportDefaultDeclaration() { + var declaration = null, + expression = null, + possibleIdentifierToken, + allowClasses = extra.ecmaFeatures.classes, + marker = markerCreate(); + + // covers: + // export default ... + expectKeyword("export"); + expectKeyword("default"); + + if (matchKeyword("function") || matchKeyword("class")) { + possibleIdentifierToken = lookahead2(); + if (possibleIdentifierToken.type === Token.Identifier) { + // covers: + // export default function foo () {} + // export default class foo {} + declaration = parseSourceElement(); + return markerApply(marker, astNodeFactory.createExportDefaultDeclaration(declaration)); + } + // covers: + // export default function () {} + // export default class {} + if (lookahead.value === "function") { + declaration = parseFunctionDeclaration(true); + return markerApply(marker, astNodeFactory.createExportDefaultDeclaration(declaration)); + } else if (allowClasses && lookahead.value === "class") { + declaration = parseClassDeclaration(true); + return markerApply(marker, astNodeFactory.createExportDefaultDeclaration(declaration)); + } + } + + if (matchContextualKeyword("from")) { + throwError({}, Messages.UnexpectedToken, lookahead.value); + } + + // covers: + // export default {}; + // export default []; + // export default (1 + 2); + if (match("{")) { + expression = parseObjectInitialiser(); + } else if (match("[")) { + expression = parseArrayInitialiser(); + } else { + expression = parseAssignmentExpression(); + } + consumeSemicolon(); + return markerApply(marker, astNodeFactory.createExportDefaultDeclaration(expression)); +} + + +function parseExportAllDeclaration() { + var src, + marker = markerCreate(); + + // covers: + // export * from "foo"; + expectKeyword("export"); + expect("*"); + if (!matchContextualKeyword("from")) { + throwError({}, lookahead.value ? + Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value); + } + lex(); + src = parseModuleSpecifier(); + consumeSemicolon(); + + return markerApply(marker, astNodeFactory.createExportAllDeclaration(src)); +} + +function parseExportDeclaration() { + if (state.inFunctionBody) { + throwError({}, Messages.IllegalExportDeclaration); + } + var declarationType = lookahead2().value; + if (declarationType === "default") { + return parseExportDefaultDeclaration(); + } else if (declarationType === "*") { + return parseExportAllDeclaration(); + } else { + return parseExportNamedDeclaration(); + } +} + +function parseImportSpecifier() { + // import {} ...; + var local, imported, marker = markerCreate(); + + imported = parseNonComputedProperty(); + if (matchContextualKeyword("as")) { + lex(); + local = parseVariableIdentifier(); + } + + return markerApply(marker, astNodeFactory.createImportSpecifier(local, imported)); +} + +function parseNamedImports() { + var specifiers = []; + // {foo, bar as bas} + expect("{"); + if (!match("}")) { + do { + specifiers.push(parseImportSpecifier()); + } while (match(",") && lex()); + } + expect("}"); + return specifiers; +} + +function parseImportDefaultSpecifier() { + // import ...; + var local, marker = markerCreate(); + + local = parseNonComputedProperty(); + + return markerApply(marker, astNodeFactory.createImportDefaultSpecifier(local)); +} + +function parseImportNamespaceSpecifier() { + // import <* as foo> ...; + var local, marker = markerCreate(); + + expect("*"); + if (!matchContextualKeyword("as")) { + throwError({}, Messages.NoAsAfterImportNamespace); + } + lex(); + local = parseNonComputedProperty(); + + return markerApply(marker, astNodeFactory.createImportNamespaceSpecifier(local)); +} + +function parseImportDeclaration() { + var specifiers, src, marker = markerCreate(); + + if (state.inFunctionBody) { + throwError({}, Messages.IllegalImportDeclaration); + } + + expectKeyword("import"); + specifiers = []; + + if (lookahead.type === Token.StringLiteral) { + // covers: + // import "foo"; + src = parseModuleSpecifier(); + consumeSemicolon(); + return markerApply(marker, astNodeFactory.createImportDeclaration(specifiers, src)); + } + + if (!matchKeyword("default") && isIdentifierName(lookahead)) { + // covers: + // import foo + // import foo, ... + specifiers.push(parseImportDefaultSpecifier()); + if (match(",")) { + lex(); + } + } + if (match("*")) { + // covers: + // import foo, * as foo + // import * as foo + specifiers.push(parseImportNamespaceSpecifier()); + } else if (match("{")) { + // covers: + // import foo, {bar} + // import {bar} + specifiers = specifiers.concat(parseNamedImports()); + } + + if (!matchContextualKeyword("from")) { + throwError({}, lookahead.value ? + Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value); + } + lex(); + src = parseModuleSpecifier(); + consumeSemicolon(); + + return markerApply(marker, astNodeFactory.createImportDeclaration(specifiers, src)); +} + +// 14 Functions and classes + +// 14.1 Functions is defined above (13 in ES5) +// 14.2 Arrow Functions Definitions is defined in (7.3 assignments) + +// 14.3 Method Definitions +// 14.3.7 + +// 14.5 Class Definitions + +function parseClassBody() { + var hasConstructor = false, generator = false, + allowGenerators = extra.ecmaFeatures.generators, + token, isStatic, body = [], method, computed, key; + + var existingProps = {}, + topMarker = markerCreate(), + marker; + + existingProps.static = new StringMap(); + existingProps.prototype = new StringMap(); + + expect("{"); + + while (!match("}")) { + + // extra semicolons are fine + if (match(";")) { + lex(); + continue; + } + + token = lookahead; + isStatic = false; + generator = match("*"); + computed = match("["); + marker = markerCreate(); + + if (generator) { + if (!allowGenerators) { + throwUnexpected(lookahead); + } + lex(); + } + + key = parseObjectPropertyKey(); + + // static generator methods + if (key.name === "static" && match("*")) { + if (!allowGenerators) { + throwUnexpected(lookahead); + } + generator = true; + lex(); + } + + if (key.name === "static" && lookaheadPropertyName()) { + token = lookahead; + isStatic = true; + computed = match("["); + key = parseObjectPropertyKey(); + } + + if (generator) { + method = parseGeneratorProperty(key, marker); + } else { + method = tryParseMethodDefinition(token, key, computed, marker, generator); + } + + if (method) { + method.static = isStatic; + if (method.kind === "init") { + method.kind = "method"; + } + + if (!isStatic) { + if (!method.computed && (method.key.name || method.key.value.toString()) === "constructor") { + if (method.kind !== "method" || !method.method || method.value.generator) { + throwUnexpected(token, Messages.ConstructorSpecialMethod); + } + if (hasConstructor) { + throwUnexpected(token, Messages.DuplicateConstructor); + } else { + hasConstructor = true; + } + method.kind = "constructor"; + } + } else { + if (!method.computed && (method.key.name || method.key.value.toString()) === "prototype") { + throwUnexpected(token, Messages.StaticPrototype); + } + } + method.type = astNodeTypes.MethodDefinition; + delete method.method; + delete method.shorthand; + body.push(method); + } else { + throwUnexpected(lookahead); + } + } + + lex(); + return markerApply(topMarker, astNodeFactory.createClassBody(body)); +} + +function parseClassExpression() { + var id = null, superClass = null, marker = markerCreate(), + previousStrict = strict, classBody; + + // classes run in strict mode + strict = true; + + expectKeyword("class"); + + if (lookahead.type === Token.Identifier) { + id = parseVariableIdentifier(); + } + + if (matchKeyword("extends")) { + lex(); + superClass = parseLeftHandSideExpressionAllowCall(); + } + + classBody = parseClassBody(); + strict = previousStrict; + + return markerApply(marker, astNodeFactory.createClassExpression(id, superClass, classBody)); +} + +function parseClassDeclaration(identifierIsOptional) { + var id = null, superClass = null, marker = markerCreate(), + previousStrict = strict, classBody; + + // classes run in strict mode + strict = true; + + expectKeyword("class"); + + if (!identifierIsOptional || lookahead.type === Token.Identifier) { + id = parseVariableIdentifier(); + } + + if (matchKeyword("extends")) { + lex(); + superClass = parseLeftHandSideExpressionAllowCall(); + } + + classBody = parseClassBody(); + strict = previousStrict; + + return markerApply(marker, astNodeFactory.createClassDeclaration(id, superClass, classBody)); +} + +// 15 Program function parseSourceElement() { + + var allowClasses = extra.ecmaFeatures.classes, + allowModules = extra.ecmaFeatures.modules, + allowBlockBindings = extra.ecmaFeatures.blockBindings; + if (lookahead.type === Token.Keyword) { switch (lookahead.value) { + case "export": + if (!allowModules) { + throwErrorTolerant({}, Messages.IllegalExportDeclaration); + } + return parseExportDeclaration(); + case "import": + if (!allowModules) { + throwErrorTolerant({}, Messages.IllegalImportDeclaration); + } + return parseImportDeclaration(); case "function": return parseFunctionDeclaration(); + case "class": + if (allowClasses) { + return parseClassDeclaration(); + } + break; case "const": case "let": - if (extra.ecmaFeatures.blockBindings) { + if (allowBlockBindings) { return parseConstLetDeclaration(lookahead.value); } /* falls through */ @@ -4630,15 +5152,16 @@ function parseSourceElements() { function parseProgram() { var body, - marker; + marker, + isModule = !!extra.ecmaFeatures.modules; skipComment(); peek(); marker = markerCreate(); - strict = false; + strict = isModule; body = parseSourceElements(); - return markerApply(marker, astNodeFactory.createProgram(body)); + return markerApply(marker, astNodeFactory.createProgram(body, isModule ? "module" : "script")); } function filterTokenLocation() { @@ -4718,7 +5241,7 @@ function tokenize(code, options) { extra.openCurlyToken = -1; // Needed when using template string tokenization - extra.curlies = []; + state.curlyStack = []; extra.range = (typeof options.range === "boolean") && options.range; extra.loc = (typeof options.loc === "boolean") && options.loc; @@ -4807,22 +5330,17 @@ function parse(code, options) { }; extra = { - ecmaFeatures: defaultFeatures + ecmaFeatures: Object.create(defaultFeatures) }; // for template strings - extra.curlies = []; + state.curlyStack = []; 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; - // apply parsing flags - if (options.ecmaFeatures && typeof options.ecmaFeatures === "object") { - extra.ecmaFeatures = options.ecmaFeatures; - } - if (extra.loc && options.source !== null && options.source !== undefined) { extra.source = toString(options.source); } @@ -4839,10 +5357,47 @@ function parse(code, options) { if (extra.attachComment) { extra.range = true; extra.comments = []; - extra.bottomRightStack = []; - extra.trailingComments = []; - extra.leadingComments = []; + commentAttachment.reset(); } + + if (options.sourceType === "module") { + extra.ecmaFeatures = { + arrowFunctions: true, + blockBindings: true, + regexUFlag: true, + regexYFlag: true, + templateStrings: true, + binaryLiterals: true, + octalLiterals: true, + unicodeCodePointEscapes: true, + superInFunctions: true, + defaultParams: true, + restParams: true, + forOf: true, + objectLiteralComputedProperties: true, + objectLiteralShorthandMethods: true, + objectLiteralShorthandProperties: true, + objectLiteralDuplicateProperties: true, + generators: true, + destructuring: true, + classes: true, + modules: true + }; + } + + // apply parsing flags after sourceType to allow overriding + if (options.ecmaFeatures && typeof options.ecmaFeatures === "object") { + + // if it's a module, augment the ecmaFeatures + if (options.sourceType === "module") { + Object.keys(options.ecmaFeatures).forEach(function(key) { + extra.ecmaFeatures[key] = options.ecmaFeatures[key]; + }); + } else { + extra.ecmaFeatures = options.ecmaFeatures; + } + } + } try { diff --git a/node_modules/espree/lib/ast-node-factory.js b/node_modules/espree/lib/ast-node-factory.js index 06b6930a..11594a30 100644 --- a/node_modules/espree/lib/ast-node-factory.js +++ b/node_modules/espree/lib/ast-node-factory.js @@ -161,6 +161,47 @@ module.exports = { }; }, + /** + * Creates an ASTNode representation of a class body. + * @param {ASTNode} body The node representing the body of the class. + * @returns {ASTNode} An ASTNode representing the class body. + */ + createClassBody: function (body) { + return { + type: astNodeTypes.ClassBody, + body: body + }; + }, + + createClassExpression: function (id, superClass, body) { + return { + type: astNodeTypes.ClassExpression, + id: id, + superClass: superClass, + body: body + }; + }, + + createClassDeclaration: function (id, superClass, body) { + return { + type: astNodeTypes.ClassDeclaration, + id: id, + superClass: superClass, + body: body + }; + }, + + createMethodDefinition: function (propertyType, kind, key, value, computed) { + return { + type: astNodeTypes.MethodDefinition, + key: key, + value: value, + kind: kind, + "static": propertyType === "static", + computed: computed + }; + }, + /** * Create an ASTNode representation of a conditional expression * @param {ASTNode} test The conditional to evaluate @@ -317,7 +358,7 @@ module.exports = { return { type: astNodeTypes.FunctionDeclaration, id: id, - params: params, + params: params || [], defaults: defaults || [], body: body, rest: rest || null, @@ -341,7 +382,7 @@ module.exports = { return { type: astNodeTypes.FunctionExpression, id: id, - params: params, + params: params || [], defaults: defaults || [], body: body, rest: rest || null, @@ -531,12 +572,14 @@ module.exports = { /** * Create an ASTNode representation of an entire program * @param {ASTNode} body The program body + * @param {string} sourceType Either "module" or "script". * @returns {ASTNode} An ASTNode representing an entire program */ - createProgram: function (body) { + createProgram: function (body, sourceType) { return { type: astNodeTypes.Program, - body: body + body: body, + sourceType: sourceType }; }, @@ -639,17 +682,17 @@ module.exports = { /** * Create an ASTNode representation of a try statement * @param {ASTNode} block The try block - * @param {ASTNode} guardedHandlers Any guarded catch handlers - * @param {ASTNode} handlers Any catch handlers + * @param {ASTNode} handler A catch handler * @param {?ASTNode} finalizer The final code block to run after the try/catch has run * @returns {ASTNode} An ASTNode representing a try statement */ - createTryStatement: function (block, guardedHandlers, handlers, finalizer) { + createTryStatement: function (block, handler, finalizer) { return { type: astNodeTypes.TryStatement, block: block, - guardedHandlers: guardedHandlers, - handlers: handlers, + guardedHandlers: [], + handlers: handler ? [ handler ] : [], + handler: handler, finalizer: finalizer }; }, @@ -801,6 +844,67 @@ module.exports = { type: astNodeTypes.JSXClosingElement, name: name }; + }, + + createExportSpecifier: function (local, exported) { + return { + type: astNodeTypes.ExportSpecifier, + exported: exported || local, + local: local + }; + }, + + createImportDefaultSpecifier: function (local) { + return { + type: astNodeTypes.ImportDefaultSpecifier, + local: local + }; + }, + + createImportNamespaceSpecifier: function (local) { + return { + type: astNodeTypes.ImportNamespaceSpecifier, + local: local + }; + }, + + createExportNamedDeclaration: function (declaration, specifiers, source) { + return { + type: astNodeTypes.ExportNamedDeclaration, + declaration: declaration, + specifiers: specifiers, + source: source + }; + }, + + createExportDefaultDeclaration: function (declaration) { + return { + type: astNodeTypes.ExportDefaultDeclaration, + declaration: declaration + }; + }, + + createExportAllDeclaration: function (source) { + return { + type: astNodeTypes.ExportAllDeclaration, + source: source + }; + }, + + createImportSpecifier: function (local, imported) { + return { + type: astNodeTypes.ImportSpecifier, + local: local || imported, + imported: imported + }; + }, + + createImportDeclaration: function (specifiers, source) { + return { + type: astNodeTypes.ImportDeclaration, + specifiers: specifiers, + source: source + }; } }; diff --git a/node_modules/espree/lib/ast-node-types.js b/node_modules/espree/lib/ast-node-types.js index 58fc3452..7976f341 100644 --- a/node_modules/espree/lib/ast-node-types.js +++ b/node_modules/espree/lib/ast-node-types.js @@ -39,6 +39,7 @@ module.exports = { AssignmentExpression: "AssignmentExpression", + AssignmentPattern: "AssignmentPattern", ArrayExpression: "ArrayExpression", ArrayPattern: "ArrayPattern", ArrowFunctionExpression: "ArrowFunctionExpression", @@ -47,6 +48,9 @@ module.exports = { BreakStatement: "BreakStatement", CallExpression: "CallExpression", CatchClause: "CatchClause", + ClassBody: "ClassBody", + ClassDeclaration: "ClassDeclaration", + ClassExpression: "ClassExpression", ConditionalExpression: "ConditionalExpression", ContinueStatement: "ContinueStatement", DoWhileStatement: "DoWhileStatement", @@ -64,6 +68,7 @@ module.exports = { LabeledStatement: "LabeledStatement", LogicalExpression: "LogicalExpression", MemberExpression: "MemberExpression", + MethodDefinition: "MethodDefinition", NewExpression: "NewExpression", ObjectExpression: "ObjectExpression", ObjectPattern: "ObjectPattern", @@ -97,5 +102,13 @@ module.exports = { JSXOpeningElement: "JSXOpeningElement", JSXAttribute: "JSXAttribute", JSXSpreadAttribute: "JSXSpreadAttribute", - JSXText: "JSXText" + JSXText: "JSXText", + ExportDefaultDeclaration: "ExportDefaultDeclaration", + ExportNamedDeclaration: "ExportNamedDeclaration", + ExportAllDeclaration: "ExportAllDeclaration", + ExportSpecifier: "ExportSpecifier", + ImportDeclaration: "ImportDeclaration", + ImportSpecifier: "ImportSpecifier", + ImportDefaultSpecifier: "ImportDefaultSpecifier", + ImportNamespaceSpecifier: "ImportNamespaceSpecifier" }; diff --git a/node_modules/espree/lib/comment-attachment.js b/node_modules/espree/lib/comment-attachment.js new file mode 100644 index 00000000..3618bb3b --- /dev/null +++ b/node_modules/espree/lib/comment-attachment.js @@ -0,0 +1,171 @@ +/** + * @fileoverview Attaches comments to the AST. + * @author Nicholas C. Zakas + * @copyright 2015 Nicholas C. Zakas. All rights reserved. + * @copyright 2011-2013 Ariya Hidayat + * + * 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 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. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var astNodeTypes = require("./ast-node-types"); + +//------------------------------------------------------------------------------ +// Private +//------------------------------------------------------------------------------ + +var extra = { + trailingComments: [], + leadingComments: [], + bottomRightStack: [] + }; + +//------------------------------------------------------------------------------ +// Public +//------------------------------------------------------------------------------ + +module.exports = { + + reset: function() { + extra.trailingComments = []; + extra.leadingComments = []; + extra.bottomRightStack = []; + }, + + addComment: function(comment) { + extra.trailingComments.push(comment); + extra.leadingComments.push(comment); + }, + + processComment: function(node) { + var lastChild, + trailingComments, + i; + + if (node.type === astNodeTypes.Program) { + if (node.body.length > 0) { + return; + } + } + + if (extra.trailingComments.length > 0) { + + /* + * If the first comment in trailingComments comes after the + * current node, then we're good - all comments in the array will + * come after the node and so it's safe to add then as official + * trailingComments. + */ + if (extra.trailingComments[0].range[0] >= node.range[1]) { + trailingComments = extra.trailingComments; + extra.trailingComments = []; + } else { + + /* + * Otherwise, if the first comment doesn't come after the + * current node, that means we have a mix of leading and trailing + * comments in the array and that leadingComments contains the + * same items as trailingComments. Reset trailingComments to + * zero items and we'll handle this by evaluating leadingComments + * later. + */ + extra.trailingComments.length = 0; + } + } else { + if (extra.bottomRightStack.length > 0 && + extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments && + extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) { + trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; + delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; + } + } + + // Eating the stack. + while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) { + lastChild = extra.bottomRightStack.pop(); + } + + if (lastChild) { + if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) { + node.leadingComments = lastChild.leadingComments; + delete lastChild.leadingComments; + } + } else if (extra.leadingComments.length > 0) { + + if (extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) { + node.leadingComments = extra.leadingComments; + extra.leadingComments = []; + } else { + + // https://github.com/eslint/espree/issues/2 + + /* + * In special cases, such as return (without a value) and + * debugger, all comments will end up as leadingComments and + * will otherwise be eliminated. This extra step runs when the + * bottomRightStack is empty and there are comments left + * in leadingComments. + * + * This loop figures out the stopping point between the actual + * leading and trailing comments by finding the location of the + * first comment that comes after the given node. + */ + for (i = 0; i < extra.leadingComments.length; i++) { + if (extra.leadingComments[i].range[1] > node.range[0]) { + break; + } + } + + /* + * Split the array based on the location of the first comment + * that comes after the node. Keep in mind that this could + * result in an empty array, and if so, the array must be + * deleted. + */ + node.leadingComments = extra.leadingComments.slice(0, i); + if (node.leadingComments.length === 0) { + delete node.leadingComments; + } + + /* + * Similarly, trailing comments are attached later. The variable + * must be reset to null if there are no trailing comments. + */ + trailingComments = extra.leadingComments.slice(i); + if (trailingComments.length === 0) { + trailingComments = null; + } + } + } + + if (trailingComments) { + node.trailingComments = trailingComments; + } + + extra.bottomRightStack.push(node); + } + +}; diff --git a/node_modules/espree/lib/features.js b/node_modules/espree/lib/features.js index 3c2b17c3..c33274a4 100644 --- a/node_modules/espree/lib/features.js +++ b/node_modules/espree/lib/features.js @@ -97,6 +97,12 @@ module.exports = { // enable super in functions superInFunctions: false, + // enable parsing of classes + classes: false, + + // enable parsing of modules + modules: false, + // React JSX parsing jsx: false, diff --git a/node_modules/espree/lib/messages.js b/node_modules/espree/lib/messages.js index 0d817391..2618f993 100644 --- a/node_modules/espree/lib/messages.js +++ b/node_modules/espree/lib/messages.js @@ -78,6 +78,9 @@ module.exports = { StrictDelete: "Delete of an unqualified identifier in strict mode.", StrictDuplicateProperty: "Duplicate data property in object literal not allowed in strict mode", DuplicatePrototypeProperty: "Duplicate '__proto__' property in object literal are not allowed", + ConstructorSpecialMethod: "Class constructor may not be an accessor", + DuplicateConstructor: "A class may only have one constructor", + StaticPrototype: "Classes may not have static property named prototype", AccessorDataProperty: "Object literal may not have data and accessor property with the same name", AccessorGetSet: "Object literal may not have multiple get/set accessors with the same name", StrictLHSAssignment: "Assignment to eval or arguments is not allowed in strict mode", @@ -86,5 +89,10 @@ module.exports = { StrictReservedWord: "Use of future reserved word in strict mode", InvalidJSXAttributeValue: "JSX value should be either an expression or a quoted JSX text", ExpectedJSXClosingTag: "Expected corresponding JSX closing tag for %0", - AdjacentJSXElements: "Adjacent JSX elements must be wrapped in an enclosing tag" + AdjacentJSXElements: "Adjacent JSX elements must be wrapped in an enclosing tag", + MissingFromClause: "Missing from clause", + NoAsAfterImportNamespace: "Missing as after import *", + InvalidModuleSpecifier: "Invalid module specifier", + IllegalImportDeclaration: "Illegal import declaration", + IllegalExportDeclaration: "Illegal export declaration" }; diff --git a/node_modules/espree/package.json b/node_modules/espree/package.json index c44ed32b..fe4557f1 100644 --- a/node_modules/espree/package.json +++ b/node_modules/espree/package.json @@ -11,7 +11,7 @@ "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" }, - "version": "1.9.1", + "version": "1.12.0", "files": [ "bin", "lib", @@ -83,10 +83,10 @@ "benchmark-quick": "node test/benchmarks.js quick" }, "dependencies": {}, - "readme": "# Espree\n\nEspree is an actively-maintained fork Esprima, a high performance,\nstandard-compliant [ECMAScript](http://www.ecma-international.org/publications/standards/Ecma-262.htm)\nparser written in ECMAScript (also popularly known as\n[JavaScript](http://en.wikipedia.org/wiki/JavaScript)).\n\n## Features\n\n- Full support for ECMAScript 5.1 ([ECMA-262](http://www.ecma-international.org/publications/standards/Ecma-262.htm))\n- Sensible syntax tree format compatible with Mozilla\n[Parser AST](https://developer.mozilla.org/en/SpiderMonkey/Parser_API)\n- Optional tracking of syntax node location (index-based and line-column)\n- Heavily tested (> 650 unit tests) with full code coverage\n\n## Usage\n\nInstall:\n\n```\nnpm i espree --save\n```\n\nAnd in your Node.js code:\n\n```javascript\nvar espree = require(\"espree\");\n\nvar ast = espree.parse(code);\n```\n\nThere is a second argument to `parse()` that allows you to specify various options:\n\n```javascript\nvar espree = require(\"espree\");\n\nvar ast = espree.parse(code, {\n\n // attach range information to each node\n range: true,\n\n // attach line/column location information to each node\n loc: true,\n\n // create a top-level comments array containing all comments\n comments: true,\n\n // attach comments to the closest relevant node as leadingComments and\n // trailingComments\n attachComment: true,\n\n // create a top-level tokens array containing all tokens\n tokens: true,\n\n // try to continue parsing if an error is encountered, store errors in a\n // top-level errors array\n tolerant: true,\n\n // specify parsing features (default only has blockBindings: true)\n ecmaFeatures: {\n\n // enable parsing of arrow functions\n arrowFunctions: true,\n\n // enable parsing of let/const\n blockBindings: true,\n\n // enable parsing of destructured arrays and objects\n destructuring: true,\n\n // enable parsing of regular expression y flag\n regexYFlag: true,\n\n // enable parsing of regular expression u flag\n regexUFlag: true,\n\n // enable parsing of template strings\n templateStrings: false,\n\n // enable parsing of binary literals\n binaryLiterals: true,\n\n // enable parsing of ES6 octal literals\n octalLiterals: true,\n\n // enable parsing unicode code point escape sequences\n unicodeCodePointEscapes: true,\n\n // enable parsing of default parameters\n defaultParams: false,\n\n // enable parsing of rest parameters\n restParams: true,\n\n // enable parsing of for-of statement\n forOf: true,\n\n // enable parsing computed object literal properties\n objectLiteralComputedProperties: true,\n\n // enable parsing of shorthand object literal methods\n objectLiteralShorthandMethods: true,\n\n // enable parsing of shorthand object literal properties\n objectLiteralShorthandProperties: true,\n\n // Allow duplicate object literal properties (except '__proto__')\n objectLiteralDuplicateProperties: true,\n\n // enable parsing of generators/yield\n generators: true,\n\n // support the spread operator\n spread: true,\n\n // enable React JSX parsing\n jsx: true,\n\n // enable return in global scope\n globalReturn: true\n }\n});\n```\n\n## Plans\n\nEspree starts as a fork of Esprima v1.2.2, the last stable published released of Esprima before work on ECMAScript 6 began. Espree's first version is therefore v1.2.2 and is 100% compatible with Esprima v1.2.2 as a drop-in replacement. The version number will be incremented based on [semantic versioning](http://semver.org/) as features and bug fixes are added.\n\nThe immediate plans are:\n\n1. Move away from giant files and move towards small, modular files that are easier to manage.\n1. Move towards CommonJS for all files and use browserify to create browser bundles.\n1. Support ECMAScript version filtering, allowing users to specify which version the parser should work in (similar to Acorn's `ecmaVersion` property).\n1. Add tests to track comment attachment.\n1. Add well-thought-out features that are useful for tools developers.\n1. Add full support for ECMAScript 6.\n1. Add optional parsing of JSX.\n\n## Esprima Compatibility Going Forward\n\nThe primary goal is to produce the exact same AST structure as Esprima and Acorn, and that takes precedence over anything else. (The AST structure being the SpiderMonkey Parser API with JSX extensions.) Separate from that, Espree may deviate from what Esprima outputs in terms of where and how comments are attached, as well as what additional information is available on AST nodes. That is to say, Espree may add more things to the AST nodes than Esprima does but the overall AST structure produced will be the same.\n\nEspree may also deviate from Esprima in the interface it exposes.\n\n## Frequent and Incremental Releases\n\nEspree will not do giant releases. Releases will happen periodically as changes are made and incremental releases will be made towards larger goals. For instance, we will not have one big release for ECMAScript 6 support. Instead, we will implement ECMAScript 6, piece-by-piece, hiding those pieces behind an `ecmaFeatures` property that allows you to opt-in to use those features.\n\n## Contributing\n\nIssues and pull requests will be triaged and responded to as quickly as possible. We operate under the [ESLint Contributor Guidelines](http://eslint.org/docs/developer-guide/contributing.html), so please be sure to read them before contributing. If you're not sure where to dig in, check out the [issues](https://github.com/eslint/espree/issues).\n\nEspree is licensed under a permissive BSD 3-clause license.\n\n## Build Commands\n\n* `npm test` - run all linting and tests\n* `npm run lint` - run all linting\n* `npm run browserify` - creates a version of Espree that is usable in a browser\n\n## Known Incompatibilities\n\nIn an effort to help those wanting to transition from other parsers to Espree, the following is a list of noteworthy incompatibilities with other parsers. These are known differences that we do not intend to change.\n\n### Esprima 1.2.2\n\n* None.\n\n### Esprima/Harmony Branch\n\n* Esprima/Harmony uses a different comment attachment algorithm that results in some comments being added in different places than Espree. The algorithm Espree uses is the same one used in Esprima 1.2.2.\n* Template tokens have a `head` property in addition to `tail`. Esprima has only `tail`.\n\n### Esprima-FB\n\n* All Esprima/Harmony incompatibilities.\n* Esprima-FB uses the term \"XJS\" to refer to its JSX support. This is seen primarily in the AST node types, such as `\"XJSElement\"`. Espree uses \"JSX\" to refer to JSX functionality, including AST node types. So, `\"XJSElement\"` in Esprima-FB is `\"JSXElement\"` in Espree (and the same is true for all JSX-related node types).\n\n## Frequently Asked Questions\n\n### Why are you forking Esprima?\n\n[ESLint](http://eslint.org) has been relying on Esprima as its parser from the beginning. While that was fine when the JavaScript language was evolving slowly, the pace of development has increased dramatically and Esprima has fallen behind. ESLint, like many other tools reliant on Esprima, has been stuck in using new JavaScript language features until Esprima updates, and that has caused our users frustration.\n\nWe decided the only way for us to move forward was to create our own parser, bringing us inline with JSHint and JSLint, and allowing us to keep implementing new features as we need them. We chose to fork Esprima instead of starting from scratch in order to move as quickly as possible with a compatible API.\n\n### Have you tried working with Esprima?\n\nYes. Since the start of ESLint, we've regularly filed bugs and feature requests with Esprima. Unfortunately, we've been unable to make much progress towards getting our needs addressed.\n\n### Why don't you just use Facebook's Esprima fork?\n\n`esprima-fb` is Facebook's Esprima fork that features JSX and Flow type annotations. We tried working with `esprima-fb` in our evaluation of how to support ECMAScript 6 and JSX in ESLint. Unfortunately, we were hampered by bugs that were part of Esprima (not necessarily Facebook's code). Since `esprima-fb` tracks the Esprima Harmony branch, that means we still were unable to get fixes or features we needed in a timely manner.\n\n### Why don't you just use Acorn?\n\nAcorn is a great JavaScript parser that produces an AST that is compatible with Esprima. Unfortunately, ESLint relies on more than just the AST to do its job. It relies on Esprima's tokens and comment attachment features to get a complete picture of the source code. We investigated switching to Acorn, but the inconsistencies between Esprima and Acorn created too much work for a project like ESLint.\n\nWe expect there are other tools like ESLint that rely on more than just the AST produced by Esprima, and so a drop-in replacement will help those projects as well as ESLint.\n\n### What ECMAScript 6 features do you support?\n\nPlease see the [tracking issue](https://github.com/eslint/espree/issues/10) for the most up-to-date information.\n\n### Why use Espree instead of Esprima?\n\n* Faster turnaround time on bug fixes\n* More frequent releases\n* Better communication and responsiveness to issues\n* Ongoing development\n\n### Why use Espree instead of Esprima-FB?\n\n* Opt-in to just the ECMAScript 6 features you want\n* JSX support is off by default, so you're not forced to use it to use ECMAScript 6\n* Stricter ECMAScript 6 support\n", + "readme": "# Espree\n\nEspree is an actively-maintained fork Esprima, a high performance,\nstandard-compliant [ECMAScript](http://www.ecma-international.org/publications/standards/Ecma-262.htm)\nparser written in ECMAScript (also popularly known as\n[JavaScript](http://en.wikipedia.org/wiki/JavaScript)).\n\n## Features\n\n- Full support for ECMAScript 5.1 ([ECMA-262](http://www.ecma-international.org/publications/standards/Ecma-262.htm))\n- Sensible syntax tree format compatible with Mozilla\n[Parser AST](https://developer.mozilla.org/en/SpiderMonkey/Parser_API)\n- Optional tracking of syntax node location (index-based and line-column)\n- Heavily tested (> 650 unit tests) with full code coverage\n\n## Usage\n\nInstall:\n\n```\nnpm i espree --save\n```\n\nAnd in your Node.js code:\n\n```javascript\nvar espree = require(\"espree\");\n\nvar ast = espree.parse(code);\n```\n\nThere is a second argument to `parse()` that allows you to specify various options:\n\n```javascript\nvar espree = require(\"espree\");\n\nvar ast = espree.parse(code, {\n\n // attach range information to each node\n range: true,\n\n // attach line/column location information to each node\n loc: true,\n\n // create a top-level comments array containing all comments\n comments: true,\n\n // attach comments to the closest relevant node as leadingComments and\n // trailingComments\n attachComment: true,\n\n // create a top-level tokens array containing all tokens\n tokens: true,\n\n // try to continue parsing if an error is encountered, store errors in a\n // top-level errors array\n tolerant: true,\n\n // specify parsing features (default only has blockBindings: true)\n ecmaFeatures: {\n\n // enable parsing of arrow functions\n arrowFunctions: true,\n\n // enable parsing of let/const\n blockBindings: true,\n\n // enable parsing of destructured arrays and objects\n destructuring: true,\n\n // enable parsing of regular expression y flag\n regexYFlag: true,\n\n // enable parsing of regular expression u flag\n regexUFlag: true,\n\n // enable parsing of template strings\n templateStrings: true,\n\n // enable parsing of binary literals\n binaryLiterals: true,\n\n // enable parsing of ES6 octal literals\n octalLiterals: true,\n\n // enable parsing unicode code point escape sequences\n unicodeCodePointEscapes: true,\n\n // enable parsing of default parameters\n defaultParams: true,\n\n // enable parsing of rest parameters\n restParams: true,\n\n // enable parsing of for-of statement\n forOf: true,\n\n // enable parsing computed object literal properties\n objectLiteralComputedProperties: true,\n\n // enable parsing of shorthand object literal methods\n objectLiteralShorthandMethods: true,\n\n // enable parsing of shorthand object literal properties\n objectLiteralShorthandProperties: true,\n\n // Allow duplicate object literal properties (except '__proto__')\n objectLiteralDuplicateProperties: true,\n\n // enable parsing of generators/yield\n generators: true,\n\n // enable parsing spread operator\n spread: true,\n\n // enable parsing classes\n classes: true,\n\n // enable parsing of modules\n modules: true,\n\n // enable React JSX parsing\n jsx: true,\n\n // enable return in global scope\n globalReturn: true\n }\n});\n```\n\n## Plans\n\nEspree starts as a fork of Esprima v1.2.2, the last stable published released of Esprima before work on ECMAScript 6 began. Espree's first version is therefore v1.2.2 and is 100% compatible with Esprima v1.2.2 as a drop-in replacement. The version number will be incremented based on [semantic versioning](http://semver.org/) as features and bug fixes are added.\n\nThe immediate plans are:\n\n1. Move away from giant files and move towards small, modular files that are easier to manage.\n1. Move towards CommonJS for all files and use browserify to create browser bundles.\n1. Support ECMAScript version filtering, allowing users to specify which version the parser should work in (similar to Acorn's `ecmaVersion` property).\n1. Add tests to track comment attachment.\n1. Add well-thought-out features that are useful for tools developers.\n1. Add full support for ECMAScript 6.\n1. Add optional parsing of JSX.\n\n## Esprima Compatibility Going Forward\n\nThe primary goal is to produce the exact same AST structure as Esprima and Acorn, and that takes precedence over anything else. (The AST structure being the SpiderMonkey Parser API with JSX extensions.) Separate from that, Espree may deviate from what Esprima outputs in terms of where and how comments are attached, as well as what additional information is available on AST nodes. That is to say, Espree may add more things to the AST nodes than Esprima does but the overall AST structure produced will be the same.\n\nEspree may also deviate from Esprima in the interface it exposes.\n\n## Frequent and Incremental Releases\n\nEspree will not do giant releases. Releases will happen periodically as changes are made and incremental releases will be made towards larger goals. For instance, we will not have one big release for ECMAScript 6 support. Instead, we will implement ECMAScript 6, piece-by-piece, hiding those pieces behind an `ecmaFeatures` property that allows you to opt-in to use those features.\n\n## Contributing\n\nIssues and pull requests will be triaged and responded to as quickly as possible. We operate under the [ESLint Contributor Guidelines](http://eslint.org/docs/developer-guide/contributing.html), so please be sure to read them before contributing. If you're not sure where to dig in, check out the [issues](https://github.com/eslint/espree/issues).\n\nEspree is licensed under a permissive BSD 3-clause license.\n\n## Build Commands\n\n* `npm test` - run all linting and tests\n* `npm run lint` - run all linting\n* `npm run browserify` - creates a version of Espree that is usable in a browser\n\n## Known Incompatibilities\n\nIn an effort to help those wanting to transition from other parsers to Espree, the following is a list of noteworthy incompatibilities with other parsers. These are known differences that we do not intend to change.\n\n### Esprima 1.2.2\n\n* None.\n\n### Esprima/Harmony Branch\n\n* Esprima/Harmony uses a different comment attachment algorithm that results in some comments being added in different places than Espree. The algorithm Espree uses is the same one used in Esprima 1.2.2.\n* Template tokens have a `head` property in addition to `tail`. Esprima has only `tail`.\n\n### Esprima-FB\n\n* All Esprima/Harmony incompatibilities.\n\n## Frequently Asked Questions\n\n### Why are you forking Esprima?\n\n[ESLint](http://eslint.org) has been relying on Esprima as its parser from the beginning. While that was fine when the JavaScript language was evolving slowly, the pace of development has increased dramatically and Esprima has fallen behind. ESLint, like many other tools reliant on Esprima, has been stuck in using new JavaScript language features until Esprima updates, and that has caused our users frustration.\n\nWe decided the only way for us to move forward was to create our own parser, bringing us inline with JSHint and JSLint, and allowing us to keep implementing new features as we need them. We chose to fork Esprima instead of starting from scratch in order to move as quickly as possible with a compatible API.\n\n### Have you tried working with Esprima?\n\nYes. Since the start of ESLint, we've regularly filed bugs and feature requests with Esprima. Unfortunately, we've been unable to make much progress towards getting our needs addressed.\n\n### Why don't you just use Facebook's Esprima fork?\n\n`esprima-fb` is Facebook's Esprima fork that features JSX and Flow type annotations. We tried working with `esprima-fb` in our evaluation of how to support ECMAScript 6 and JSX in ESLint. Unfortunately, we were hampered by bugs that were part of Esprima (not necessarily Facebook's code). Since `esprima-fb` tracks the Esprima Harmony branch, that means we still were unable to get fixes or features we needed in a timely manner.\n\n### Why don't you just use Acorn?\n\nAcorn is a great JavaScript parser that produces an AST that is compatible with Esprima. Unfortunately, ESLint relies on more than just the AST to do its job. It relies on Esprima's tokens and comment attachment features to get a complete picture of the source code. We investigated switching to Acorn, but the inconsistencies between Esprima and Acorn created too much work for a project like ESLint.\n\nWe expect there are other tools like ESLint that rely on more than just the AST produced by Esprima, and so a drop-in replacement will help those projects as well as ESLint.\n\n### What ECMAScript 6 features do you support?\n\nPlease see the [tracking issue](https://github.com/eslint/espree/issues/10) for the most up-to-date information.\n\n### Why use Espree instead of Esprima?\n\n* Faster turnaround time on bug fixes\n* More frequent releases\n* Better communication and responsiveness to issues\n* Ongoing development\n\n### Why use Espree instead of Esprima-FB?\n\n* Opt-in to just the ECMAScript 6 features you want\n* JSX support is off by default, so you're not forced to use it to use ECMAScript 6\n* Stricter ECMAScript 6 support\n", "readmeFilename": "README.md", - "_id": "espree@1.9.1", - "_shasum": "f1ac59e5b56c6ac4351f8beb27293c1cee73112f", - "_from": "espree@~1.9.1", - "_resolved": "https://registry.npmjs.org/espree/-/espree-1.9.1.tgz" + "_id": "espree@1.12.0", + "_shasum": "18980ba9121d325a626d9e732e2e47f524278383", + "_from": "espree@~1.12.0", + "_resolved": "https://registry.npmjs.org/espree/-/espree-1.12.0.tgz" } diff --git a/package.json b/package.json index 1a51e2c5..825220cc 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "bluebird": "~2.9.14", "catharsis": "~0.8.6", "escape-string-regexp": "~1.0.2", - "espree": "~1.9.1", + "espree": "~1.12.0", "js2xmlparser": "~0.1.7", "marked": "~0.3.2", "requizzle": "~0.2.0",