vendor/assets/javascripts/eslint.js in eslint-rails-0.1.1 vs vendor/assets/javascripts/eslint.js in eslint-rails-0.2.0

- old
+ new

@@ -43,36 +43,32 @@ /** * Create an Array Expression ASTNode out of an array of elements * @param {ASTNode[]} elements An array of ASTNode elements * @returns {ASTNode} An ASTNode representing the entire array expression */ - createArrayExpression: function (elements) { + createArrayExpression: function(elements) { return { type: astNodeTypes.ArrayExpression, elements: elements }; }, /** * Create an Arrow Function Expression ASTNode * @param {ASTNode} params The function arguments - * @param {ASTNode} defaults Any default arguments * @param {ASTNode} body The function body - * @param {ASTNode} rest The rest parameter * @param {boolean} expression True if the arrow function is created via an expression. * Always false for declarations, but kept here to be in sync with * FunctionExpression objects. * @returns {ASTNode} An ASTNode representing the entire arrow function expression */ - createArrowFunctionExpression: function (params, defaults, body, rest, expression) { + createArrowFunctionExpression: function (params, body, expression) { return { type: astNodeTypes.ArrowFunctionExpression, id: null, params: params, - defaults: defaults, body: body, - rest: rest, generator: false, expression: expression }; }, @@ -81,27 +77,41 @@ * @param {ASTNode} operator The assignment operator * @param {ASTNode} left The left operand * @param {ASTNode} right The right operand * @returns {ASTNode} An ASTNode representing the entire assignment expression */ - createAssignmentExpression: function (operator, left, right) { + createAssignmentExpression: function(operator, left, right) { return { type: astNodeTypes.AssignmentExpression, operator: operator, left: left, right: right }; }, /** + * Create an ASTNode representation of an assignment pattern (default parameters) + * @param {ASTNode} left The left operand + * @param {ASTNode} right The right operand + * @returns {ASTNode} An ASTNode representing the entire assignment pattern + */ + createAssignmentPattern: function(left, right) { + return { + type: astNodeTypes.AssignmentPattern, + left: left, + right: right + }; + }, + + /** * Create an ASTNode representation of a binary expression * @param {ASTNode} operator The assignment operator * @param {ASTNode} left The left operand * @param {ASTNode} right The right operand * @returns {ASTNode} An ASTNode representing the entire binary expression */ - createBinaryExpression: function (operator, left, right) { + createBinaryExpression: function(operator, left, right) { var type = (operator === "||" || operator === "&&") ? astNodeTypes.LogicalExpression : astNodeTypes.BinaryExpression; return { type: type, operator: operator, @@ -113,11 +123,11 @@ /** * Create an ASTNode representation of a block statement * @param {ASTNode} body The block statement body * @returns {ASTNode} An ASTNode representing the entire block statement */ - createBlockStatement: function (body) { + createBlockStatement: function(body) { return { type: astNodeTypes.BlockStatement, body: body }; }, @@ -125,11 +135,11 @@ /** * Create an ASTNode representation of a break statement * @param {ASTNode} label The break statement label * @returns {ASTNode} An ASTNode representing the break statement */ - createBreakStatement: function (label) { + createBreakStatement: function(label) { return { type: astNodeTypes.BreakStatement, label: label }; }, @@ -138,11 +148,11 @@ * Create an ASTNode representation of a call expression * @param {ASTNode} callee The function being called * @param {ASTNode[]} args An array of ASTNodes representing the function call arguments * @returns {ASTNode} An ASTNode representing the entire call expression */ - createCallExpression: function (callee, args) { + createCallExpression: function(callee, args) { return { type: astNodeTypes.CallExpression, callee: callee, "arguments": args }; @@ -152,11 +162,11 @@ * Create an ASTNode representation of a catch clause/block * @param {ASTNode} param Any catch clause exeption/conditional parameter information * @param {ASTNode} body The catch block body * @returns {ASTNode} An ASTNode representing the entire catch clause */ - createCatchClause: function (param, body) { + createCatchClause: function(param, body) { return { type: astNodeTypes.CatchClause, param: param, body: body }; @@ -165,54 +175,62 @@ /** * 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) { + createClassBody: function(body) { return { type: astNodeTypes.ClassBody, body: body }; }, - createClassExpression: function (id, superClass, body) { + createClassExpression: function(id, superClass, body) { return { type: astNodeTypes.ClassExpression, id: id, superClass: superClass, body: body }; }, - createClassDeclaration: function (id, superClass, body) { + createClassDeclaration: function(id, superClass, body) { return { type: astNodeTypes.ClassDeclaration, id: id, superClass: superClass, body: body }; }, - createMethodDefinition: function (propertyType, kind, key, value, computed) { + createMethodDefinition: function(propertyType, kind, key, value, computed) { return { type: astNodeTypes.MethodDefinition, key: key, value: value, kind: kind, "static": propertyType === "static", computed: computed }; }, + createMetaProperty: function(meta, property) { + return { + type: astNodeTypes.MetaProperty, + meta: meta, + property: property + }; + }, + /** * Create an ASTNode representation of a conditional expression * @param {ASTNode} test The conditional to evaluate * @param {ASTNode} consequent The code to be run if the test returns true * @param {ASTNode} alternate The code to be run if the test returns false * @returns {ASTNode} An ASTNode representing the entire conditional expression */ - createConditionalExpression: function (test, consequent, alternate) { + createConditionalExpression: function(test, consequent, alternate) { return { type: astNodeTypes.ConditionalExpression, test: test, consequent: consequent, alternate: alternate @@ -222,43 +240,43 @@ /** * Create an ASTNode representation of a continue statement * @param {?ASTNode} label The optional continue label (null if not set) * @returns {ASTNode} An ASTNode representing the continue statement */ - createContinueStatement: function (label) { + createContinueStatement: function(label) { return { type: astNodeTypes.ContinueStatement, label: label }; }, /** * Create an ASTNode representation of a debugger statement * @returns {ASTNode} An ASTNode representing the debugger statement */ - createDebuggerStatement: function () { + createDebuggerStatement: function() { return { type: astNodeTypes.DebuggerStatement }; }, /** * Create an ASTNode representation of an empty statement * @returns {ASTNode} An ASTNode representing an empty statement */ - createEmptyStatement: function () { + createEmptyStatement: function() { return { type: astNodeTypes.EmptyStatement }; }, /** * Create an ASTNode representation of an expression statement * @param {ASTNode} expression The expression * @returns {ASTNode} An ASTNode representing an expression statement */ - createExpressionStatement: function (expression) { + createExpressionStatement: function(expression) { return { type: astNodeTypes.ExpressionStatement, expression: expression }; }, @@ -267,11 +285,11 @@ * Create an ASTNode representation of a while statement * @param {ASTNode} test The while conditional * @param {ASTNode} body The while loop body * @returns {ASTNode} An ASTNode representing a while statement */ - createWhileStatement: function (test, body) { + createWhileStatement: function(test, body) { return { type: astNodeTypes.WhileStatement, test: test, body: body }; @@ -281,11 +299,11 @@ * Create an ASTNode representation of a do..while statement * @param {ASTNode} test The do..while conditional * @param {ASTNode} body The do..while loop body * @returns {ASTNode} An ASTNode representing a do..while statement */ - createDoWhileStatement: function (test, body) { + createDoWhileStatement: function(test, body) { return { type: astNodeTypes.DoWhileStatement, body: body, test: test }; @@ -297,11 +315,11 @@ * @param {ASTNode} test The conditional test expression * @param {ASTNode} update The update expression * @param {ASTNode} body The statement body * @returns {ASTNode} An ASTNode representing a for statement */ - createForStatement: function (init, test, update, body) { + createForStatement: function(init, test, update, body) { return { type: astNodeTypes.ForStatement, init: init, test: test, update: update, @@ -314,11 +332,11 @@ * @param {ASTNode} left The left-side variable for the property name * @param {ASTNode} right The right-side object * @param {ASTNode} body The statement body * @returns {ASTNode} An ASTNode representing a for..in statement */ - createForInStatement: function (left, right, body) { + createForInStatement: function(left, right, body) { return { type: astNodeTypes.ForInStatement, left: left, right: right, body: body, @@ -331,11 +349,11 @@ * @param {ASTNode} left The left-side variable for the property value * @param {ASTNode} right The right-side object * @param {ASTNode} body The statement body * @returns {ASTNode} An ASTNode representing a for..of statement */ - createForOfStatement: function (left, right, body) { + createForOfStatement: function(left, right, body) { return { type: astNodeTypes.ForOfStatement, left: left, right: right, body: body @@ -344,62 +362,54 @@ /** * Create an ASTNode representation of a function declaration * @param {ASTNode} id The function name * @param {ASTNode} params The function arguments - * @param {ASTNode} defaults Any default arguments (ES6-only feature) * @param {ASTNode} body The function body - * @param {ASTNode} rest The node representing a rest argument. * @param {boolean} generator True if the function is a generator, false if not. * @param {boolean} expression True if the function is created via an expression. * Always false for declarations, but kept here to be in sync with * FunctionExpression objects. * @returns {ASTNode} An ASTNode representing a function declaration */ - createFunctionDeclaration: function (id, params, defaults, body, rest, generator, expression) { + createFunctionDeclaration: function (id, params, body, generator, expression) { return { type: astNodeTypes.FunctionDeclaration, id: id, params: params || [], - defaults: defaults || [], body: body, - rest: rest || null, generator: !!generator, expression: !!expression }; }, /** * Create an ASTNode representation of a function expression * @param {ASTNode} id The function name * @param {ASTNode} params The function arguments - * @param {ASTNode} defaults Any default arguments (ES6-only feature) * @param {ASTNode} body The function body - * @param {ASTNode} rest The node representing a rest argument. * @param {boolean} generator True if the function is a generator, false if not. * @param {boolean} expression True if the function is created via an expression. * @returns {ASTNode} An ASTNode representing a function declaration */ - createFunctionExpression: function (id, params, defaults, body, rest, generator, expression) { + createFunctionExpression: function (id, params, body, generator, expression) { return { type: astNodeTypes.FunctionExpression, id: id, params: params || [], - defaults: defaults || [], body: body, - rest: rest || null, generator: !!generator, expression: !!expression }; }, /** * Create an ASTNode representation of an identifier * @param {ASTNode} name The identifier name * @returns {ASTNode} An ASTNode representing an identifier */ - createIdentifier: function (name) { + createIdentifier: function(name) { return { type: astNodeTypes.Identifier, name: name }; }, @@ -409,11 +419,11 @@ * @param {ASTNode} test The if conditional expression * @param {ASTNode} consequent The consequent if statement to run * @param {ASTNode} alternate the "else" alternate statement * @returns {ASTNode} An ASTNode representing an if statement */ - createIfStatement: function (test, consequent, alternate) { + createIfStatement: function(test, consequent, alternate) { return { type: astNodeTypes.IfStatement, test: test, consequent: consequent, alternate: alternate @@ -424,11 +434,11 @@ * Create an ASTNode representation of a labeled statement * @param {ASTNode} label The statement label * @param {ASTNode} body The labeled statement body * @returns {ASTNode} An ASTNode representing a labeled statement */ - createLabeledStatement: function (label, body) { + createLabeledStatement: function(label, body) { return { type: astNodeTypes.LabeledStatement, label: label, body: body }; @@ -438,11 +448,11 @@ * Create an ASTNode literal from the source code * @param {ASTNode} token The ASTNode token * @param {string} source The source code to get the literal from * @returns {ASTNode} An ASTNode representing the new literal */ - createLiteralFromSource: function (token, source) { + createLiteralFromSource: function(token, source) { var node = { type: astNodeTypes.Literal, value: token.value, raw: source.slice(token.range[0], token.range[1]) }; @@ -461,11 +471,11 @@ * @param {string} value.raw The raw template string * @param {string} value.cooked The processed template string * @param {boolean} tail True if this is the final element in a template string * @returns {ASTNode} An ASTNode representing the template string element */ - createTemplateElement: function (value, tail) { + createTemplateElement: function(value, tail) { return { type: astNodeTypes.TemplateElement, value: value, tail: tail }; @@ -475,11 +485,11 @@ * Create an ASTNode template literal * @param {ASTNode[]} quasis An array of the template string elements * @param {ASTNode[]} expressions An array of the template string expressions * @returns {ASTNode} An ASTNode representing the template string */ - createTemplateLiteral: function (quasis, expressions) { + createTemplateLiteral: function(quasis, expressions) { return { type: astNodeTypes.TemplateLiteral, quasis: quasis, expressions: expressions }; @@ -488,25 +498,49 @@ /** * Create an ASTNode representation of a spread element * @param {ASTNode} argument The array being spread * @returns {ASTNode} An ASTNode representing a spread element */ - createSpreadElement: function (argument) { + createSpreadElement: function(argument) { return { type: astNodeTypes.SpreadElement, argument: argument }; }, /** + * Create an ASTNode representation of an experimental rest property + * @param {ASTNode} argument The identifier being rested + * @returns {ASTNode} An ASTNode representing a rest element + */ + createExperimentalRestProperty: function(argument) { + return { + type: astNodeTypes.ExperimentalRestProperty, + argument: argument + }; + }, + + /** + * Create an ASTNode representation of an experimental spread property + * @param {ASTNode} argument The identifier being spread + * @returns {ASTNode} An ASTNode representing a spread element + */ + createExperimentalSpreadProperty: function(argument) { + return { + type: astNodeTypes.ExperimentalSpreadProperty, + argument: argument + }; + }, + + /** * Create an ASTNode tagged template expression * @param {ASTNode} tag The tag expression * @param {ASTNode} quasi A TemplateLiteral ASTNode representing * the template string itself. * @returns {ASTNode} An ASTNode representing the tagged template */ - createTaggedTemplateExpression: function (tag, quasi) { + createTaggedTemplateExpression: function(tag, quasi) { return { type: astNodeTypes.TaggedTemplateExpression, tag: tag, quasi: quasi }; @@ -517,11 +551,11 @@ * @param {string} accessor The member access method (bracket or period) * @param {ASTNode} object The object being referenced * @param {ASTNode} property The object-property being referenced * @returns {ASTNode} An ASTNode representing a member expression */ - createMemberExpression: function (accessor, object, property) { + createMemberExpression: function(accessor, object, property) { return { type: astNodeTypes.MemberExpression, computed: accessor === "[", object: object, property: property @@ -532,11 +566,11 @@ * Create an ASTNode representation of a new expression * @param {ASTNode} callee The constructor for the new object type * @param {ASTNode} args The arguments passed to the constructor * @returns {ASTNode} An ASTNode representing a new expression */ - createNewExpression: function (callee, args) { + createNewExpression: function(callee, args) { return { type: astNodeTypes.NewExpression, callee: callee, "arguments": args }; @@ -546,11 +580,11 @@ * Create an ASTNode representation of a new object expression * @param {ASTNode[]} properties An array of ASTNodes that represent all object * properties and associated values * @returns {ASTNode} An ASTNode representing a new object expression */ - createObjectExpression: function (properties) { + createObjectExpression: function(properties) { return { type: astNodeTypes.ObjectExpression, properties: properties }; }, @@ -559,11 +593,11 @@ * Create an ASTNode representation of a postfix expression * @param {string} operator The postfix operator ("++", "--", etc.) * @param {ASTNode} argument The operator argument * @returns {ASTNode} An ASTNode representing a postfix expression */ - createPostfixExpression: function (operator, argument) { + createPostfixExpression: function(operator, argument) { return { type: astNodeTypes.UpdateExpression, operator: operator, argument: argument, prefix: false @@ -571,16 +605,18 @@ }, /** * 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 }; }, /** * Create an ASTNode representation of an object property @@ -590,11 +626,11 @@ * @param {boolean} method True if the property is also a method (value is a function) * @param {boolean} shorthand True if the property is shorthand * @param {boolean} computed True if the property value has been computed * @returns {ASTNode} An ASTNode representing an object property */ - createProperty: function (kind, key, value, method, shorthand, computed) { + createProperty: function(kind, key, value, method, shorthand, computed) { return { type: astNodeTypes.Property, key: key, value: value, kind: kind, @@ -603,15 +639,27 @@ computed: computed }; }, /** + * Create an ASTNode representation of a rest element + * @param {ASTNode} argument The rest argument + * @returns {ASTNode} An ASTNode representing a rest element + */ + createRestElement: function (argument) { + return { + type: astNodeTypes.RestElement, + argument: argument + }; + }, + + /** * Create an ASTNode representation of a return statement * @param {?ASTNode} argument The return argument, null if no argument is provided * @returns {ASTNode} An ASTNode representing a return statement */ - createReturnStatement: function (argument) { + createReturnStatement: function(argument) { return { type: astNodeTypes.ReturnStatement, argument: argument }; }, @@ -619,24 +667,34 @@ /** * Create an ASTNode representation of a sequence of expressions * @param {ASTNode[]} expressions An array containing each expression, in order * @returns {ASTNode} An ASTNode representing a sequence of expressions */ - createSequenceExpression: function (expressions) { + createSequenceExpression: function(expressions) { return { type: astNodeTypes.SequenceExpression, expressions: expressions }; }, /** + * Create an ASTNode representation of super + * @returns {ASTNode} An ASTNode representing super + */ + createSuper: function() { + return { + type: astNodeTypes.Super + }; + }, + + /** * Create an ASTNode representation of a switch case statement * @param {ASTNode} test The case value to test against the switch value * @param {ASTNode} consequent The consequent case statement * @returns {ASTNode} An ASTNode representing a switch case */ - createSwitchCase: function (test, consequent) { + createSwitchCase: function(test, consequent) { return { type: astNodeTypes.SwitchCase, test: test, consequent: consequent }; @@ -646,11 +704,11 @@ * Create an ASTNode representation of a switch statement * @param {ASTNode} discriminant An expression to test against each case value * @param {ASTNode[]} cases An array of switch case statements * @returns {ASTNode} An ASTNode representing a switch statement */ - createSwitchStatement: function (discriminant, cases) { + createSwitchStatement: function(discriminant, cases) { return { type: astNodeTypes.SwitchStatement, discriminant: discriminant, cases: cases }; @@ -658,22 +716,22 @@ /** * Create an ASTNode representation of a this statement * @returns {ASTNode} An ASTNode representing a this statement */ - createThisExpression: function () { + createThisExpression: function() { return { type: astNodeTypes.ThisExpression }; }, /** * Create an ASTNode representation of a throw statement * @param {ASTNode} argument The argument to throw * @returns {ASTNode} An ASTNode representing a throw statement */ - createThrowStatement: function (argument) { + createThrowStatement: function(argument) { return { type: astNodeTypes.ThrowStatement, argument: argument }; }, @@ -683,16 +741,14 @@ * @param {ASTNode} block The try block * @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, handler, finalizer) { + createTryStatement: function(block, handler, finalizer) { return { type: astNodeTypes.TryStatement, block: block, - guardedHandlers: [], - handlers: handler ? [ handler ] : [], handler: handler, finalizer: finalizer }; }, @@ -700,11 +756,11 @@ * Create an ASTNode representation of a unary expression * @param {string} operator The unary operator * @param {ASTNode} argument The unary operand * @returns {ASTNode} An ASTNode representing a unary expression */ - createUnaryExpression: function (operator, argument) { + createUnaryExpression: function(operator, argument) { if (operator === "++" || operator === "--") { return { type: astNodeTypes.UpdateExpression, operator: operator, argument: argument, @@ -723,11 +779,11 @@ * Create an ASTNode representation of a variable declaration * @param {ASTNode[]} declarations An array of variable declarations * @param {string} kind The kind of variable created ("var", "let", etc.) * @returns {ASTNode} An ASTNode representing a variable declaration */ - createVariableDeclaration: function (declarations, kind) { + createVariableDeclaration: function(declarations, kind) { return { type: astNodeTypes.VariableDeclaration, declarations: declarations, kind: kind }; @@ -737,11 +793,11 @@ * Create an ASTNode representation of a variable declarator * @param {ASTNode} id The variable ID * @param {ASTNode} init The variable's initial value * @returns {ASTNode} An ASTNode representing a variable declarator */ - createVariableDeclarator: function (id, init) { + createVariableDeclarator: function(id, init) { return { type: astNodeTypes.VariableDeclarator, id: id, init: init }; @@ -751,156 +807,156 @@ * Create an ASTNode representation of a with statement * @param {ASTNode} object The with statement object expression * @param {ASTNode} body The with statement body * @returns {ASTNode} An ASTNode representing a with statement */ - createWithStatement: function (object, body) { + createWithStatement: function(object, body) { return { type: astNodeTypes.WithStatement, object: object, body: body }; }, - createYieldExpression: function (argument, delegate) { + createYieldExpression: function(argument, delegate) { return { type: astNodeTypes.YieldExpression, - argument: argument, + argument: argument || null, delegate: delegate }; }, - createJSXAttribute: function (name, value) { + createJSXAttribute: function(name, value) { return { type: astNodeTypes.JSXAttribute, name: name, value: value || null }; }, - createJSXSpreadAttribute: function (argument) { + createJSXSpreadAttribute: function(argument) { return { type: astNodeTypes.JSXSpreadAttribute, argument: argument }; }, - createJSXIdentifier: function (name) { + createJSXIdentifier: function(name) { return { type: astNodeTypes.JSXIdentifier, name: name }; }, - createJSXNamespacedName: function (namespace, name) { + createJSXNamespacedName: function(namespace, name) { return { type: astNodeTypes.JSXNamespacedName, namespace: namespace, name: name }; }, - createJSXMemberExpression: function (object, property) { + createJSXMemberExpression: function(object, property) { return { type: astNodeTypes.JSXMemberExpression, object: object, property: property }; }, - createJSXElement: function (openingElement, closingElement, children) { + createJSXElement: function(openingElement, closingElement, children) { return { type: astNodeTypes.JSXElement, openingElement: openingElement, closingElement: closingElement, children: children }; }, - createJSXEmptyExpression: function () { + createJSXEmptyExpression: function() { return { type: astNodeTypes.JSXEmptyExpression }; }, - createJSXExpressionContainer: function (expression) { + createJSXExpressionContainer: function(expression) { return { type: astNodeTypes.JSXExpressionContainer, expression: expression }; }, - createJSXOpeningElement: function (name, attributes, selfClosing) { + createJSXOpeningElement: function(name, attributes, selfClosing) { return { type: astNodeTypes.JSXOpeningElement, name: name, selfClosing: selfClosing, attributes: attributes }; }, - createJSXClosingElement: function (name) { + createJSXClosingElement: function(name) { return { type: astNodeTypes.JSXClosingElement, name: name }; }, - createExportSpecifier: function (local, exported) { + createExportSpecifier: function(local, exported) { return { type: astNodeTypes.ExportSpecifier, exported: exported || local, local: local }; }, - createImportDefaultSpecifier: function (local) { + createImportDefaultSpecifier: function(local) { return { type: astNodeTypes.ImportDefaultSpecifier, local: local }; }, - createImportNamespaceSpecifier: function (local) { + createImportNamespaceSpecifier: function(local) { return { type: astNodeTypes.ImportNamespaceSpecifier, local: local }; }, - createExportNamedDeclaration: function (declaration, specifiers, source) { + createExportNamedDeclaration: function(declaration, specifiers, source) { return { type: astNodeTypes.ExportNamedDeclaration, declaration: declaration, specifiers: specifiers, source: source }; }, - createExportDefaultDeclaration: function (declaration) { + createExportDefaultDeclaration: function(declaration) { return { type: astNodeTypes.ExportDefaultDeclaration, declaration: declaration }; }, - createExportAllDeclaration: function (source) { + createExportAllDeclaration: function(source) { return { type: astNodeTypes.ExportAllDeclaration, source: source }; }, - createImportSpecifier: function (local, imported) { + createImportSpecifier: function(local, imported) { return { type: astNodeTypes.ImportSpecifier, local: local || imported, imported: imported }; }, - createImportDeclaration: function (specifiers, source) { + createImportDeclaration: function(specifiers, source) { return { type: astNodeTypes.ImportDeclaration, specifiers: specifiers, source: source }; @@ -965,10 +1021,12 @@ ConditionalExpression: "ConditionalExpression", ContinueStatement: "ContinueStatement", DoWhileStatement: "DoWhileStatement", DebuggerStatement: "DebuggerStatement", EmptyStatement: "EmptyStatement", + ExperimentalRestProperty: "ExperimentalRestProperty", + ExperimentalSpreadProperty: "ExperimentalSpreadProperty", ExpressionStatement: "ExpressionStatement", ForStatement: "ForStatement", ForInStatement: "ForInStatement", ForOfStatement: "ForOfStatement", FunctionDeclaration: "FunctionDeclaration", @@ -977,19 +1035,22 @@ IfStatement: "IfStatement", Literal: "Literal", LabeledStatement: "LabeledStatement", LogicalExpression: "LogicalExpression", MemberExpression: "MemberExpression", + MetaProperty: "MetaProperty", MethodDefinition: "MethodDefinition", NewExpression: "NewExpression", ObjectExpression: "ObjectExpression", ObjectPattern: "ObjectPattern", Program: "Program", Property: "Property", + RestElement: "RestElement", ReturnStatement: "ReturnStatement", SequenceExpression: "SequenceExpression", SpreadElement: "SpreadElement", + Super: "Super", SwitchCase: "SwitchCase", SwitchStatement: "SwitchStatement", TaggedTemplateExpression: "TaggedTemplateExpression", TemplateElement: "TemplateElement", TemplateLiteral: "TemplateLiteral", @@ -1134,13 +1195,25 @@ 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; + if (lastChild.leadingComments) { + if (lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) { + node.leadingComments = lastChild.leadingComments; + delete lastChild.leadingComments; + } else { + // A leading comment for an anonymous class had been stolen by its first MethodDefinition, + // so this takes back the leading comment. + // See Also: https://github.com/eslint/espree/issues/158 + for (i = lastChild.leadingComments.length - 2; i >= 0; --i) { + if (lastChild.leadingComments[i].range[1] <= node.range[0]) { + node.leadingComments = lastChild.leadingComments.splice(0, i + 1); + break; + } + } + } } } else if (extra.leadingComments.length > 0) { if (extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) { node.leadingComments = extra.leadingComments; @@ -1298,18 +1371,24 @@ superInFunctions: false, // enable parsing of classes classes: false, + // enable parsing of new.target + newTarget: false, + // enable parsing of modules modules: false, // React JSX parsing jsx: false, // allow return statement in global scope - globalReturn: false + globalReturn: false, + + // allow experimental object rest/spread + experimentalObjectRestSpread: false }; },{}],5:[function(require,module,exports){ /** * @fileoverview Error messages returned by the parser. @@ -1379,11 +1458,12 @@ StrictModeWith: "Strict mode code may not include a with statement", StrictCatchVariable: "Catch variable may not be eval or arguments in strict mode", StrictVarName: "Variable name may not be eval or arguments in strict mode", StrictParamName: "Parameter name eval or arguments is not allowed in strict mode", StrictParamDupe: "Strict mode function may not have duplicate parameter names", - ParameterAfterRestParameter: "Rest parameter must be final parameter of an argument list", + TemplateOctalLiteral: "Octal literals are not allowed in template strings.", + ParameterAfterRestParameter: "Rest parameter must be last formal parameter", DefaultRestParameter: "Rest parameter can not have a default value", ElementAfterSpreadElement: "Spread must be the final element of an element list", ObjectPatternAsRestParameter: "Invalid rest parameter", ObjectPatternAsSpread: "Invalid spread argument", StrictFunctionName: "Function name may not be eval or arguments in strict mode", @@ -1581,11 +1661,11 @@ default: return false; } }, - isStrictModeReservedWord: function(id) { + isStrictModeReservedWord: function(id, ecmaFeatures) { switch (id) { case "implements": case "interface": case "package": case "private": @@ -1593,10 +1673,12 @@ case "public": case "static": case "yield": case "let": return true; + case "await": + return ecmaFeatures.modules; default: return false; } }, @@ -1606,11 +1688,11 @@ // 7.6.1.1 Keywords isKeyword: function(id, strict, ecmaFeatures) { - if (strict && this.isStrictModeReservedWord(id)) { + if (strict && this.isStrictModeReservedWord(id, ecmaFeatures)) { return true; } // "const" is specialized as Keyword in V8. // "yield" and "let" are for compatiblity with SpiderMonkey and ES.next. @@ -2043,56 +2125,64 @@ diams: "\u2666" }; },{}],10:[function(require,module,exports){ module.exports={ - "name": "espree", - "description": "An actively-maintained fork of Esprima, the ECMAScript parsing infrastructure for multipurpose analysis", + "_args": [ + [ + "espree@^2.2.4", + "/Users/force/code/eslint" + ] + ], + "_from": "espree@>=2.2.4 <3.0.0", + "_id": "espree@2.2.5", + "_inCache": true, + "_installable": true, + "_location": "/espree", + "_npmUser": { + "email": "nicholas@nczconsulting.com", + "name": "nzakas" + }, + "_npmVersion": "1.4.28", + "_phantomChildren": {}, + "_requested": { + "name": "espree", + "raw": "espree@^2.2.4", + "rawSpec": "^2.2.4", + "scope": null, + "spec": ">=2.2.4 <3.0.0", + "type": "range" + }, + "_requiredBy": [ + "/", + "/jsdoc" + ], + "_resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz", + "_shasum": "df691b9310889402aeb29cc066708c56690b854b", + "_shrinkwrap": null, + "_spec": "espree@^2.2.4", + "_where": "/Users/force/code/eslint", "author": { - "name": "Nicholas C. Zakas", - "email": "nicholas+npm@nczconsulting.com" + "email": "nicholas+npm@nczconsulting.com", + "name": "Nicholas C. Zakas" }, - "homepage": "https://github.com/eslint/espree", - "main": "espree.js", "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" }, - "version": "1.11.0", - "files": [ - "bin", - "lib", - "test/run.js", - "test/runner.js", - "test/test.js", - "test/compat.js", - "test/reflect.js", - "espree.js" - ], - "engines": { - "node": ">=0.10.0" - }, - "repository": { - "type": "git", - "url": "http://github.com/eslint/espree.git" - }, "bugs": { "url": "http://github.com/eslint/espree.git" }, - "licenses": [ - { - "type": "BSD", - "url": "http://github.com/nzakas/espree/raw/master/LICENSE" - } - ], + "dependencies": {}, + "description": "An actively-maintained fork of Esprima, the ECMAScript parsing infrastructure for multipurpose analysis", "devDependencies": { "browserify": "^7.0.0", "chai": "^1.10.0", "complexity-report": "~0.6.1", "dateformat": "^1.0.11", "eslint": "^0.9.2", - "esprima": "git://github.com/ariya/esprima#harmony", + "esprima": "git://github.com/jquery/esprima.git", "esprima-fb": "^8001.2001.0-dev-harmony-fb", "istanbul": "~0.2.6", "json-diff": "~0.3.1", "leche": "^1.0.1", "mocha": "^2.0.1", @@ -2102,56 +2192,75 @@ "semver": "^4.1.1", "shelljs": "^0.3.0", "shelljs-nodecli": "^0.1.1", "unicode-6.3.0": "~0.1.0" }, + "directories": {}, + "dist": { + "shasum": "df691b9310889402aeb29cc066708c56690b854b", + "tarball": "http://registry.npmjs.org/espree/-/espree-2.2.5.tgz" + }, + "engines": { + "node": ">=0.10.0" + }, + "files": [ + "bin", + "espree.js", + "lib", + "test/compat.js", + "test/reflect.js", + "test/run.js", + "test/runner.js", + "test/test.js" + ], + "gitHead": "eeeeb05b879783901ff2308efcbd0cda76753cbe", + "homepage": "https://github.com/eslint/espree", "keywords": [ "ast", "ecmascript", "javascript", "parser", "syntax" ], - "scripts": { - "generate-regex": "node tools/generate-identifier-regex.js", - "test": "npm run-script lint && node Makefile.js test && node test/run.js", - "lint": "node Makefile.js lint", - "patch": "node Makefile.js patch", - "minor": "node Makefile.js minor", - "major": "node Makefile.js major", - "browserify": "node Makefile.js browserify", - "coverage": "npm run-script analyze-coverage && npm run-script check-coverage", - "analyze-coverage": "node node_modules/istanbul/lib/cli.js cover test/runner.js", - "check-coverage": "node node_modules/istanbul/lib/cli.js check-coverage --statement 99 --branch 99 --function 99", - "complexity": "npm run-script analyze-complexity && npm run-script check-complexity", - "analyze-complexity": "node tools/list-complexity.js", - "check-complexity": "node node_modules/complexity-report/src/cli.js --maxcc 14 --silent -l -w espree.js", - "benchmark": "node test/benchmarks.js", - "benchmark-quick": "node test/benchmarks.js quick" - }, - "dependencies": {}, - "gitHead": "06fdcd69a6a6006a635910c8c80baaab931cb0cd", - "_id": "espree@1.11.0", - "_shasum": "862c3033fad49ea1f3c5446fbab7650d7759186b", - "_from": "espree@>=1.11.0 <2.0.0", - "_npmVersion": "1.4.28", - "_npmUser": { - "name": "nzakas", - "email": "nicholas@nczconsulting.com" - }, + "licenses": [ + { + "type": "BSD", + "url": "http://github.com/nzakas/espree/raw/master/LICENSE" + } + ], + "main": "espree.js", "maintainers": [ { "name": "nzakas", "email": "nicholas@nczconsulting.com" } ], - "dist": { - "shasum": "862c3033fad49ea1f3c5446fbab7650d7759186b", - "tarball": "http://registry.npmjs.org/espree/-/espree-1.11.0.tgz" + "name": "espree", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/eslint/espree.git" }, - "_resolved": "https://registry.npmjs.org/espree/-/espree-1.11.0.tgz", - "readme": "ERROR: No README data found!" + "scripts": { + "analyze-complexity": "node tools/list-complexity.js", + "analyze-coverage": "node node_modules/istanbul/lib/cli.js cover test/runner.js", + "benchmark": "node test/benchmarks.js", + "benchmark-quick": "node test/benchmarks.js quick", + "browserify": "node Makefile.js browserify", + "check-complexity": "node node_modules/complexity-report/src/cli.js --maxcc 14 --silent -l -w espree.js", + "check-coverage": "node node_modules/istanbul/lib/cli.js check-coverage --statement 99 --branch 99 --function 99", + "complexity": "npm run-script analyze-complexity && npm run-script check-complexity", + "coverage": "npm run-script analyze-coverage && npm run-script check-coverage", + "generate-regex": "node tools/generate-identifier-regex.js", + "lint": "node Makefile.js lint", + "major": "node Makefile.js major", + "minor": "node Makefile.js minor", + "patch": "node Makefile.js patch", + "test": "npm run-script lint && node Makefile.js test && node test/run.js" + }, + "version": "2.2.5" } },{}],"espree":[function(require,module,exports){ /* Copyright (C) 2015 Fred K. Schott <fkschott@gmail.com> @@ -2580,25 +2689,49 @@ // Check for most common single-character punctuators. case 40: // ( open bracket case 41: // ) close bracket case 59: // ; semicolon case 44: // , comma - case 123: // { open curly brace - case 125: // } close curly brace case 91: // [ case 93: // ] case 58: // : case 63: // ? case 126: // ~ ++index; - if (extra.tokenize) { - if (code === 40) { - extra.openParenToken = extra.tokens.length; - } else if (code === 123) { - extra.openCurlyToken = extra.tokens.length; + + if (extra.tokenize && code === 40) { + extra.openParenToken = extra.tokens.length; + } + + return { + type: Token.Punctuator, + value: String.fromCharCode(code), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + + case 123: // { open curly brace + case 125: // } close curly brace + ++index; + + if (extra.tokenize && code === 123) { + extra.openCurlyToken = extra.tokens.length; + } + + // lookahead2 function can cause tokens to be scanned twice and in doing so + // would wreck the curly stack by pushing the same token onto the stack twice. + // curlyLastIndex ensures each token is pushed or popped exactly once + if (index > state.curlyLastIndex) { + state.curlyLastIndex = index; + if (code === 123) { + state.curlyStack.push("{"); + } else { + state.curlyStack.pop(); } } + return { type: Token.Punctuator, value: String.fromCharCode(code), lineNumber: lineNumber, lineStart: lineStart, @@ -2709,10 +2842,11 @@ } // The ... operator (spread, restParams, JSX, etc.) if (extra.ecmaFeatures.spread || extra.ecmaFeatures.restParams || + extra.ecmaFeatures.experimentalObjectRestSpread || (extra.ecmaFeatures.jsx && state.inJSXSpreadAttribute) ) { if (ch1 === "." && ch2 === "." && ch3 === ".") { index += 3; return { @@ -3103,11 +3237,10 @@ */ function scanTemplate() { var cooked = "", ch, escapedSequence, - octal = false, start = index, terminated = false, tail = false, head = (source[index] === "`"); @@ -3128,12 +3261,17 @@ } cooked += ch; } else if (ch === "\\") { ch = source[index++]; escapedSequence = scanEscapeSequence(ch); + + if (escapedSequence.octal) { + throwError({}, Messages.TemplateOctalLiteral); + } + cooked += escapedSequence.ch; - octal = escapedSequence.octal || octal; + } else if (syntax.isLineTerminator(ch.charCodeAt(0))) { ++lineNumber; if (ch === "\r" && source[index] === "\n") { ++index; } @@ -3146,56 +3284,36 @@ if (!terminated) { throwError({}, Messages.UnexpectedToken, "ILLEGAL"); } + if (index > state.curlyLastIndex) { + state.curlyLastIndex = index; + + if (!tail) { + state.curlyStack.push("template"); + } + + if (!head) { + state.curlyStack.pop(); + } + } + return { type: Token.Template, value: { cooked: cooked, raw: source.slice(start + 1, index - ((tail) ? 1 : 2)) }, head: head, tail: tail, - octal: octal, lineNumber: lineNumber, lineStart: lineStart, range: [start, index] }; } -/** - * Scan a template string element and return a ASTNode representation - * @param {Object} options Scan options - * @param {Object} options.head True if this element is the first in the - * template string, false otherwise. - * @returns {ASTNode} The template element node - * @private - */ -function scanTemplateElement(options) { - var startsWith, template; - - lookahead = null; - skipComment(); - - startsWith = (options.head) ? "`" : "}"; - - if (source[index] !== startsWith) { - throwError({}, Messages.UnexpectedToken, "ILLEGAL"); - } - - template = scanTemplate(); - - if (!template.tail) { - extra.curlies.push("template"); - } - - peek(); - - return template; -} - function testRegExp(pattern, flags) { var tmp = pattern, validFlags = "gmsi"; if (extra.ecmaFeatures.regexYFlag) { @@ -3538,12 +3656,11 @@ // Template strings start with backtick (U+0096) or closing curly brace (125) and backtick. if (allowTemplateStrings) { // 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(); } } if (syntax.isIdentifierStart(ch)) { @@ -3626,26 +3743,10 @@ index = token.range[1]; lineNumber = token.lineNumber; lineStart = token.lineStart; - if (token.type === Token.Template) { - if (token.tail) { - extra.curlies.pop(); - } else { - extra.curlies.push("template"); - } - } - - if (token.value === "{") { - extra.curlies.push("{"); - } - - if (token.value === "}") { - extra.curlies.pop(); - } - return token; } function peek() { var pos, @@ -4110,11 +4211,11 @@ /** * 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 */ function markerApply(marker, node) { @@ -4231,11 +4332,11 @@ if (typeof token.lineNumber === "number") { error = new Error("Line " + token.lineNumber + ": " + msg); error.index = token.range[0]; error.lineNumber = token.lineNumber; - error.column = token.range[0] - lineStart + 1; + error.column = token.range[0] - token.lineStart + 1; } else { error = new Error("Line " + lineNumber + ": " + msg); error.index = index; error.lineNumber = lineNumber; error.column = index - lineStart + 1; @@ -4279,11 +4380,11 @@ } if (token.type === Token.Keyword) { if (syntax.isFutureReservedWord(token.value)) { throwError(token, Messages.UnexpectedReserved); - } else if (strict && syntax.isStrictModeReservedWord(token.value)) { + } else if (strict && syntax.isStrictModeReservedWord(token.value, extra.ecmaFeatures)) { throwErrorTolerant(token, Messages.StrictReservedWord); return; } throwError(token, Messages.UnexpectedToken, token.value); } @@ -4398,15 +4499,11 @@ lex(); // only get here when you have [a,,] or similar elements.push(null); } 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 } } } @@ -4443,13 +4540,11 @@ state.yieldAllowed = previousYieldAllowed; return markerApply(options.marker, astNodeFactory.createFunctionExpression( null, paramInfo.params, - paramInfo.defaults, body, - paramInfo.rest, generator, body.type !== astNodeTypes.BlockStatement )); } @@ -4554,15 +4649,13 @@ expect("("); expect(")"); value = parsePropertyFunction({ params: [], - defaults: [], stricted: null, firstRestricted: null, - message: null, - rest: null + message: null }, { marker: methodMarker }); return markerApply(marker, astNodeFactory.createProperty("get", key, value, false, false, computed)); @@ -4574,23 +4667,18 @@ expect("("); options = { params: [], defaultCount: 0, - defaults: [], stricted: null, firstRestricted: null, - paramSet: new StringMap(), - rest: null + paramSet: new StringMap() }; if (match(")")) { - throwErrorTolerant(lookahead, Messages.UnexpectedToken); + throwErrorTolerant(lookahead, Messages.UnexpectedToken, lookahead.value); } 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)); @@ -4604,18 +4692,46 @@ // 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, computed, methodMarker, options; var allowComputed = extra.ecmaFeatures.objectLiteralComputedProperties, allowMethod = extra.ecmaFeatures.objectLiteralShorthandMethods, allowShorthand = extra.ecmaFeatures.objectLiteralShorthandProperties, allowGenerators = extra.ecmaFeatures.generators, allowDestructuring = extra.ecmaFeatures.destructuring, + allowSpread = extra.ecmaFeatures.experimentalObjectRestSpread, marker = markerCreate(); token = lookahead; computed = (token.value === "[" && token.type === Token.Punctuator); @@ -4625,11 +4741,12 @@ /* * Check for getters and setters. Be careful! "get" and "set" are legal * method names. It's only a getter or setter if followed by a space. */ - if (token.value === "get" && !(match(":") || match("("))) { + if (token.value === "get" && + !(match(":") || match("(") || match(",") || match("}"))) { computed = (lookahead.value === "["); key = parseObjectPropertyKey(); methodMarker = markerCreate(); expect("("); expect(")"); @@ -4649,33 +4766,29 @@ computed ) ); } - if (token.value === "set" && !(match(":") || match("("))) { + if (token.value === "set" && + !(match(":") || match("(") || match(",") || match("}"))) { computed = (lookahead.value === "["); key = parseObjectPropertyKey(); methodMarker = markerCreate(); expect("("); options = { params: [], defaultCount: 0, - defaults: [], stricted: null, firstRestricted: null, - paramSet: new StringMap(), - rest: null + paramSet: new StringMap() }; if (match(")")) { throwErrorTolerant(lookahead, Messages.UnexpectedToken, lookahead.value); } else { parseParam(options); - if (options.defaultCount === 0) { - options.defaults = []; - } } expect(")"); return markerApply( @@ -4763,37 +4876,28 @@ false ) ); } - // only possibility in this branch is a generator + // object spread property + if (allowSpread && match("...")) { + lex(); + return markerApply(marker, astNodeFactory.createExperimentalSpreadProperty(parseAssignmentExpression())); + } + + // 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 === "["); - id = parseObjectPropertyKey(); - if (!match("(")) { - throwUnexpected(lex()); - } + return parseGeneratorProperty(id, marker); - return markerApply( - marker, - astNodeFactory.createProperty( - "init", - id, - parsePropertyMethodFunction({ generator: true }), - true, - false, - computed - ) - ); - } /* * If we've made it here, then that means the property name is represented * by a string (i.e, { "foo": 2}). The only options here are normal @@ -4851,21 +4955,22 @@ property, name, propertyFn, kind, storedKind, + previousInObjectLiteral = state.inObjectLiteral, kindMap = new StringMap(); state.inObjectLiteral = true; expect("{"); while (!match("}")) { property = parseObjectProperty(); - if (!property.computed) { + if (!property.computed && property.type.indexOf("Experimental") === -1) { name = getFieldName(property.key); propertyFn = (property.kind === "get") ? PropertyKind.Get : PropertyKind.Set; kind = (property.kind === "init") ? PropertyKind.Data : propertyFn; @@ -4901,30 +5006,43 @@ } } expect("}"); - state.inObjectLiteral = false; + state.inObjectLiteral = previousInObjectLiteral; return markerApply(marker, astNodeFactory.createObjectExpression(properties)); } /** * Parse a template string element and return its ASTNode representation - * @param {Object} options Parsing & scanning options - * @param {Object} options.head True if this element is the first in the + * @param {Object} option Parsing & scanning options + * @param {Object} option.head True if this element is the first in the * template string, false otherwise. * @returns {ASTNode} The template element node with marker info applied * @private */ -function parseTemplateElement(options) { - var marker = markerCreate(), - token = scanTemplateElement(options); - if (strict && token.octal) { - throwError(token, Messages.StrictOctalLiteral); +function parseTemplateElement(option) { + var marker, token; + + if (lookahead.type !== Token.Template || (option.head && !lookahead.head)) { + throwError({}, Messages.UnexpectedToken, "ILLEGAL"); } - return markerApply(marker, astNodeFactory.createTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail)); + + marker = markerCreate(); + token = lex(); + + return markerApply( + marker, + astNodeFactory.createTemplateElement( + { + raw: token.value.raw, + cooked: token.value.cooked + }, + token.tail + ) + ); } /** * Parse a template string literal and return its ASTNode representation * @returns {ASTNode} The template literal node with marker info applied @@ -4967,12 +5085,12 @@ function parsePrimaryExpression() { var type, token, expr, marker, allowJSX = extra.ecmaFeatures.jsx, - allowSuper = extra.ecmaFeatures.superInFunctions, - allowClasses = extra.ecmaFeatures.classes; + allowClasses = extra.ecmaFeatures.classes, + allowSuper = allowClasses || extra.ecmaFeatures.superInFunctions; if (match("(")) { return parseGroupExpression(); } @@ -5004,11 +5122,11 @@ } if (allowSuper && matchKeyword("super") && state.inFunctionBody) { marker = markerCreate(); lex(); - return markerApply(marker, astNodeFactory.createIdentifier("super")); + return markerApply(marker, astNodeFactory.createSuper()); } if (matchKeyword("this")) { marker = markerCreate(); lex(); @@ -5048,20 +5166,17 @@ function parseArguments() { var args = [], arg; expect("("); - if (!match(")")) { while (index < length) { arg = parseSpreadOrAssignmentExpression(); args.push(arg); if (match(")")) { break; - } else if (arg.type === astNodeTypes.SpreadElement) { - throwError({}, Messages.ElementAfterSpreadElement); } expect(","); } } @@ -5114,10 +5229,23 @@ function parseNewExpression() { var callee, args, marker = markerCreate(); expectKeyword("new"); + + if (extra.ecmaFeatures.newTarget && match(".")) { + lex(); + if (lookahead.type === Token.Identifier && lookahead.value === "target") { + if (state.inFunctionBody) { + lex(); + return markerApply(marker, astNodeFactory.createMetaProperty("new", "target")); + } + } + + throwUnexpected(lookahead); + } + callee = parseLeftHandSideExpression(); args = match("(") ? parseArguments() : []; return markerApply(marker, astNodeFactory.createNewExpression(callee, args)); } @@ -5138,11 +5266,11 @@ expr = markerApply(marker, astNodeFactory.createCallExpression(expr, args)); } else if (match("[")) { expr = markerApply(marker, astNodeFactory.createMemberExpression("[", expr, parseComputedMember())); } else if (match(".")) { expr = markerApply(marker, astNodeFactory.createMemberExpression(".", expr, parseNonComputedMember())); - } else if (!lookahead.tail) { + } else { expr = markerApply(marker, astNodeFactory.createTaggedTemplateExpression(expr, parseTemplateLiteral())); } } return expr; @@ -5416,41 +5544,61 @@ } return parseAssignmentExpression(); } function reinterpretAsCoverFormalsList(expressions) { - var i, len, param, params, defaults, defaultCount, options, rest; + var i, len, param, params, options, + allowRestParams = extra.ecmaFeatures.restParams; params = []; - defaults = []; - defaultCount = 0; - rest = null; options = { paramSet: new StringMap() }; for (i = 0, len = expressions.length; i < len; i += 1) { param = expressions[i]; if (param.type === astNodeTypes.Identifier) { params.push(param); - defaults.push(null); validateParam(options, param, param.name); } else if (param.type === astNodeTypes.ObjectExpression || param.type === astNodeTypes.ArrayExpression) { reinterpretAsDestructuredParameter(options, param); params.push(param); - defaults.push(null); } else if (param.type === astNodeTypes.SpreadElement) { assert(i === len - 1, "It is guaranteed that SpreadElement is last element by parseExpression"); if (param.argument.type !== astNodeTypes.Identifier) { - throwError({}, Messages.InvalidLHSInFormalsList); + throwError({}, Messages.UnexpectedToken, "["); } - reinterpretAsDestructuredParameter(options, param.argument); - rest = param.argument; + + if (!allowRestParams) { + // can't get correct line/column here :( + throwError({}, Messages.UnexpectedToken, "."); + } + + validateParam(options, param.argument, param.argument.name); + param.type = astNodeTypes.RestElement; + params.push(param); + } else if (param.type === astNodeTypes.RestElement) { + params.push(param); + validateParam(options, param.argument, param.argument.name); } else if (param.type === astNodeTypes.AssignmentExpression) { - params.push(param.left); - defaults.push(param.right); - ++defaultCount; + + // TODO: Find a less hacky way of doing this + param.type = astNodeTypes.AssignmentPattern; + delete param.operator; + + if (param.right.type === astNodeTypes.YieldExpression) { + if (param.right.argument) { + throwUnexpected(lookahead); + } + + param.right.type = astNodeTypes.Identifier; + param.right.name = "yield"; + delete param.right.argument; + delete param.right.delegate; + } + + params.push(param); validateParam(options, param.left, param.left.name); } else { return null; } } @@ -5460,31 +5608,29 @@ strict ? options.stricted : options.firstRestricted, options.message ); } - // must be here so it's not an array of [null, null] - if (defaultCount === 0) { - defaults = []; - } - return { params: params, - defaults: defaults, - rest: rest, stricted: options.stricted, firstRestricted: options.firstRestricted, message: options.message }; } function parseArrowFunctionExpression(options, marker) { var previousStrict, body; + var arrowStart = lineNumber; expect("=>"); previousStrict = strict; + if (lineNumber > arrowStart) { + throwError({}, Messages.UnexpectedToken, "=>"); + } + body = parseConciseBody(); if (strict && options.firstRestricted) { throwError(options.firstRestricted, options.message); } @@ -5493,33 +5639,44 @@ } strict = previousStrict; return markerApply(marker, astNodeFactory.createArrowFunctionExpression( options.params, - options.defaults, body, - options.rest, body.type !== astNodeTypes.BlockStatement )); } // 11.13 Assignment Operators // 12.14.5 AssignmentPattern function reinterpretAsAssignmentBindingPattern(expr) { var i, len, property, element, - allowDestructuring = extra.ecmaFeatures.destructuring; + allowDestructuring = extra.ecmaFeatures.destructuring, + allowRest = extra.ecmaFeatures.experimentalObjectRestSpread; if (!allowDestructuring) { throwUnexpected(lex()); } if (expr.type === astNodeTypes.ObjectExpression) { expr.type = astNodeTypes.ObjectPattern; for (i = 0, len = expr.properties.length; i < len; i += 1) { property = expr.properties[i]; + + if (allowRest && property.type === astNodeTypes.ExperimentalSpreadProperty) { + + // only allow identifiers + if (property.argument.type !== astNodeTypes.Identifier) { + throwErrorTolerant({}, "Invalid object rest."); + } + + property.type = astNodeTypes.ExperimentalRestProperty; + return; + } + if (property.kind !== "init") { throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } reinterpretAsAssignmentBindingPattern(property.value); } @@ -5630,11 +5787,10 @@ node = left = parseConditionalExpression(); if (match("=>") && (state.parenthesisCount === oldParenthesisCount || state.parenthesisCount === (oldParenthesisCount + 1))) { - if (node.type === astNodeTypes.Identifier) { params = reinterpretAsCoverFormalsList([ node ]); } else if (node.type === astNodeTypes.AssignmentExpression || node.type === astNodeTypes.ArrayExpression || node.type === astNodeTypes.ObjectExpression) { @@ -5645,10 +5801,11 @@ } else if (node.type === astNodeTypes.SequenceExpression) { params = reinterpretAsCoverFormalsList(node.expressions); } if (params) { + state.parenthesisCount--; return parseArrowFunctionExpression(params, marker); } } if (matchAssign()) { @@ -5665,10 +5822,11 @@ throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } token = lex(); right = parseAssignmentExpression(); + node = markerApply(marker, astNodeFactory.createAssignmentExpression(token.value, left, right)); } return node; } @@ -5749,11 +5907,11 @@ marker = markerCreate(); token = lex(); if (token.type !== Token.Identifier) { - if (strict && token.type === Token.Keyword && syntax.isStrictModeReservedWord(token.value)) { + if (strict && token.type === Token.Keyword && syntax.isStrictModeReservedWord(token.value, extra.ecmaFeatures)) { throwErrorTolerant(token, Messages.StrictReservedWord); } else { throwUnexpected(token); } } @@ -5836,10 +5994,34 @@ consumeSemicolon(); return markerApply(marker, astNodeFactory.createVariableDeclaration(declarations, kind)); } + +function parseRestElement() { + var param, + marker = markerCreate(); + + lex(); + + if (match("{")) { + throwError(lookahead, Messages.ObjectPatternAsRestParameter); + } + + param = parseVariableIdentifier(); + + if (match("=")) { + throwError(lookahead, Messages.DefaultRestParameter); + } + + if (!match(")")) { + throwError(lookahead, Messages.ParameterAfterRestParameter); + } + + return markerApply(marker, astNodeFactory.createRestElement(param)); +} + // 12.3 Empty Statement function parseEmptyStatement() { expect(";"); return astNodeFactory.createEmptyStatement(); @@ -5977,10 +6159,15 @@ } else { state.allowIn = false; init = parseExpression(); state.allowIn = true; + if (init.type === astNodeTypes.ArrayExpression) { + init.type = astNodeTypes.ArrayPattern; + } + + if (allowForOf && matchContextualKeyword("of")) { operator = lex(); left = init; right = parseExpression(); init = null; @@ -6199,10 +6386,13 @@ while (index < length) { if (match("}") || matchKeyword("default") || matchKeyword("case")) { break; } statement = parseSourceElement(); + if (typeof statement === "undefined") { + break; + } consequent.push(statement); } return markerApply(marker, astNodeFactory.createSwitchCase(test, consequent)); } @@ -6272,22 +6462,42 @@ // 12.14 The try statement function parseCatchClause() { var param, body, - marker = markerCreate(); + marker = markerCreate(), + allowDestructuring = extra.ecmaFeatures.destructuring, + options = { + paramSet: new StringMap() + }; expectKeyword("catch"); expect("("); if (match(")")) { throwUnexpected(lookahead); } - param = parseVariableIdentifier(); + if (match("[")) { + if (!allowDestructuring) { + throwUnexpected(lookahead); + } + param = parseArrayInitialiser(); + reinterpretAsDestructuredParameter(options, param); + } else if (match("{")) { + + if (!allowDestructuring) { + throwUnexpected(lookahead); + } + param = parseObjectInitialiser(); + reinterpretAsDestructuredParameter(options, param); + } else { + param = parseVariableIdentifier(); + } + // 12.14.1 - if (strict && syntax.isRestrictedWord(param.name)) { + if (strict && param.name && syntax.isRestrictedWord(param.name)) { throwErrorTolerant({}, Messages.StrictCatchVariable); } expect(")"); body = parseBlock(); @@ -6461,11 +6671,11 @@ oldLabelSet = state.labelSet; oldInIteration = state.inIteration; oldInSwitch = state.inSwitch; oldInFunctionBody = state.inFunctionBody; - oldParenthesisCount = state.parenthesizedCount; + oldParenthesisCount = state.parenthesisCount; state.labelSet = new StringMap(); state.inIteration = false; state.inSwitch = false; state.inFunctionBody = true; @@ -6489,11 +6699,11 @@ state.labelSet = oldLabelSet; state.inIteration = oldInIteration; state.inSwitch = oldInSwitch; state.inFunctionBody = oldInFunctionBody; - state.parenthesizedCount = oldParenthesisCount; + state.parenthesisCount = oldParenthesisCount; return markerApply(marker, astNodeFactory.createBlockStatement(sourceElements)); } function validateParam(options, param, name) { @@ -6510,11 +6720,11 @@ } } else if (!options.firstRestricted) { if (syntax.isRestrictedWord(name)) { options.firstRestricted = param; options.message = Messages.StrictParamName; - } else if (syntax.isStrictModeReservedWord(name)) { + } else if (syntax.isStrictModeReservedWord(name, extra.ecmaFeatures)) { options.firstRestricted = param; options.message = Messages.StrictReservedWord; } else if (options.paramSet.has(name)) { options.firstRestricted = param; options.message = Messages.StrictParamDupe; @@ -6522,35 +6732,34 @@ } options.paramSet.set(name, true); } function parseParam(options) { - var token, rest, param, def, + var token, param, def, allowRestParams = extra.ecmaFeatures.restParams, allowDestructuring = extra.ecmaFeatures.destructuring, - allowDefaultParams = extra.ecmaFeatures.defaultParams; + allowDefaultParams = extra.ecmaFeatures.defaultParams, + marker = markerCreate(); - token = lookahead; if (token.value === "...") { if (!allowRestParams) { throwUnexpected(lookahead); } - token = lex(); - rest = true; + param = parseRestElement(); + validateParam(options, param.argument, param.argument.name); + options.params.push(param); + return false; } if (match("[")) { if (!allowDestructuring) { throwUnexpected(lookahead); } param = parseArrayInitialiser(); reinterpretAsDestructuredParameter(options, param); } else if (match("{")) { - if (rest) { - throwError({}, Messages.ObjectPatternAsRestParameter); - } if (!allowDestructuring) { throwUnexpected(lookahead); } param = parseObjectInitialiser(); reinterpretAsDestructuredParameter(options, param); @@ -6558,45 +6767,41 @@ param = parseVariableIdentifier(); validateParam(options, token, token.value); } if (match("=")) { - if (rest) { - throwErrorTolerant(lookahead, Messages.DefaultRestParameter); - } if (allowDefaultParams || allowDestructuring) { lex(); def = parseAssignmentExpression(); ++options.defaultCount; } else { throwUnexpected(lookahead); } } - if (rest) { - if (!match(")")) { - throwError({}, Messages.ParameterAfterRestParameter); - } - options.rest = param; - return false; + if (def) { + options.params.push(markerApply( + marker, + astNodeFactory.createAssignmentPattern( + param, + def + ) + )); + } else { + options.params.push(param); } - options.params.push(param); - options.defaults.push(def ? def : null); // TODO: determine if null or undefined (see: #55) - return !match(")"); } function parseParams(firstRestricted) { var options; options = { params: [], defaultCount: 0, - defaults: [], - rest: null, firstRestricted: firstRestricted }; expect("("); @@ -6610,18 +6815,12 @@ } } expect(")"); - if (options.defaultCount === 0) { - options.defaults = []; - } - return { params: options.params, - defaults: options.defaults, - rest: options.rest, stricted: options.stricted, firstRestricted: options.firstRestricted, message: options.message }; } @@ -6651,11 +6850,11 @@ } } else { if (syntax.isRestrictedWord(token.value)) { firstRestricted = token; message = Messages.StrictFunctionName; - } else if (syntax.isStrictModeReservedWord(token.value)) { + } else if (syntax.isStrictModeReservedWord(token.value, extra.ecmaFeatures)) { firstRestricted = token; message = Messages.StrictReservedWord; } } } @@ -6684,13 +6883,11 @@ return markerApply( marker, astNodeFactory.createFunctionDeclaration( id, tmp.params, - tmp.defaults, body, - tmp.rest, generator, false ) ); } @@ -6718,11 +6915,11 @@ } } else { if (syntax.isRestrictedWord(token.value)) { firstRestricted = token; message = Messages.StrictFunctionName; - } else if (syntax.isStrictModeReservedWord(token.value)) { + } else if (syntax.isStrictModeReservedWord(token.value, extra.ecmaFeatures)) { firstRestricted = token; message = Messages.StrictReservedWord; } } } @@ -6751,13 +6948,11 @@ return markerApply( marker, astNodeFactory.createFunctionExpression( id, tmp.params, - tmp.defaults, body, - tmp.rest, generator, false ) ); } @@ -6776,12 +6971,20 @@ if (match("*")) { lex(); delegateFlag = true; } - expr = parseAssignmentExpression(); + if (peekLineTerminator()) { + return markerApply(marker, astNodeFactory.createYieldExpression(null, delegateFlag)); + } + if (!match(";") && !match(")")) { + if (!match("}") && lookahead.type !== Token.EOF) { + expr = parseAssignmentExpression(); + } + } + return markerApply(marker, astNodeFactory.createYieldExpression(expr, delegateFlag)); } // Modules grammar from: // people.mozilla.org/~jorendorff/es6-draft.html @@ -6841,11 +7044,11 @@ expect("{"); if (!match("}")) { do { isExportFromIdentifier = isExportFromIdentifier || matchKeyword("default"); specifiers.push(parseExportSpecifier()); - } while (match(",") && lex()); + } while (match(",") && lex() && !match("}")); } expect("}"); if (matchContextualKeyword("from")) { // covering: @@ -6971,11 +7174,11 @@ // {foo, bar as bas} expect("{"); if (!match("}")) { do { specifiers.push(parseImportSpecifier()); - } while (match(",") && lex()); + } while (match(",") && lex() && !match("}")); } expect("}"); return specifiers; } @@ -7061,11 +7264,13 @@ // 14.3.7 // 14.5 Class Definitions function parseClassBody() { - var token, isStatic, hasConstructor = false, body = [], method, computed, key; + var hasConstructor = false, generator = false, + allowGenerators = extra.ecmaFeatures.generators, + token, isStatic, body = [], method, computed, key; var existingProps = {}, topMarker = markerCreate(), marker; @@ -7082,31 +7287,54 @@ 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(); } - method = tryParseMethodDefinition(token, key, computed, marker); + 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.computed && (method.key.name || (method.key.value && method.key.value.toString())) === "constructor") { if (method.kind !== "method" || !method.method || method.value.generator) { throwUnexpected(token, Messages.ConstructorSpecialMethod); } if (hasConstructor) { throwUnexpected(token, Messages.DuplicateConstructor); @@ -7263,19 +7491,20 @@ return sourceElements; } function parseProgram() { var body, - marker; + marker, + isModule = !!extra.ecmaFeatures.modules; skipComment(); peek(); marker = markerCreate(); - strict = extra.ecmaFeatures.modules; + strict = isModule; body = parseSourceElements(); - return markerApply(marker, astNodeFactory.createProgram(body)); + return markerApply(marker, astNodeFactory.createProgram(body, isModule ? "module" : "script")); } function filterTokenLocation() { var i, entry, token, tokens = []; @@ -7329,10 +7558,12 @@ inFunctionBody: false, inIteration: false, inSwitch: false, lastCommentStart: -1, yieldAllowed: false, + curlyStack: [], + curlyLastIndex: 0, inJSXSpreadAttribute: false, inJSXChild: false, inJSXTag: false }; @@ -7350,13 +7581,10 @@ // The following two fields are necessary to compute the Regex tokens. extra.openParenToken = -1; extra.openCurlyToken = -1; - // Needed when using template string tokenization - extra.curlies = []; - extra.range = (typeof options.range === "boolean") && options.range; extra.loc = (typeof options.loc === "boolean") && options.loc; if (typeof options.comment === "boolean" && options.comment) { extra.comments = []; @@ -7434,21 +7662,23 @@ inFunctionBody: false, inIteration: false, inSwitch: false, lastCommentStart: -1, yieldAllowed: false, + curlyStack: [], + curlyLastIndex: 0, inJSXSpreadAttribute: false, inJSXChild: false, inJSXTag: false }; extra = { 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; @@ -7491,11 +7721,12 @@ objectLiteralShorthandProperties: true, objectLiteralDuplicateProperties: true, generators: true, destructuring: true, classes: true, - modules: true + modules: true, + newTarget: true }; } // apply parsing flags after sourceType to allow overriding if (options.ecmaFeatures && typeof options.ecmaFeatures === "object") { @@ -7565,65 +7796,122 @@ return types; }()); },{"./lib/ast-node-factory":1,"./lib/ast-node-types":2,"./lib/comment-attachment":3,"./lib/features":4,"./lib/messages":5,"./lib/string-map":6,"./lib/syntax":7,"./lib/token-info":8,"./lib/xhtml-entities":9,"./package.json":10}]},{},[]); -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.eslint=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.eslint = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ +module.exports={ + "type": "Program", + "body": [], + "sourceType": "script", + "range": [ + 0, + 0 + ], + "loc": { + "start": { + "line": 0, + "column": 0 + }, + "end": { + "line": 0, + "column": 0 + } + }, + "comments": [], + "tokens": [] +} + +},{}],2:[function(require,module,exports){ /** * @fileoverview Defines environment settings and globals. * @author Elan Shanker * @copyright 2014 Elan Shanker. All rights reserved. */ "use strict"; +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + var globals = require("globals"); +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + module.exports = { builtin: globals.builtin, browser: { globals: globals.browser }, node: { globals: globals.node, ecmaFeatures: { globalReturn: true - }, - rules: { - "no-catch-shadow": 0, - "no-console": 0, - "no-mixed-requires": 2, - "no-new-require": 2, - "no-path-concat": 2, - "no-process-exit": 2, - "global-strict": [0, "always"], - "handle-callback-err": [2, "err"] } }, + commonjs: { + globals: globals.commonjs, + ecmaFeatures: { + globalReturn: true + } + }, + worker: { + globals: globals.worker + }, amd: { globals: globals.amd }, mocha: { globals: globals.mocha }, jasmine: { globals: globals.jasmine }, + jest: { + globals: globals.jest + }, phantomjs: { - globals: globals.phantom + globals: globals.phantomjs }, jquery: { globals: globals.jquery }, + qunit: { + globals: globals.qunit + }, prototypejs: { globals: globals.prototypejs }, shelljs: { globals: globals.shelljs }, meteor: { globals: globals.meteor }, + mongo: { + globals: globals.mongo + }, + protractor: { + globals: globals.protractor + }, + applescript: { + globals: globals.applescript + }, + nashorn: { + globals: globals.nashorn + }, + serviceworker: { + globals: globals.serviceworker + }, + embertest: { + globals: globals.embertest + }, + webextensions: { + globals: globals.webextensions + }, es6: { ecmaFeatures: { arrowFunctions: true, blockBindings: true, regexUFlag: true, @@ -7640,182 +7928,235 @@ objectLiteralShorthandMethods: true, objectLiteralShorthandProperties: true, objectLiteralDuplicateProperties: true, generators: true, destructuring: true, - classes: true + classes: true, + spread: true, + newTarget: true } } }; -},{"globals":130}],2:[function(require,module,exports){ +},{"globals":100}],3:[function(require,module,exports){ module.exports={ - "ecmaFeatures": {}, "parser": "espree", - "env": { - "browser": false, - "node": false, - "amd": false, - "mocha": false, - "jasmine": false - }, - + "ecmaFeatures": {}, "rules": { - "no-alert": 2, - "no-array-constructor": 2, + "no-alert": 0, + "no-array-constructor": 0, + "no-arrow-condition": 0, "no-bitwise": 0, - "no-caller": 2, - "no-catch-shadow": 2, - "no-comma-dangle": 0, + "no-caller": 0, + "no-case-declarations": 0, + "no-catch-shadow": 0, + "no-class-assign": 0, "no-cond-assign": 2, "no-console": 2, + "no-const-assign": 0, "no-constant-condition": 2, + "no-continue": 0, "no-control-regex": 2, "no-debugger": 2, "no-delete-var": 2, "no-div-regex": 0, + "no-dupe-class-members": 0, "no-dupe-keys": 2, "no-dupe-args": 2, + "no-duplicate-case": 2, "no-else-return": 0, "no-empty": 2, - "no-empty-class": 2, - "no-empty-label": 2, + "no-empty-character-class": 2, + "no-empty-label": 0, + "no-empty-pattern": 0, "no-eq-null": 0, - "no-eval": 2, + "no-eval": 0, "no-ex-assign": 2, - "no-extend-native": 2, - "no-extra-bind": 2, + "no-extend-native": 0, + "no-extra-bind": 0, "no-extra-boolean-cast": 2, "no-extra-parens": 0, "no-extra-semi": 2, - "no-extra-strict": 2, "no-fallthrough": 2, "no-floating-decimal": 0, "no-func-assign": 2, - "no-implied-eval": 2, + "no-implicit-coercion": 0, + "no-implied-eval": 0, "no-inline-comments": 0, "no-inner-declarations": [2, "functions"], "no-invalid-regexp": 2, + "no-invalid-this": 0, "no-irregular-whitespace": 2, - "no-iterator": 2, - "no-label-var": 2, - "no-labels": 2, - "no-lone-blocks": 2, + "no-iterator": 0, + "no-label-var": 0, + "no-labels": 0, + "no-lone-blocks": 0, "no-lonely-if": 0, - "no-loop-func": 2, + "no-loop-func": 0, "no-mixed-requires": [0, false], "no-mixed-spaces-and-tabs": [2, false], - "no-multi-spaces": 2, - "no-multi-str": 2, + "linebreak-style": [0, "unix"], + "no-multi-spaces": 0, + "no-multi-str": 0, "no-multiple-empty-lines": [0, {"max": 2}], - "no-native-reassign": 2, + "no-native-reassign": 0, + "no-negated-condition": 0, "no-negated-in-lhs": 2, "no-nested-ternary": 0, - "no-new": 2, - "no-new-func": 2, - "no-new-object": 2, + "no-new": 0, + "no-new-func": 0, + "no-new-object": 0, "no-new-require": 0, - "no-new-wrappers": 2, + "no-new-wrappers": 0, "no-obj-calls": 2, "no-octal": 2, - "no-octal-escape": 2, + "no-octal-escape": 0, + "no-param-reassign": 0, "no-path-concat": 0, "no-plusplus": 0, "no-process-env": 0, - "no-process-exit": 2, - "no-proto": 2, + "no-process-exit": 0, + "no-proto": 0, "no-redeclare": 2, "no-regex-spaces": 2, - "no-reserved-keys": 0, "no-restricted-modules": 0, - "no-return-assign": 2, - "no-script-url": 2, + "no-restricted-syntax": 0, + "no-return-assign": 0, + "no-script-url": 0, "no-self-compare": 0, - "no-sequences": 2, - "no-shadow": 2, - "no-shadow-restricted-names": 2, - "no-space-before-semi": 0, - "no-spaced-func": 2, + "no-sequences": 0, + "no-shadow": 0, + "no-shadow-restricted-names": 0, + "no-spaced-func": 0, "no-sparse-arrays": 2, "no-sync": 0, "no-ternary": 0, - "no-trailing-spaces": 2, + "no-trailing-spaces": 0, + "no-this-before-super": 0, "no-throw-literal": 0, "no-undef": 2, - "no-undef-init": 2, + "no-undef-init": 0, "no-undefined": 0, - "no-underscore-dangle": 2, + "no-unexpected-multiline": 0, + "no-underscore-dangle": 0, + "no-unneeded-ternary": 0, "no-unreachable": 2, - "no-unused-expressions": 2, + "no-unused-expressions": 0, "no-unused-vars": [2, {"vars": "all", "args": "after-used"}], - "no-use-before-define": 2, + "no-use-before-define": 0, + "no-useless-call": 0, + "no-useless-concat": 0, "no-void": 0, "no-var": 0, "no-warning-comments": [0, { "terms": ["todo", "fixme", "xxx"], "location": "start" }], - "no-with": 2, - "no-wrap-func": 2, + "no-with": 0, + "no-magic-numbers": 0, + "array-bracket-spacing": [0, "never"], + "arrow-body-style": [0, "as-needed"], + "arrow-parens": 0, + "arrow-spacing": 0, + "accessor-pairs": 0, "block-scoped-var": 0, + "block-spacing": 0, "brace-style": [0, "1tbs"], - "camelcase": 2, + "callback-return": 0, + "camelcase": 0, "comma-dangle": [2, "never"], - "comma-spacing": 2, + "comma-spacing": 0, "comma-style": 0, "complexity": [0, 11], - "consistent-return": 2, + "computed-property-spacing": [0, "never"], + "consistent-return": 0, "consistent-this": [0, "that"], - "curly": [2, "all"], + "constructor-super": 0, + "curly": [0, "all"], "default-case": 0, - "dot-notation": [2, { "allowKeywords": true }], - "eol-last": 2, - "eqeqeq": 2, + "dot-location": 0, + "dot-notation": [0, { "allowKeywords": true }], + "eol-last": 0, + "eqeqeq": 0, "func-names": 0, "func-style": [0, "declaration"], - "generator-star": 0, - "global-strict": [2, "never"], + "generator-star-spacing": 0, + "global-require": 0, "guard-for-in": 0, "handle-callback-err": 0, + "id-length": 0, "indent": 0, - "key-spacing": [2, { "beforeColon": false, "afterColon": true }], + "init-declarations": 0, + "jsx-quotes": [0, "prefer-double"], + "key-spacing": [0, { "beforeColon": false, "afterColon": true }], + "lines-around-comment": 0, "max-depth": [0, 4], "max-len": [0, 80, 4], "max-nested-callbacks": [0, 2], "max-params": [0, 3], "max-statements": [0, 10], - "new-cap": 2, - "new-parens": 2, - "one-var": 0, + "new-cap": 0, + "new-parens": 0, + "newline-after-var": 0, + "object-curly-spacing": [0, "never"], + "object-shorthand": 0, + "one-var": [0, "always"], "operator-assignment": [0, "always"], + "operator-linebreak": 0, "padded-blocks": 0, + "prefer-arrow-callback": 0, + "prefer-const": 0, + "prefer-spread": 0, + "prefer-reflect": 0, + "prefer-template": 0, "quote-props": 0, - "quotes": [2, "double"], + "quotes": [0, "double"], "radix": 0, - "semi": 2, - "semi-spacing": [2, {"before": false, "after": true}], + "id-match": 0, + "require-jsdoc": 0, + "require-yield": 0, + "semi": 0, + "semi-spacing": [0, {"before": false, "after": true}], "sort-vars": 0, - "space-after-function-name": [0, "never"], "space-after-keywords": [0, "always"], + "space-before-keywords": [0, "always"], "space-before-blocks": [0, "always"], - "space-before-function-parentheses": [0, "always"], - "space-in-brackets": [0, "never"], + "space-before-function-paren": [0, "always"], "space-in-parens": [0, "never"], - "space-infix-ops": 2, - "space-return-throw-case": 2, - "space-unary-ops": [2, { "words": true, "nonwords": false }], - "spaced-line-comment": [0, "always"], - "strict": 2, + "space-infix-ops": 0, + "space-return-throw-case": 0, + "space-unary-ops": [0, { "words": true, "nonwords": false }], + "spaced-comment": 0, + "strict": 0, "use-isnan": 2, "valid-jsdoc": 0, "valid-typeof": 2, "vars-on-top": 0, "wrap-iife": 0, "wrap-regex": 0, - "yoda": [2, "never"] + "yoda": [0, "never"] } } -},{}],3:[function(require,module,exports){ +},{}],4:[function(require,module,exports){ +module.exports={ + "rules": { + "generator-star": ["generator-star-spacing"], + "global-strict": ["strict"], + "no-comma-dangle": ["comma-dangle"], + "no-empty-class": ["no-empty-character-class"], + "no-extra-strict": ["strict"], + "no-reserved-keys": ["quote-props"], + "no-space-before-semi": ["semi-spacing"], + "no-wrap-func": ["no-extra-parens"], + "space-after-function-name": ["space-before-function-paren"], + "space-before-function-parentheses": ["space-before-function-paren"], + "space-in-brackets": ["object-curly-spacing", "array-bracket-spacing", "computed-property-spacing"], + "space-unary-word-ops": ["space-unary-ops"], + "spaced-line-comment": ["spaced-comment"] + } +} + +},{}],5:[function(require,module,exports){ // http://wiki.commonjs.org/wiki/Unit_Testing/1.0 // // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! // // Originally from narwhal.js (http://narwhaljs.org) @@ -8172,996 +8513,478 @@ if (hasOwn.call(obj, key)) keys.push(key); } return keys; }; -},{"util/":8}],4:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. +},{"util/":111}],6:[function(require,module,exports){ +'use strict'; -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; +var copy = require('es5-ext/object/copy') + , map = require('es5-ext/object/map') + , callable = require('es5-ext/object/valid-callable') + , validValue = require('es5-ext/object/valid-value') -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; + , bind = Function.prototype.bind, defineProperty = Object.defineProperty + , hasOwnProperty = Object.prototype.hasOwnProperty + , define; -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; - -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; - -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; +define = function (name, desc, bindTo) { + var value = validValue(desc) && callable(desc.value), dgs; + dgs = copy(desc); + delete dgs.writable; + delete dgs.value; + dgs.get = function () { + if (hasOwnProperty.call(this, name)) return value; + desc.value = bind.call(value, (bindTo == null) ? this : this[bindTo]); + defineProperty(this, name, desc); + return this[name]; + }; + return dgs; }; -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; - - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } - throw TypeError('Uncaught, unspecified "error" event.'); - } - } - - handler = this._events[type]; - - if (isUndefined(handler)) - return false; - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - handler.apply(this, args); - } - } else if (isObject(handler)) { - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } - - return true; +module.exports = function (props/*, bindTo*/) { + var bindTo = arguments[1]; + return map(props, function (desc, name) { + return define(name, desc, bindTo); + }); }; -EventEmitter.prototype.addListener = function(type, listener) { - var m; +},{"es5-ext/object/copy":30,"es5-ext/object/map":38,"es5-ext/object/valid-callable":44,"es5-ext/object/valid-value":46}],7:[function(require,module,exports){ +'use strict'; - if (!isFunction(listener)) - throw TypeError('listener must be a function'); +var assign = require('es5-ext/object/assign') + , normalizeOpts = require('es5-ext/object/normalize-options') + , isCallable = require('es5-ext/object/is-callable') + , contains = require('es5-ext/string/#/contains') - if (!this._events) - this._events = {}; + , d; - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); +d = module.exports = function (dscr, value/*, options*/) { + var c, e, w, options, desc; + if ((arguments.length < 2) || (typeof dscr !== 'string')) { + options = value; + value = dscr; + dscr = null; + } else { + options = arguments[2]; + } + if (dscr == null) { + c = w = true; + e = false; + } else { + c = contains.call(dscr, 'c'); + e = contains.call(dscr, 'e'); + w = contains.call(dscr, 'w'); + } - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - var m; - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } - - return this; + desc = { value: value, configurable: c, enumerable: e, writable: w }; + return !options ? desc : assign(normalizeOpts(options), desc); }; -EventEmitter.prototype.on = EventEmitter.prototype.addListener; +d.gs = function (dscr, get, set/*, options*/) { + var c, e, options, desc; + if (typeof dscr !== 'string') { + options = set; + set = get; + get = dscr; + dscr = null; + } else { + options = arguments[3]; + } + if (get == null) { + get = undefined; + } else if (!isCallable(get)) { + options = get; + get = set = undefined; + } else if (set == null) { + set = undefined; + } else if (!isCallable(set)) { + options = set; + set = undefined; + } + if (dscr == null) { + c = true; + e = false; + } else { + c = contains.call(dscr, 'c'); + e = contains.call(dscr, 'e'); + } -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } - - g.listener = listener; - this.on(type, g); - - return this; + desc = { get: get, set: set, configurable: c, enumerable: e }; + return !options ? desc : assign(normalizeOpts(options), desc); }; -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; +},{"es5-ext/object/assign":27,"es5-ext/object/is-callable":33,"es5-ext/object/normalize-options":39,"es5-ext/string/#/contains":47}],8:[function(require,module,exports){ - if (!isFunction(listener)) - throw TypeError('listener must be a function'); +/** + * This is the web browser implementation of `debug()`. + * + * Expose `debug()` as the module. + */ - if (!this._events || !this._events[type]) - return this; +exports = module.exports = require('./debug'); +exports.log = log; +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; +exports.storage = 'undefined' != typeof chrome + && 'undefined' != typeof chrome.storage + ? chrome.storage.local + : localstorage(); - list = this._events[type]; - length = list.length; - position = -1; +/** + * Colors. + */ - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); +exports.colors = [ + 'lightseagreen', + 'forestgreen', + 'goldenrod', + 'dodgerblue', + 'darkorchid', + 'crimson' +]; - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } +/** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ - if (position < 0) - return this; +function useColors() { + // is webkit? http://stackoverflow.com/a/16459606/376773 + return ('WebkitAppearance' in document.documentElement.style) || + // is firebug? http://stackoverflow.com/a/398120/376773 + (window.console && (console.firebug || (console.exception && console.table))) || + // is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + (navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31); +} - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } - - return this; +exports.formatters.j = function(v) { + return JSON.stringify(v); }; -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - if (!this._events) - return this; +/** + * Colorize log arguments if enabled. + * + * @api public + */ - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } +function formatArgs() { + var args = arguments; + var useColors = this.useColors; - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } + args[0] = (useColors ? '%c' : '') + + this.namespace + + (useColors ? ' %c' : ' ') + + args[0] + + (useColors ? '%c ' : ' ') + + '+' + exports.humanize(this.diff); - listeners = this._events[type]; + if (!useColors) return args; - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; + var c = 'color: ' + this.color; + args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1)); - return this; -}; + // the final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + var index = 0; + var lastC = 0; + args[0].replace(/%[a-z%]/g, function(match) { + if ('%%' === match) return; + index++; + if ('%c' === match) { + // we only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; + } + }); -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; - -EventEmitter.listenerCount = function(emitter, type) { - var ret; - if (!emitter._events || !emitter._events[type]) - ret = 0; - else if (isFunction(emitter._events[type])) - ret = 1; - else - ret = emitter._events[type].length; - return ret; -}; - -function isFunction(arg) { - return typeof arg === 'function'; + args.splice(lastC, 0, c); + return args; } -function isNumber(arg) { - return typeof arg === 'number'; -} +/** + * Invokes `console.log()` when available. + * No-op when `console.log` is not a "function". + * + * @api public + */ -function isObject(arg) { - return typeof arg === 'object' && arg !== null; +function log() { + // this hackery is required for IE8/9, where + // the `console.log` function doesn't have 'apply' + return 'object' === typeof console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); } -function isUndefined(arg) { - return arg === void 0; -} +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ -},{}],5:[function(require,module,exports){ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } +function save(namespaces) { + try { + if (null == namespaces) { + exports.storage.removeItem('debug'); + } else { + exports.storage.debug = namespaces; + } + } catch(e) {} } -},{}],6:[function(require,module,exports){ -// shim for using process in browser +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ -var process = module.exports = {}; -var queue = []; -var draining = false; - -function drainQueue() { - if (draining) { - return; - } - draining = true; - var currentQueue; - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - var i = -1; - while (++i < len) { - currentQueue[i](); - } - len = queue.length; - } - draining = false; +function load() { + var r; + try { + r = exports.storage.debug; + } catch(e) {} + return r; } -process.nextTick = function (fun) { - queue.push(fun); - if (!draining) { - setTimeout(drainQueue, 0); - } -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; +/** + * Enable namespaces listed in `localStorage.debug` initially. + */ -function noop() {} +exports.enable(load()); -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; +/** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -// TODO(shtylman) -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - -},{}],7:[function(require,module,exports){ -module.exports = function isBuffer(arg) { - return arg && typeof arg === 'object' - && typeof arg.copy === 'function' - && typeof arg.fill === 'function' - && typeof arg.readUInt8 === 'function'; +function localstorage(){ + try { + return window.localStorage; + } catch (e) {} } -},{}],8:[function(require,module,exports){ -(function (process,global){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } +},{"./debug":9}],9:[function(require,module,exports){ - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } - } - return str; -}; +/** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + * + * Expose `debug()` as the module. + */ +exports = module.exports = debug; +exports.coerce = coerce; +exports.disable = disable; +exports.enable = enable; +exports.enabled = enabled; +exports.humanize = require('ms'); -// Mark that a method should not be used. -// Returns a modified function which warns once by default. -// If --no-deprecation is set, then it is a no-op. -exports.deprecate = function(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return exports.deprecate(fn, msg).apply(this, arguments); - }; - } +/** + * The currently active debug mode names, and names to skip. + */ - if (process.noDeprecation === true) { - return fn; - } +exports.names = []; +exports.skips = []; - var warned = false; - function deprecated() { - if (!warned) { - if (process.throwDeprecation) { - throw new Error(msg); - } else if (process.traceDeprecation) { - console.trace(msg); - } else { - console.error(msg); - } - warned = true; - } - return fn.apply(this, arguments); - } +/** + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lowercased letter, i.e. "n". + */ - return deprecated; -}; +exports.formatters = {}; +/** + * Previously assigned color. + */ -var debugs = {}; -var debugEnviron; -exports.debuglog = function(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = process.pid; - debugs[set] = function() { - var msg = exports.format.apply(exports, arguments); - console.error('%s %d: %s', set, pid, msg); - }; - } else { - debugs[set] = function() {}; - } - } - return debugs[set]; -}; +var prevColor = 0; +/** + * Previous log timestamp. + */ +var prevTime; + /** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. + * Select a color. * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. + * @return {Number} + * @api private */ -/* legacy: obj, showHidden, depth, colors*/ -function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); + +function selectColor() { + return exports.colors[prevColor++ % exports.colors.length]; } -exports.inspect = inspect; +/** + * Create a debugger with the given `namespace`. + * + * @param {String} namespace + * @return {Function} + * @api public + */ -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] -}; +function debug(namespace) { -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; - - -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; + // define the `disabled` version + function disabled() { } -} + disabled.enabled = false; + // define the `enabled` version + function enabled() { -function stylizeNoColor(str, styleType) { - return str; -} + var self = enabled; + // set `diff` timestamp + var curr = +new Date(); + var ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; -function arrayToHash(array) { - var hash = {}; + // add the `color` if not set + if (null == self.useColors) self.useColors = exports.useColors(); + if (null == self.color && self.useColors) self.color = selectColor(); - array.forEach(function(val, idx) { - hash[val] = true; - }); + var args = Array.prototype.slice.call(arguments); - return hash; -} + args[0] = exports.coerce(args[0]); - -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); + if ('string' !== typeof args[0]) { + // anything else let's inspect with %o + args = ['%o'].concat(args); } - return ret; - } - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } + // apply any `formatters` transformations + var index = 0; + args[0] = args[0].replace(/%([a-z%])/g, function(match, format) { + // if we encounter an escaped % then don't increase the array index + if (match === '%%') return match; + index++; + var formatter = exports.formatters[format]; + if ('function' === typeof formatter) { + var val = args[index]; + match = formatter.call(self, val); - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); + // now we need to remove `args[index]` since it's inlined in the `format` + args.splice(index, 1); + index--; + } + return match; + }); - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } - - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); - } - - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); + if ('function' === typeof exports.formatArgs) { + args = exports.formatArgs.apply(self, args); } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } + var logFn = enabled.log || exports.log || console.log.bind(console); + logFn.apply(self, args); } + enabled.enabled = true; - var base = '', array = false, braces = ['{', '}']; + var fn = exports.enabled(namespace) ? enabled : disabled; - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } + fn.namespace = namespace; - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } + return fn; +} - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } +/** + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. + * + * @param {String} namespaces + * @api public + */ - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } +function enable(namespaces) { + exports.save(namespaces); - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } + var split = (namespaces || '').split(/[\s,]+/); + var len = split.length; - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + for (var i = 0; i < len; i++) { + if (!split[i]) continue; // ignore empty strings + namespaces = split[i].replace(/\*/g, '.*?'); + if (namespaces[0] === '-') { + exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); } else { - return ctx.stylize('[Object]', 'special'); + exports.names.push(new RegExp('^' + namespaces + '$')); } } - - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); } +/** + * Disable debug output. + * + * @api public + */ -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); +function disable() { + exports.enable(''); } +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; -} - - -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); +function enabled(name) { + var i, len; + for (i = 0, len = exports.skips.length; i < len; i++) { + if (exports.skips[i].test(name)) { + return false; } } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); + for (i = 0, len = exports.names.length; i < len; i++) { + if (exports.names[i].test(name)) { + return true; } - }); - return output; -} - - -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - - return name + ': ' + str; + return false; } - -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } - - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} - - -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. -function isArray(ar) { - return Array.isArray(ar); -} -exports.isArray = isArray; - -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; - -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; - -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; - -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; - -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; - -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; - -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; - -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; - -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; - -function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; - -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; - -exports.isBuffer = require('./support/isBuffer'); - -function objectToString(o) { - return Object.prototype.toString.call(o); -} - - -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); -} - - -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; - -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); -} - - -// log is just a thin wrapper to console.log that prepends a timestamp -exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); -}; - - /** - * Inherit the prototype methods from one constructor into another. + * Coerce `val`. * - * The Function.prototype.inherits from lang.js rewritten as a standalone - * function (not on Function.prototype). NOTE: If this file is to be loaded - * during bootstrapping this function needs to be rewritten using some native - * functions as prototype setup using normal JavaScript does not work as - * expected during bootstrapping (see mirror.js in r114903). - * - * @param {function} ctor Constructor function which needs to inherit the - * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. + * @param {Mixed} val + * @return {Mixed} + * @api private */ -exports.inherits = require('inherits'); -exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; - - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; -}; - -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; } -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":7,"_process":6,"inherits":5}],9:[function(require,module,exports){ +},{"ms":107}],10:[function(require,module,exports){ /* Copyright (C) 2012-2014 Yusuke Suzuki <utatane.tea@gmail.com> Copyright (C) 2014 Dan Tao <daniel.tao@gmail.com> Copyright (C) 2013 Andrew Eisenberg <andrew@eisenberg.as> @@ -9230,10 +9053,14 @@ function isParamTitle(title) { return title === 'param' || title === 'argument' || title === 'arg'; } + function isReturnTitle(title) { + return title === 'return' || title === 'returns'; + } + function isProperty(title) { return title === 'property' || title === 'prop'; } function isNameParameterRequired(title) { @@ -9248,14 +9075,14 @@ function isAllowedNested(title) { return isProperty(title) || isParamTitle(title); } function isTypeParameterRequired(title) { - return isParamTitle(title) || title === 'define' || title === 'enum' || - title === 'implements' || title === 'return' || - title === 'this' || title === 'type' || title === 'typedef' || - title === 'returns' || isProperty(title); + return isParamTitle(title) || isReturnTitle(title) || + title === 'define' || title === 'enum' || + title === 'implements' || title === 'this' || + title === 'type' || title === 'typedef' || isProperty(title); } // Consider deprecation instead using 'isTypeParameterRequired' and 'Rules' declaration to pick when a type is optional/required // This would require changes to 'parseType' function isAllowedType(title) { @@ -9319,11 +9146,11 @@ break; } index += 1; } - return result; + return result.replace(/\s+$/, ''); } // JSDoc Tag Parser (function (exports) { @@ -9484,26 +9311,38 @@ name === 'event')) { name += advance(); name += scanIdentifier(last); } + if(source.charCodeAt(index) === 0x5B /* '[' */ && source.charCodeAt(index + 1) === 0x5D /* ']' */){ + name += advance(); + name += advance(); + } while (source.charCodeAt(index) === 0x2E /* '.' */ || source.charCodeAt(index) === 0x23 /* '#' */ || source.charCodeAt(index) === 0x7E /* '~' */) { name += advance(); name += scanIdentifier(last); } } if (useBrackets) { + + // do we have a default value for this? if (source.charCodeAt(index) === 0x3D /* '=' */) { - // consume the '='' symbol name += advance(); + var bracketDepth = 1; // scan in the default value - while (index < last && source.charCodeAt(index) !== 0x5D /* ']' */) { + while (index < last) { + if (source.charCodeAt(index) === 0x5B /* '[' */) { + bracketDepth++; + } else if (source.charCodeAt(index) === 0x5D /* ']' */ && + --bracketDepth === 0) { + break; + } name += advance(); } } if (index >= last || source.charCodeAt(index) !== 0x5D /* ']' */) { @@ -9569,11 +9408,11 @@ // type required titles if (isTypeParameterRequired(this._title)) { try { this._tag.type = parseType(this._title, this._last); if (!this._tag.type) { - if (!isParamTitle(this._title)) { + if (!isParamTitle(this._title) && !isReturnTitle(this._title)) { if (!this.addError('Missing or invalid tag type')) { return false; } } } @@ -9741,11 +9580,13 @@ description = this._tag.description; // un-fix potentially sloppy declaration if (isParamTitle(this._title) && !this._tag.type && description && description.charAt(0) === '[') { this._tag.type = this._extra.name; - this._tag.name = undefined; + if (!this._tag.name) { + this._tag.name = undefined; + } if (!sloppy) { if (!this.addError('Missing or invalid tag name')) { return false; } @@ -9816,10 +9657,12 @@ 'summary': ['parseDescription'], // http://usejsdoc.org/tags-this.html 'this': ['parseNamePath', 'ensureEnd'], // http://usejsdoc.org/tags-todo.html 'todo': ['parseDescription'], + // http://usejsdoc.org/tags-typedef.html + 'typedef': ['parseType', 'parseNamePathOptional'], // http://usejsdoc.org/tags-variation.html 'variation': ['parseVariation'], // http://usejsdoc.org/tags-version.html 'version': ['parseDescription'] }; @@ -9874,11 +9717,11 @@ // // Parse JSDoc // - function scanJSDocDescription() { + function scanJSDocDescription(preserveWhitespace) { var description = '', ch, atAllowed; atAllowed = true; while (index < length) { ch = source.charCodeAt(index); @@ -9893,11 +9736,12 @@ atAllowed = false; } description += advance(); } - return trim(description); + + return preserveWhitespace ? description : trim(description); } function parse(comment, options) { var tags = [], tag, description, interestingTags, i, iz; @@ -9932,11 +9776,11 @@ lineNumber = 0; recoverable = options.recoverable; sloppy = options.sloppy; strict = options.strict; - description = scanJSDocDescription(); + description = scanJSDocDescription(options.preserveWhitespace); while (true) { tag = parseTag(options); if (!tag) { break; @@ -9968,11 +9812,11 @@ stringify: typed.stringify }; }()); /* vim: set sw=4 ts=4 et tw=80 : */ -},{"./typed":10,"./utility":11,"esutils":15,"isarray":16}],10:[function(require,module,exports){ +},{"./typed":11,"./utility":12,"esutils":16,"isarray":105}],11:[function(require,module,exports){ /* Copyright (C) 2012-2014 Yusuke Suzuki <utatane.tea@gmail.com> Copyright (C) 2014 Dan Tao <daniel.tao@gmail.com> Copyright (C) 2013 Andrew Eisenberg <andrew@eisenberg.as> @@ -11231,11 +11075,11 @@ exports.stringify = stringify; exports.Syntax = Syntax; }()); /* vim: set sw=4 ts=4 et tw=80 : */ -},{"./utility":11,"esutils":15}],11:[function(require,module,exports){ +},{"./utility":12,"esutils":16}],12:[function(require,module,exports){ /* Copyright (C) 2014 Yusuke Suzuki <utatane.tea@gmail.com> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -11287,11 +11131,11 @@ exports.assert = require('assert'); }()); /* vim: set sw=4 ts=4 et tw=80 : */ -},{"../package.json":17,"assert":3}],12:[function(require,module,exports){ +},{"../package.json":17,"assert":5}],13:[function(require,module,exports){ /* Copyright (C) 2013 Yusuke Suzuki <utatane.tea@gmail.com> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -11433,11 +11277,11 @@ trailingStatement: trailingStatement }; }()); /* vim: set sw=4 ts=4 et tw=80 : */ -},{}],13:[function(require,module,exports){ +},{}],14:[function(require,module,exports){ /* Copyright (C) 2013-2014 Yusuke Suzuki <utatane.tea@gmail.com> Copyright (C) 2014 Ivan Nikulin <ifaaan@gmail.com> Redistribution and use in source and binary forms, with or without @@ -11536,11 +11380,11 @@ isIdentifierPart: isIdentifierPart }; }()); /* vim: set sw=4 ts=4 et tw=80 : */ -},{}],14:[function(require,module,exports){ +},{}],15:[function(require,module,exports){ /* Copyright (C) 2013 Yusuke Suzuki <utatane.tea@gmail.com> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -11675,11 +11519,11 @@ isIdentifierES6: isIdentifierES6 }; }()); /* vim: set sw=4 ts=4 et tw=80 : */ -},{"./code":13}],15:[function(require,module,exports){ +},{"./code":14}],16:[function(require,module,exports){ /* Copyright (C) 2013 Yusuke Suzuki <utatane.tea@gmail.com> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -11710,1746 +11554,127 @@ exports.code = require('./code'); exports.keyword = require('./keyword'); }()); /* vim: set sw=4 ts=4 et tw=80 : */ -},{"./ast":12,"./code":13,"./keyword":14}],16:[function(require,module,exports){ -module.exports = Array.isArray || function (arr) { - return Object.prototype.toString.call(arr) == '[object Array]'; -}; - -},{}],17:[function(require,module,exports){ +},{"./ast":13,"./code":14,"./keyword":15}],17:[function(require,module,exports){ module.exports={ - "name": "doctrine", - "description": "JSDoc parser", - "homepage": "http://github.com/Constellation/doctrine.html", - "main": "lib/doctrine.js", - "version": "0.6.4", - "engines": { - "node": ">=0.10.0" + "_args": [ + [ + "doctrine@^0.7.0", + "/Users/force/code/eslint" + ] + ], + "_from": "doctrine@>=0.7.0 <0.8.0", + "_id": "doctrine@0.7.1", + "_inCache": true, + "_installable": true, + "_location": "/doctrine", + "_npmUser": { + "email": "nicholas@nczconsulting.com", + "name": "nzakas" }, - "directories": { - "lib": "./lib" + "_npmVersion": "1.4.28", + "_phantomChildren": {}, + "_requested": { + "name": "doctrine", + "raw": "doctrine@^0.7.0", + "rawSpec": "^0.7.0", + "scope": null, + "spec": ">=0.7.0 <0.8.0", + "type": "range" }, - "maintainers": [ - { - "name": "constellation", - "email": "utatane.tea@gmail.com" - } + "_requiredBy": [ + "/" ], - "repository": { - "type": "git", - "url": "http://github.com/Constellation/doctrine.git" + "_resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.7.1.tgz", + "_shasum": "7ecff8b8981693c0a1ce9cc5438a7ec55e29f702", + "_shrinkwrap": null, + "_spec": "doctrine@^0.7.0", + "_where": "/Users/force/code/eslint", + "bugs": { + "url": "https://github.com/eslint/doctrine/issues" }, + "dependencies": { + "esutils": "^1.1.6", + "isarray": "0.0.1" + }, + "description": "JSDoc parser", "devDependencies": { "coveralls": "^2.11.2", + "dateformat": "^1.0.11", + "eslint": "^1.9.0", "gulp": "^3.8.10", "gulp-bump": "^0.1.13", "gulp-eslint": "^0.5.0", "gulp-filter": "^2.0.2", "gulp-git": "^1.0.0", "gulp-istanbul": "^0.6.0", "gulp-jshint": "^1.9.0", "gulp-mocha": "^2.0.0", "gulp-tag-version": "^1.2.1", "jshint-stylish": "^1.0.0", + "mocha": "^2.3.3", + "npm-license": "^0.3.1", + "semver": "^5.0.3", + "shelljs": "^0.5.3", + "shelljs-nodecli": "^0.1.1", "should": "^5.0.1" }, + "directories": { + "lib": "./lib" + }, + "dist": { + "shasum": "7ecff8b8981693c0a1ce9cc5438a7ec55e29f702", + "tarball": "http://registry.npmjs.org/doctrine/-/doctrine-0.7.1.tgz" + }, + "engines": { + "node": ">=0.10.0" + }, + "files": [ + "LICENSE.BSD", + "LICENSE.closure-compiler", + "LICENSE.esprima", + "README.md", + "lib" + ], + "gitHead": "400aea03020456769eb4048c349892c7a7dcfb6e", + "homepage": "https://github.com/eslint/doctrine", "licenses": [ { "type": "BSD", - "url": "http://github.com/Constellation/doctrine/raw/master/LICENSE.BSD" + "url": "http://github.com/eslint/doctrine/raw/master/LICENSE.BSD" } ], + "main": "lib/doctrine.js", + "maintainers": [ + { + "name": "constellation", + "email": "utatane.tea@gmail.com" + }, + { + "name": "nzakas", + "email": "nicholas@nczconsulting.com" + } + ], + "name": "doctrine", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/eslint/doctrine.git" + }, "scripts": { - "test": "gulp", - "unit-test": "gulp test", + "coveralls": "cat ./coverage/lcov.info | coveralls && rm -rf ./coverage", "lint": "gulp lint", - "coveralls": "cat ./coverage/lcov.info | coveralls && rm -rf ./coverage" + "test": "gulp", + "unit-test": "gulp test" }, - "dependencies": { - "esutils": "^1.1.6", - "isarray": "0.0.1" - }, - "gitHead": "0835299b485ecdfa908d20628d6c8900144590ff", - "bugs": { - "url": "https://github.com/Constellation/doctrine/issues" - }, - "_id": "doctrine@0.6.4", - "_shasum": "81428491a942ef18b0492056eda3800eee57d61d", - "_from": "doctrine@>=0.6.2 <0.7.0", - "_npmVersion": "1.4.28", - "_npmUser": { - "name": "constellation", - "email": "utatane.tea@gmail.com" - }, - "dist": { - "shasum": "81428491a942ef18b0492056eda3800eee57d61d", - "tarball": "http://registry.npmjs.org/doctrine/-/doctrine-0.6.4.tgz" - }, - "_resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.6.4.tgz", - "readme": "ERROR: No README data found!" + "version": "0.7.1" } },{}],18:[function(require,module,exports){ -'use strict'; - -var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; - -module.exports = function (str) { - if (typeof str !== 'string') { - throw new TypeError('Expected a string'); - } - - return str.replace(matchOperatorsRe, '\\$&'); -}; - -},{}],19:[function(require,module,exports){ -/* - Copyright (C) 2012-2014 Yusuke Suzuki <utatane.tea@gmail.com> - Copyright (C) 2013 Alex Seville <hi@alexanderseville.com> - Copyright (C) 2014 Thiago de Arruda <tpadilha84@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. -*/ - -/** - * Escope (<a href="http://github.com/Constellation/escope">escope</a>) is an <a - * href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript</a> - * scope analyzer extracted from the <a - * href="http://github.com/Constellation/esmangle">esmangle project</a/>. - * <p> - * <em>escope</em> finds lexical scopes in a source program, i.e. areas of that - * program where different occurrences of the same identifier refer to the same - * variable. With each scope the contained variables are collected, and each - * identifier reference in code is linked to its corresponding variable (if - * possible). - * <p> - * <em>escope</em> works on a syntax tree of the parsed source code which has - * to adhere to the <a - * href="https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API"> - * Mozilla Parser API</a>. E.g. <a href="http://esprima.org">esprima</a> is a parser - * that produces such syntax trees. - * <p> - * The main interface is the {@link analyze} function. - * @module - */ - -/*jslint bitwise:true */ -(function () { - 'use strict'; - - var Syntax, - util, - extend, - estraverse, - esrecurse, - Map, - WeakMap; - - util = require('util'); - extend = require('util-extend'); - estraverse = require('estraverse'); - esrecurse = require('esrecurse'); - - Map = require('es6-map'); - WeakMap = require('es6-weak-map'); - - Syntax = estraverse.Syntax; - - function assert(cond, text) { - if (!cond) { - throw new Error(text); - } - } - - function defaultOptions() { - return { - optimistic: false, - directive: false, - nodejsScope: false, - sourceType: 'script', // one of ['script', 'module'] - ecmaVersion: 5 - }; - } - - function updateDeeply(target, override) { - var key, val; - - function isHashObject(target) { - return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp); - } - - for (key in override) { - if (override.hasOwnProperty(key)) { - val = override[key]; - if (isHashObject(val)) { - if (isHashObject(target[key])) { - updateDeeply(target[key], val); - } else { - target[key] = updateDeeply({}, val); - } - } else { - target[key] = val; - } - } - } - return target; - } - - /** - * A Reference represents a single occurrence of an identifier in code. - * @class Reference - */ - function Reference(ident, scope, flag, writeExpr, maybeImplicitGlobal, partial) { - /** - * Identifier syntax node. - * @member {esprima#Identifier} Reference#identifier - */ - this.identifier = ident; - /** - * Reference to the enclosing Scope. - * @member {Scope} Reference#from - */ - this.from = scope; - /** - * Whether the reference comes from a dynamic scope (such as 'eval', - * 'with', etc.), and may be trapped by dynamic scopes. - * @member {boolean} Reference#tainted - */ - this.tainted = false; - /** - * The variable this reference is resolved with. - * @member {Variable} Reference#resolved - */ - this.resolved = null; - /** - * The read-write mode of the reference. (Value is one of {@link - * Reference.READ}, {@link Reference.RW}, {@link Reference.WRITE}). - * @member {number} Reference#flag - * @private - */ - this.flag = flag; - if (this.isWrite()) { - /** - * If reference is writeable, this is the tree being written to it. - * @member {esprima#Node} Reference#writeExpr - */ - this.writeExpr = writeExpr; - /** - * Whether the Reference might refer to a partial value of writeExpr. - * @member {boolean} Reference#partial - */ - this.partial = partial; - } - this.__maybeImplicitGlobal = maybeImplicitGlobal; - } - - /** - * @constant Reference.READ - * @private - */ - Reference.READ = 0x1; - /** - * @constant Reference.WRITE - * @private - */ - Reference.WRITE = 0x2; - /** - * @constant Reference.RW - * @private - */ - Reference.RW = Reference.READ | Reference.WRITE; - - /** - * Whether the reference is static. - * @method Reference#isStatic - * @return {boolean} - */ - Reference.prototype.isStatic = function isStatic() { - return !this.tainted && this.resolved && this.resolved.scope.isStatic(); - }; - - /** - * Whether the reference is writeable. - * @method Reference#isWrite - * @return {boolean} - */ - Reference.prototype.isWrite = function isWrite() { - return !!(this.flag & Reference.WRITE); - }; - - /** - * Whether the reference is readable. - * @method Reference#isRead - * @return {boolean} - */ - Reference.prototype.isRead = function isRead() { - return !!(this.flag & Reference.READ); - }; - - /** - * Whether the reference is read-only. - * @method Reference#isReadOnly - * @return {boolean} - */ - Reference.prototype.isReadOnly = function isReadOnly() { - return this.flag === Reference.READ; - }; - - /** - * Whether the reference is write-only. - * @method Reference#isWriteOnly - * @return {boolean} - */ - Reference.prototype.isWriteOnly = function isWriteOnly() { - return this.flag === Reference.WRITE; - }; - - /** - * Whether the reference is read-write. - * @method Reference#isReadWrite - * @return {boolean} - */ - Reference.prototype.isReadWrite = function isReadWrite() { - return this.flag === Reference.RW; - }; - - /** - * A Variable represents a locally scoped identifier. These include arguments to - * functions. - * @class Variable - */ - function Variable(name, scope) { - /** - * The variable name, as given in the source code. - * @member {String} Variable#name - */ - this.name = name; - /** - * List of defining occurrences of this variable (like in 'var ...' - * statements or as parameter), as AST nodes. - * @member {esprima.Identifier[]} Variable#identifiers - */ - this.identifiers = []; - /** - * List of {@link Reference|references} of this variable (excluding parameter entries) - * in its defining scope and all nested scopes. For defining - * occurrences only see {@link Variable#defs}. - * @member {Reference[]} Variable#references - */ - this.references = []; - - /** - * List of defining occurrences of this variable (like in 'var ...' - * statements or as parameter), as custom objects. - * @typedef {Object} DefEntry - * @property {String} DefEntry.type - the type of the occurrence (e.g. - * "Parameter", "Variable", ...) - * @property {esprima.Identifier} DefEntry.name - the identifier AST node of the occurrence - * @property {esprima.Node} DefEntry.node - the enclosing node of the - * identifier - * @property {esprima.Node} [DefEntry.parent] - the enclosing statement - * node of the identifier - * @member {DefEntry[]} Variable#defs - */ - this.defs = []; - - this.tainted = false; - /** - * Whether this is a stack variable. - * @member {boolean} Variable#stack - */ - this.stack = true; - /** - * Reference to the enclosing Scope. - * @member {Scope} Variable#scope - */ - this.scope = scope; - } - - Variable.CatchClause = 'CatchClause'; - Variable.Parameter = 'Parameter'; - Variable.FunctionName = 'FunctionName'; - Variable.ClassName = 'ClassName'; - Variable.Variable = 'Variable'; - Variable.ImportBinding = 'ImportBinding'; - Variable.TDZ = 'TDZ'; - Variable.ImplicitGlobalVariable = 'ImplicitGlobalVariable'; - - function isStrictScope(scope, block, isMethodDefinition, useDirective) { - var body, i, iz, stmt, expr; - - // When upper scope is exists and strict, inner scope is also strict. - if (scope.upper && scope.upper.isStrict) { - return true; - } - - // ArrowFunctionExpression's scope is always strict scope. - if (block.type === Syntax.ArrowFunctionExpression) { - return true; - } - - if (isMethodDefinition) { - return true; - } - - if (scope.type === 'class' || scope.type === 'module') { - return true; - } - - if (scope.type === 'block' || scope.type === 'switch') { - return false; - } - - if (scope.type === 'function') { - if (block.type === 'Program') { - body = block; - } else { - body = block.body; - } - } else if (scope.type === 'global') { - body = block; - } else { - return false; - } - - // Search 'use strict' directive. - if (useDirective) { - for (i = 0, iz = body.body.length; i < iz; ++i) { - stmt = body.body[i]; - if (stmt.type !== 'DirectiveStatement') { - break; - } - if (stmt.raw === '"use strict"' || stmt.raw === '\'use strict\'') { - return true; - } - } - } else { - for (i = 0, iz = body.body.length; i < iz; ++i) { - stmt = body.body[i]; - if (stmt.type !== Syntax.ExpressionStatement) { - break; - } - expr = stmt.expression; - if (expr.type !== Syntax.Literal || typeof expr.value !== 'string') { - break; - } - if (expr.raw != null) { - if (expr.raw === '"use strict"' || expr.raw === '\'use strict\'') { - return true; - } - } else { - if (expr.value === 'use strict') { - return true; - } - } - } - } - return false; - } - - function registerScope(scopeManager, scope) { - var scopes; - - scopeManager.scopes.push(scope); - - scopes = scopeManager.__nodeToScope.get(scope.block); - if (scopes) { - scopes.push(scope); - } else { - scopeManager.__nodeToScope.set(scope.block, [ scope ]); - } - } - - /* Special Scope types. */ - var SCOPE_NORMAL = 0, - SCOPE_MODULE = 1, - SCOPE_FUNCTION_EXPRESSION_NAME = 2, - SCOPE_TDZ = 3, - SCOPE_FUNCTION = 4; - - /** - * @class Scope - */ - function Scope(scopeManager, block, isMethodDefinition, scopeType) { - /** - * One of 'catch', 'with', 'function', 'global' or 'block'. - * @member {String} Scope#type - */ - this.type = - (scopeType === SCOPE_TDZ) ? 'TDZ' : - (scopeType === SCOPE_MODULE) ? 'module' : - (block.type === Syntax.BlockStatement) ? 'block' : - (block.type === Syntax.SwitchStatement) ? 'switch' : - (scopeType === SCOPE_FUNCTION || block.type === Syntax.FunctionExpression || block.type === Syntax.FunctionDeclaration || block.type === Syntax.ArrowFunctionExpression) ? 'function' : - (block.type === Syntax.CatchClause) ? 'catch' : - (block.type === Syntax.ForInStatement || block.type === Syntax.ForOfStatement || block.type === Syntax.ForStatement) ? 'for' : - (block.type === Syntax.WithStatement) ? 'with' : - (block.type === Syntax.ClassExpression || block.type === Syntax.ClassDeclaration) ? 'class' : 'global'; - /** - * The scoped {@link Variable}s of this scope, as <code>{ Variable.name - * : Variable }</code>. - * @member {Map} Scope#set - */ - this.set = new Map(); - /** - * The tainted variables of this scope, as <code>{ Variable.name : - * boolean }</code>. - * @member {Map} Scope#taints */ - this.taints = new Map(); - /** - * Generally, through the lexical scoping of JS you can always know - * which variable an identifier in the source code refers to. There are - * a few exceptions to this rule. With 'global' and 'with' scopes you - * can only decide at runtime which variable a reference refers to. - * Moreover, if 'eval()' is used in a scope, it might introduce new - * bindings in this or its prarent scopes. - * All those scopes are considered 'dynamic'. - * @member {boolean} Scope#dynamic - */ - this.dynamic = this.type === 'global' || this.type === 'with'; - /** - * A reference to the scope-defining syntax node. - * @member {esprima.Node} Scope#block - */ - this.block = block; - /** - * The {@link Reference|references} that are not resolved with this scope. - * @member {Reference[]} Scope#through - */ - this.through = []; - /** - * The scoped {@link Variable}s of this scope. In the case of a - * 'function' scope this includes the automatic argument <em>arguments</em> as - * its first element, as well as all further formal arguments. - * @member {Variable[]} Scope#variables - */ - this.variables = []; - /** - * Any variable {@link Reference|reference} found in this scope. This - * includes occurrences of local variables as well as variables from - * parent scopes (including the global scope). For local variables - * this also includes defining occurrences (like in a 'var' statement). - * In a 'function' scope this does not include the occurrences of the - * formal parameter in the parameter list. - * @member {Reference[]} Scope#references - */ - this.references = []; - - /** - * For 'global' and 'function' scopes, this is a self-reference. For - * other scope types this is the <em>variableScope</em> value of the - * parent scope. - * @member {Scope} Scope#variableScope - */ - this.variableScope = - (this.type === 'global' || this.type === 'function' || this.type === 'module') ? this : scopeManager.__currentScope.variableScope; - /** - * Whether this scope is created by a FunctionExpression. - * @member {boolean} Scope#functionExpressionScope - */ - this.functionExpressionScope = false; - /** - * Whether this is a scope that contains an 'eval()' invocation. - * @member {boolean} Scope#directCallToEvalScope - */ - this.directCallToEvalScope = false; - /** - * @member {boolean} Scope#thisFound - */ - this.thisFound = false; - - this.__left = []; - - if (scopeType === SCOPE_FUNCTION_EXPRESSION_NAME) { - this.__define(block.id, { - type: Variable.FunctionName, - name: block.id, - node: block - }); - this.functionExpressionScope = true; - } else { - // section 9.2.13, FunctionDeclarationInstantiation. - // NOTE Arrow functions never have an arguments objects. - if (this.type === 'function' && this.block.type !== Syntax.ArrowFunctionExpression) { - this.__defineArguments(); - } - - if (block.type === Syntax.FunctionExpression && block.id) { - scopeManager.__nestFunctionExpressionNameScope(block, isMethodDefinition); - } - } - - /** - * Reference to the parent {@link Scope|scope}. - * @member {Scope} Scope#upper - */ - this.upper = scopeManager.__currentScope; - /** - * Whether 'use strict' is in effect in this scope. - * @member {boolean} Scope#isStrict - */ - this.isStrict = isStrictScope(this, block, isMethodDefinition, scopeManager.__useDirective()); - - /** - * List of nested {@link Scope}s. - * @member {Scope[]} Scope#childScopes - */ - this.childScopes = []; - if (scopeManager.__currentScope) { - scopeManager.__currentScope.childScopes.push(this); - } - - - // RAII - scopeManager.__currentScope = this; - if (this.type === 'global') { - scopeManager.globalScope = this; - scopeManager.globalScope.implicit = { - set: new Map(), - variables: [], - /** - * List of {@link Reference}s that are left to be resolved (i.e. which - * need to be linked to the variable they refer to). - * @member {Reference[]} Scope#implicit#left - */ - left: [] - }; - } - - registerScope(scopeManager, this); - } - - Scope.prototype.__close = function __close(scopeManager) { - var i, iz, ref, current, implicit, info; - - // Because if this is global environment, upper is null - if (!this.dynamic || scopeManager.__isOptimistic()) { - // static resolve - for (i = 0, iz = this.__left.length; i < iz; ++i) { - ref = this.__left[i]; - if (!this.__resolve(ref)) { - this.__delegateToUpperScope(ref); - } - } - } else { - // this is "global" / "with" / "function with eval" environment - if (this.type === 'with') { - for (i = 0, iz = this.__left.length; i < iz; ++i) { - ref = this.__left[i]; - ref.tainted = true; - this.__delegateToUpperScope(ref); - } - } else { - for (i = 0, iz = this.__left.length; i < iz; ++i) { - // notify all names are through to global - ref = this.__left[i]; - current = this; - do { - current.through.push(ref); - current = current.upper; - } while (current); - } - } - } - - if (this.type === 'global') { - implicit = []; - for (i = 0, iz = this.__left.length; i < iz; ++i) { - ref = this.__left[i]; - if (ref.__maybeImplicitGlobal && !this.set.has(ref.identifier.name)) { - implicit.push(ref.__maybeImplicitGlobal); - } - } - - // create an implicit global variable from assignment expression - for (i = 0, iz = implicit.length; i < iz; ++i) { - info = implicit[i]; - this.__defineImplicit(info.pattern, { - type: Variable.ImplicitGlobalVariable, - name: info.pattern, - node: info.node - }); - } - - this.implicit.left = this.__left; - } - - this.__left = null; - scopeManager.__currentScope = this.upper; - }; - - Scope.prototype.__resolve = function __resolve(ref) { - var variable, name; - name = ref.identifier.name; - if (this.set.has(name)) { - variable = this.set.get(name); - variable.references.push(ref); - variable.stack = variable.stack && ref.from.variableScope === this.variableScope; - if (ref.tainted) { - variable.tainted = true; - this.taints.set(variable.name, true); - } - ref.resolved = variable; - return true; - } - return false; - }; - - Scope.prototype.__delegateToUpperScope = function __delegateToUpperScope(ref) { - if (this.upper) { - this.upper.__left.push(ref); - } - this.through.push(ref); - }; - - Scope.prototype.__defineGeneric = function (name, set, variables, node, info) { - var variable; - - variable = set.get(name); - if (!variable) { - variable = new Variable(name, this); - set.set(name, variable); - variables.push(variable); - } - - if (info) { - variable.defs.push(info); - } - if (node) { - variable.identifiers.push(node); - } - }; - - Scope.prototype.__defineArguments = function () { - this.__defineGeneric('arguments', this.set, this.variables); - this.taints.set('arguments', true); - }; - - Scope.prototype.__defineImplicit = function (node, info) { - if (node && node.type === Syntax.Identifier) { - this.__defineGeneric(node.name, this.implicit.set, this.implicit.variables, node, info); - } - }; - - Scope.prototype.__define = function (node, info) { - if (node && node.type === Syntax.Identifier) { - this.__defineGeneric(node.name, this.set, this.variables, node, info); - } - }; - - Scope.prototype.__referencing = function __referencing(node, assign, writeExpr, maybeImplicitGlobal, partial) { - var ref; - // because Array element may be null - if (node && node.type === Syntax.Identifier) { - ref = new Reference(node, this, assign || Reference.READ, writeExpr, maybeImplicitGlobal, !!partial); - this.references.push(ref); - this.__left.push(ref); - } - }; - - Scope.prototype.__detectEval = function __detectEval() { - var current; - current = this; - this.directCallToEvalScope = true; - do { - current.dynamic = true; - current = current.upper; - } while (current); - }; - - Scope.prototype.__detectThis = function __detectThis() { - this.thisFound = true; - }; - - Scope.prototype.__isClosed = function isClosed() { - return this.__left === null; - }; - - // API Scope#resolve(name) - // returns resolved reference - Scope.prototype.resolve = function resolve(ident) { - var ref, i, iz; - assert(this.__isClosed(), 'scope should be closed'); - assert(ident.type === Syntax.Identifier, 'target should be identifier'); - for (i = 0, iz = this.references.length; i < iz; ++i) { - ref = this.references[i]; - if (ref.identifier === ident) { - return ref; - } - } - return null; - }; - - // API Scope#isStatic - // returns this scope is static - Scope.prototype.isStatic = function isStatic() { - return !this.dynamic; - }; - - // API Scope#isArgumentsMaterialized - // return this scope has materialized arguments - Scope.prototype.isArgumentsMaterialized = function isArgumentsMaterialized() { - // TODO(Constellation) - // We can more aggressive on this condition like this. - // - // function t() { - // // arguments of t is always hidden. - // function arguments() { - // } - // } - var variable; - - // This is not function scope - if (this.type !== 'function') { - return true; - } - - if (!this.isStatic()) { - return true; - } - - variable = this.set.get('arguments'); - assert(variable, 'always have arguments variable'); - return variable.tainted || variable.references.length !== 0; - }; - - // API Scope#isThisMaterialized - // return this scope has materialized `this` reference - Scope.prototype.isThisMaterialized = function isThisMaterialized() { - // This is not function scope - if (this.type !== 'function') { - return true; - } - if (!this.isStatic()) { - return true; - } - return this.thisFound; - }; - - Scope.prototype.isUsedName = function (name) { - if (this.set.has(name)) { - return true; - } - for (var i = 0, iz = this.through.length; i < iz; ++i) { - if (this.through[i].identifier.name === name) { - return true; - } - } - return false; - }; - - /** - * @class ScopeManager - */ - function ScopeManager(options) { - this.scopes = []; - this.globalScope = null; - this.__nodeToScope = new WeakMap(); - this.__currentScope = null; - this.__options = options; - } - - ScopeManager.prototype.__useDirective = function () { - return this.__options.directive; - }; - - ScopeManager.prototype.__isOptimistic = function () { - return this.__options.optimistic; - }; - - ScopeManager.prototype.__ignoreEval = function () { - return this.__options.ignoreEval; - }; - - ScopeManager.prototype.__isNodejsScope = function () { - return this.__options.nodejsScope; - }; - - ScopeManager.prototype.isModule = function () { - return this.__options.sourceType === 'module'; - }; - - // Returns appropliate scope for this node. - ScopeManager.prototype.__get = function __get(node) { - return this.__nodeToScope.get(node); - }; - - ScopeManager.prototype.acquire = function acquire(node, inner) { - var scopes, scope, i, iz; - - function predicate(scope) { - if (scope.type === 'function' && scope.functionExpressionScope) { - return false; - } - if (scope.type === 'TDZ') { - return false; - } - return true; - } - - scopes = this.__get(node); - if (!scopes || scopes.length === 0) { - return null; - } - - // Heuristic selection from all scopes. - // If you would like to get all scopes, please use ScopeManager#acquireAll. - if (scopes.length === 1) { - return scopes[0]; - } - - if (inner) { - for (i = scopes.length - 1; i >= 0; --i) { - scope = scopes[i]; - if (predicate(scope)) { - return scope; - } - } - } else { - for (i = 0, iz = scopes.length; i < iz; ++i) { - scope = scopes[i]; - if (predicate(scope)) { - return scope; - } - } - } - - return null; - }; - - ScopeManager.prototype.acquireAll = function acquire(node) { - return this.__get(node); - }; - - ScopeManager.prototype.release = function release(node, inner) { - var scopes, scope; - scopes = this.__get(node); - if (scopes && scopes.length) { - scope = scopes[0].upper; - if (!scope) { - return null; - } - return this.acquire(scope.block, inner); - } - return null; - }; - - ScopeManager.prototype.attach = function attach() { }; - - ScopeManager.prototype.detach = function detach() { }; - - ScopeManager.prototype.__nestScope = function (node, isMethodDefinition) { - return new Scope(this, node, isMethodDefinition, SCOPE_NORMAL); - }; - - ScopeManager.prototype.__nestForceFunctionScope = function (node) { - return new Scope(this, node, false, SCOPE_FUNCTION); - }; - - ScopeManager.prototype.__nestModuleScope = function (node) { - return new Scope(this, node, false, SCOPE_MODULE); - }; - - ScopeManager.prototype.__nestTDZScope = function (node) { - return new Scope(this, node, false, SCOPE_TDZ); - }; - - ScopeManager.prototype.__nestFunctionExpressionNameScope = function (node, isMethodDefinition) { - return new Scope(this, node, isMethodDefinition, SCOPE_FUNCTION_EXPRESSION_NAME); - }; - - ScopeManager.prototype.__isES6 = function () { - return this.__options.ecmaVersion >= 6; - }; - - function traverseIdentifierInPattern(rootPattern, callback) { - estraverse.traverse(rootPattern, { - enter: function (pattern, parent) { - var i, iz, element, property; - - switch (pattern.type) { - case Syntax.Identifier: - // Toplevel identifier. - if (parent === null) { - callback(pattern, true); - } - break; - - case Syntax.SpreadElement: - if (pattern.argument.type === Syntax.Identifier) { - callback(pattern.argument, false); - } - break; - - case Syntax.ObjectPattern: - for (i = 0, iz = pattern.properties.length; i < iz; ++i) { - property = pattern.properties[i]; - if (property.shorthand) { - callback(property.key, false); - continue; - } - if (property.value.type === Syntax.Identifier) { - callback(property.value, false); - continue; - } - } - break; - - case Syntax.ArrayPattern: - for (i = 0, iz = pattern.elements.length; i < iz; ++i) { - element = pattern.elements[i]; - if (element && element.type === Syntax.Identifier) { - callback(element, false); - } - } - break; - } - } - }); - } - - function isPattern(node) { - var nodeType = node.type; - return nodeType === Syntax.Identifier || nodeType === Syntax.ObjectPattern || nodeType === Syntax.ArrayPattern || nodeType === Syntax.SpreadElement; - } - - // Importing ImportDeclaration. - // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-moduledeclarationinstantiation - // FIXME: Now, we don't create module environment, because the context is - // implementation dependent. - - function Importer(declaration, referencer) { - esrecurse.Visitor.call(this, this); - this.declaration = declaration; - this.referencer = referencer; - } - util.inherits(Importer, esrecurse.Visitor); - - Importer.prototype.visitImport = function (id, specifier) { - var that = this; - that.referencer.visitPattern(id, function (pattern) { - that.referencer.currentScope().__define(pattern, { - type: Variable.ImportBinding, - name: pattern, - node: specifier, - parent: that.declaration - }); - }); - }; - - Importer.prototype.ImportNamespaceSpecifier = function (node) { - if (node.id) { - this.visitImport(node.id, node); - } - }; - - Importer.prototype.ImportDefaultSpecifier = function (node) { - this.visitImport(node.id, node); - }; - - Importer.prototype.ImportSpecifier = function (node) { - if (node.name) { - this.visitImport(node.name, node); - } else { - this.visitImport(node.id, node); - } - }; - - // Referencing variables and creating bindings. - - function Referencer(scopeManager) { - esrecurse.Visitor.call(this, this); - this.scopeManager = scopeManager; - this.parent = null; - this.isInnerMethodDefinition = false; - } - - util.inherits(Referencer, esrecurse.Visitor); - - extend(Referencer.prototype, { - currentScope: function () { - return this.scopeManager.__currentScope; - }, - - close: function (node) { - while (this.currentScope() && node === this.currentScope().block) { - this.currentScope().__close(this.scopeManager); - } - }, - - pushInnerMethodDefinition: function (isInnerMethodDefinition) { - var previous = this.isInnerMethodDefinition; - this.isInnerMethodDefinition = isInnerMethodDefinition; - return previous; - }, - - popInnerMethodDefinition: function (isInnerMethodDefinition) { - this.isInnerMethodDefinition = isInnerMethodDefinition; - }, - - materializeTDZScope: function (node, iterationNode) { - // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-runtime-semantics-forin-div-ofexpressionevaluation-abstract-operation - // TDZ scope hides the declaration's names. - this.scopeManager.__nestTDZScope(node, iterationNode); - this.visitVariableDeclaration(this.currentScope(), Variable.TDZ, iterationNode.left, 0); - }, - - materializeIterationScope: function (node) { - // Generate iteration scope for upper ForIn/ForOf Statements. - // parent node for __nestScope is only necessary to - // distinguish MethodDefinition. - var letOrConstDecl, that = this; - this.scopeManager.__nestScope(node, false); - letOrConstDecl = node.left; - this.visitVariableDeclaration(this.currentScope(), Variable.Variable, letOrConstDecl, 0); - this.visitPattern(letOrConstDecl.declarations[0].id, function (pattern) { - that.currentScope().__referencing(pattern, Reference.WRITE, node.right, null, true); - }); - }, - - visitPattern: function (node, callback) { - traverseIdentifierInPattern(node, callback); - }, - - visitFunction: function (node) { - var i, iz, that = this; - // FunctionDeclaration name is defined in upper scope - // NOTE: Not referring variableScope. It is intended. - // Since - // in ES5, FunctionDeclaration should be in FunctionBody. - // in ES6, FunctionDeclaration should be block scoped. - if (node.type === Syntax.FunctionDeclaration) { - // id is defined in upper scope - this.currentScope().__define(node.id, { - type: Variable.FunctionName, - name: node.id, - node: node - }); - } - - // Consider this function is in the MethodDefinition. - this.scopeManager.__nestScope(node, this.isInnerMethodDefinition); - - for (i = 0, iz = node.params.length; i < iz; ++i) { - this.visitPattern(node.params[i], function (pattern) { - that.currentScope().__define(pattern, { - type: Variable.Parameter, - name: pattern, - node: node, - index: i, - rest: false - }); - }); - } - - - // if there's a rest argument, add that - if (node.rest) { - this.visitPattern(node.rest, function (pattern) { - that.currentScope().__define(pattern, { - type: Variable.Parameter, - name: pattern, - node: node, - index: node.params.length, - rest: true - }); - }); - } - - // Skip BlockStatement to prevent creating BlockStatement scope. - if (node.body.type === Syntax.BlockStatement) { - this.visitChildren(node.body); - } else { - this.visit(node.body); - } - - this.close(node); - }, - - visitClass: function (node) { - if (node.type === Syntax.ClassDeclaration) { - this.currentScope().__define(node.id, { - type: Variable.ClassName, - name: node.id, - node: node - }); - } - - // FIXME: Maybe consider TDZ. - this.visit(node.superClass); - - this.scopeManager.__nestScope(node); - - if (node.id) { - this.currentScope().__define(node.id, { - type: Variable.ClassName, - name: node.id, - node: node - }); - } - this.visit(node.body); - - this.close(node); - }, - - visitProperty: function (node) { - var previous, isMethodDefinition; - if (node.computed) { - this.visit(node.key); - } - - isMethodDefinition = node.type === Syntax.MethodDefinition || node.method; - if (isMethodDefinition) { - previous = this.pushInnerMethodDefinition(true); - } - this.visit(node.value); - if (isMethodDefinition) { - this.popInnerMethodDefinition(previous); - } - }, - - visitForIn: function (node) { - var that = this; - if (node.left.type === Syntax.VariableDeclaration && node.left.kind !== 'var') { - this.materializeTDZScope(node.right, node); - this.visit(node.right); - this.close(node.right); - - this.materializeIterationScope(node); - this.visit(node.body); - this.close(node); - } else { - if (node.left.type === Syntax.VariableDeclaration) { - this.visit(node.left); - this.visitPattern(node.left.declarations[0].id, function (pattern) { - that.currentScope().__referencing(pattern, Reference.WRITE, node.right, null, true); - }); - } else { - if (!isPattern(node.left)) { - this.visit(node.left); - } - this.visitPattern(node.left, function (pattern) { - var maybeImplicitGlobal = null; - if (!that.currentScope().isStrict) { - maybeImplicitGlobal = { - pattern: pattern, - node: node - }; - } - that.currentScope().__referencing(pattern, Reference.WRITE, node.right, maybeImplicitGlobal, true); - }); - } - this.visit(node.right); - this.visit(node.body); - } - }, - - visitVariableDeclaration: function (variableTargetScope, type, node, index) { - var decl, init, that = this; - - decl = node.declarations[index]; - init = decl.init; - // FIXME: Don't consider initializer with complex patterns. - // Such as, - // var [a, b, c = 20] = array; - this.visitPattern(decl.id, function (pattern, toplevel) { - variableTargetScope.__define(pattern, { - type: type, - name: pattern, - node: decl, - index: index, - kind: node.kind, - parent: node - }); - - if (init) { - that.currentScope().__referencing(pattern, Reference.WRITE, init, null, !toplevel); - } - }); - }, - - AssignmentExpression: function (node) { - var that = this; - if (isPattern(node.left)) { - if (node.operator === '=') { - this.visitPattern(node.left, function (pattern, toplevel) { - var maybeImplicitGlobal = null; - if (!that.currentScope().isStrict) { - maybeImplicitGlobal = { - pattern: pattern, - node: node - }; - } - that.currentScope().__referencing(pattern, Reference.WRITE, node.right, maybeImplicitGlobal, !toplevel); - }); - } else { - that.currentScope().__referencing(node.left, Reference.RW, node.right); - } - } else { - this.visit(node.left); - } - this.visit(node.right); - }, - - CatchClause: function (node) { - var that = this; - this.scopeManager.__nestScope(node); - - this.visitPattern(node.param, function (pattern) { - that.currentScope().__define(pattern, { - type: Variable.CatchClause, - name: node.param, - node: node - }); - }); - this.visit(node.body); - - this.close(node); - }, - - Program: function (node) { - this.scopeManager.__nestScope(node); - - if (this.scopeManager.__isNodejsScope()) { - // Force strictness of GlobalScope to false when using node.js scope. - this.currentScope().isStrict = false; - this.scopeManager.__nestForceFunctionScope(node); - } - - if (this.scopeManager.__isES6() && this.scopeManager.isModule()) { - this.scopeManager.__nestModuleScope(node); - } - - this.visitChildren(node); - this.close(node); - }, - - Identifier: function (node) { - this.currentScope().__referencing(node); - }, - - UpdateExpression: function (node) { - if (isPattern(node.argument)) { - this.currentScope().__referencing(node.argument, Reference.RW, null); - } else { - this.visitChildren(node); - } - }, - - MemberExpression: function (node) { - this.visit(node.object); - if (node.computed) { - this.visit(node.property); - } - }, - - Property: function (node) { - this.visitProperty(node); - }, - - MethodDefinition: function (node) { - this.visitProperty(node); - }, - - BreakStatement: function () {}, - - ContinueStatement: function () {}, - - LabeledStatement: function (node) { - this.visit(node.body); - }, - - ForStatement: function (node) { - // Create ForStatement declaration. - // NOTE: In ES6, ForStatement dynamically generates - // per iteration environment. However, escope is - // a static analyzer, we only generate one scope for ForStatement. - if (node.init && node.init.type === Syntax.VariableDeclaration && node.init.kind !== 'var') { - this.scopeManager.__nestScope(node); - } - - this.visitChildren(node); - - this.close(node); - }, - - ClassExpression: function (node) { - this.visitClass(node); - }, - - ClassDeclaration: function (node) { - this.visitClass(node); - }, - - CallExpression: function (node) { - // Check this is direct call to eval - if (!this.scopeManager.__ignoreEval() && node.callee.type === Syntax.Identifier && node.callee.name === 'eval') { - // NOTE: This should be `variableScope`. Since direct eval call always creates Lexical environment and - // let / const should be enclosed into it. Only VariableDeclaration affects on the caller's environment. - this.currentScope().variableScope.__detectEval(); - } - this.visitChildren(node); - }, - - BlockStatement: function (node) { - if (this.scopeManager.__isES6()) { - this.scopeManager.__nestScope(node); - } - - this.visitChildren(node); - - this.close(node); - }, - - ThisExpression: function () { - this.currentScope().variableScope.__detectThis(); - }, - - WithStatement: function (node) { - this.visit(node.object); - // Then nest scope for WithStatement. - this.scopeManager.__nestScope(node); - - this.visit(node.body); - - this.close(node); - }, - - VariableDeclaration: function (node) { - var variableTargetScope, i, iz, decl; - variableTargetScope = (node.kind === 'var') ? this.currentScope().variableScope : this.currentScope(); - for (i = 0, iz = node.declarations.length; i < iz; ++i) { - decl = node.declarations[i]; - this.visitVariableDeclaration(variableTargetScope, Variable.Variable, node, i); - if (decl.init) { - this.visit(decl.init); - } - } - }, - - // sec 13.11.8 - SwitchStatement: function (node) { - var i, iz; - - this.visit(node.discriminant); - - if (this.scopeManager.__isES6()) { - this.scopeManager.__nestScope(node); - } - - for (i = 0, iz = node.cases.length; i < iz; ++i) { - this.visit(node.cases[i]); - } - - this.close(node); - }, - - FunctionDeclaration: function (node) { - this.visitFunction(node); - }, - - FunctionExpression: function (node) { - this.visitFunction(node); - }, - - ForOfStatement: function (node) { - this.visitForIn(node); - }, - - ForInStatement: function (node) { - this.visitForIn(node); - }, - - ArrowFunctionExpression: function (node) { - this.visitFunction(node); - }, - - ImportDeclaration: function (node) { - var importer; - - assert(this.scopeManager.__isES6() && this.scopeManager.isModule()); - - importer = new Importer(node, this); - importer.visit(node); - }, - - ExportDeclaration: function (node) { - if (node.source) { - return; - } - if (node.declaration) { - this.visit(node.declaration); - return; - } - - this.visitChildren(node); - }, - - ExportSpecifier: function (node) { - this.visit(node.id); - } - }); - - /** - * Main interface function. Takes an Esprima syntax tree and returns the - * analyzed scopes. - * @function analyze - * @param {esprima.Tree} tree - * @param {Object} providedOptions - Options that tailor the scope analysis - * @param {boolean} [providedOptions.optimistic=false] - the optimistic flag - * @param {boolean} [providedOptions.directive=false]- the directive flag - * @param {boolean} [providedOptions.nodejsScope=false]- whether the whole - * script is executed under node.js environment. When enabled, escope adds - * a function scope immediately following the global scope. - * @param {boolean} [providedOptions.ignoreEval=false]- whether to check 'eval()' calls - * @param {string} [providedOptions.sourceType='script']- the source type of the script. one of 'script' and 'module' - * @param {number} [providedOptions.ecmaVersion=5]- which ECMAScript version is considered - * @return {ScopeManager} - */ - function analyze(tree, providedOptions) { - var scopeManager, referencer, options; - - options = updateDeeply(defaultOptions(), providedOptions); - - scopeManager = new ScopeManager(options); - - referencer = new Referencer(scopeManager); - referencer.visit(tree); - - assert(scopeManager.__currentScope === null); - - return scopeManager; - } - - /** @name module:escope.version */ - exports.version = require('./package.json').version; - /** @name module:escope.Reference */ - exports.Reference = Reference; - /** @name module:escope.Variable */ - exports.Variable = Variable; - /** @name module:escope.Scope */ - exports.Scope = Scope; - /** @name module:escope.ScopeManager */ - exports.ScopeManager = ScopeManager; - /** @name module:escope.analyze */ - exports.analyze = analyze; -}()); -/* vim: set sw=4 ts=4 et tw=80 : */ - -},{"./package.json":124,"es6-map":20,"es6-weak-map":75,"esrecurse":121,"estraverse":127,"util":8,"util-extend":123}],20:[function(require,module,exports){ -'use strict'; - -module.exports = require('./is-implemented')() ? Map : require('./polyfill'); - -},{"./is-implemented":21,"./polyfill":74}],21:[function(require,module,exports){ -'use strict'; - -module.exports = function () { - var map, iterator, result; - if (typeof Map !== 'function') return false; - try { - // WebKit doesn't support arguments and crashes - map = new Map([['raz', 'one'], ['dwa', 'two'], ['trzy', 'three']]); - } catch (e) { - return false; - } - if (map.size !== 3) return false; - if (typeof map.clear !== 'function') return false; - if (typeof map.delete !== 'function') return false; - if (typeof map.entries !== 'function') return false; - if (typeof map.forEach !== 'function') return false; - if (typeof map.get !== 'function') return false; - if (typeof map.has !== 'function') return false; - if (typeof map.keys !== 'function') return false; - if (typeof map.set !== 'function') return false; - if (typeof map.values !== 'function') return false; - - iterator = map.entries(); - result = iterator.next(); - if (result.done !== false) return false; - if (!result.value) return false; - if (result.value[0] !== 'raz') return false; - if (result.value[1] !== 'one') return false; - return true; -}; - -},{}],22:[function(require,module,exports){ -// Exports true if environment provides native `Map` implementation, -// whatever that is. - -'use strict'; - -module.exports = (function () { - if (typeof Map === 'undefined') return false; - return (Object.prototype.toString.call(Map.prototype) === '[object Map]'); -}()); - -},{}],23:[function(require,module,exports){ -'use strict'; - -module.exports = require('es5-ext/object/primitive-set')('key', - 'value', 'key+value'); - -},{"es5-ext/object/primitive-set":48}],24:[function(require,module,exports){ -'use strict'; - -var setPrototypeOf = require('es5-ext/object/set-prototype-of') - , d = require('d') - , Iterator = require('es6-iterator') - , toStringTagSymbol = require('es6-symbol').toStringTag - , kinds = require('./iterator-kinds') - - , defineProperties = Object.defineProperties - , unBind = Iterator.prototype._unBind - , MapIterator; - -MapIterator = module.exports = function (map, kind) { - if (!(this instanceof MapIterator)) return new MapIterator(map, kind); - Iterator.call(this, map.__mapKeysData__, map); - if (!kind || !kinds[kind]) kind = 'key+value'; - defineProperties(this, { - __kind__: d('', kind), - __values__: d('w', map.__mapValuesData__) - }); -}; -if (setPrototypeOf) setPrototypeOf(MapIterator, Iterator); - -MapIterator.prototype = Object.create(Iterator.prototype, { - constructor: d(MapIterator), - _resolve: d(function (i) { - if (this.__kind__ === 'value') return this.__values__[i]; - if (this.__kind__ === 'key') return this.__list__[i]; - return [this.__list__[i], this.__values__[i]]; - }), - _unBind: d(function () { - this.__values__ = null; - unBind.call(this); - }), - toString: d(function () { return '[object Map Iterator]'; }) -}); -Object.defineProperty(MapIterator.prototype, toStringTagSymbol, - d('c', 'Map Iterator')); - -},{"./iterator-kinds":23,"d":26,"es5-ext/object/set-prototype-of":49,"es6-iterator":61,"es6-symbol":70}],25:[function(require,module,exports){ -'use strict'; - -var copy = require('es5-ext/object/copy') - , map = require('es5-ext/object/map') - , callable = require('es5-ext/object/valid-callable') - , validValue = require('es5-ext/object/valid-value') - - , bind = Function.prototype.bind, defineProperty = Object.defineProperty - , hasOwnProperty = Object.prototype.hasOwnProperty - , define; - -define = function (name, desc, bindTo) { - var value = validValue(desc) && callable(desc.value), dgs; - dgs = copy(desc); - delete dgs.writable; - delete dgs.value; - dgs.get = function () { - if (hasOwnProperty.call(this, name)) return value; - desc.value = bind.call(value, (bindTo == null) ? this : this[bindTo]); - defineProperty(this, name, desc); - return this[name]; - }; - return dgs; -}; - -module.exports = function (props/*, bindTo*/) { - var bindTo = arguments[1]; - return map(props, function (desc, name) { - return define(name, desc, bindTo); - }); -}; - -},{"es5-ext/object/copy":38,"es5-ext/object/map":46,"es5-ext/object/valid-callable":52,"es5-ext/object/valid-value":53}],26:[function(require,module,exports){ -'use strict'; - -var assign = require('es5-ext/object/assign') - , normalizeOpts = require('es5-ext/object/normalize-options') - , isCallable = require('es5-ext/object/is-callable') - , contains = require('es5-ext/string/#/contains') - - , d; - -d = module.exports = function (dscr, value/*, options*/) { - var c, e, w, options, desc; - if ((arguments.length < 2) || (typeof dscr !== 'string')) { - options = value; - value = dscr; - dscr = null; - } else { - options = arguments[2]; - } - if (dscr == null) { - c = w = true; - e = false; - } else { - c = contains.call(dscr, 'c'); - e = contains.call(dscr, 'e'); - w = contains.call(dscr, 'w'); - } - - desc = { value: value, configurable: c, enumerable: e, writable: w }; - return !options ? desc : assign(normalizeOpts(options), desc); -}; - -d.gs = function (dscr, get, set/*, options*/) { - var c, e, options, desc; - if (typeof dscr !== 'string') { - options = set; - set = get; - get = dscr; - dscr = null; - } else { - options = arguments[3]; - } - if (get == null) { - get = undefined; - } else if (!isCallable(get)) { - options = get; - get = set = undefined; - } else if (set == null) { - set = undefined; - } else if (!isCallable(set)) { - options = set; - set = undefined; - } - if (dscr == null) { - c = true; - e = false; - } else { - c = contains.call(dscr, 'c'); - e = contains.call(dscr, 'e'); - } - - desc = { get: get, set: set, configurable: c, enumerable: e }; - return !options ? desc : assign(normalizeOpts(options), desc); -}; - -},{"es5-ext/object/assign":35,"es5-ext/object/is-callable":41,"es5-ext/object/normalize-options":47,"es5-ext/string/#/contains":54}],27:[function(require,module,exports){ // Inspired by Google Closure: // http://closure-library.googlecode.com/svn/docs/ // closure_goog_array_array.js.html#goog.array.clear 'use strict'; @@ -13459,11 +11684,11 @@ module.exports = function () { value(this).length = 0; return this; }; -},{"../../object/valid-value":53}],28:[function(require,module,exports){ +},{"../../object/valid-value":46}],19:[function(require,module,exports){ 'use strict'; var toPosInt = require('../../number/to-pos-integer') , value = require('../../object/valid-value') @@ -13490,36 +11715,45 @@ } } return -1; }; -},{"../../number/to-pos-integer":33,"../../object/valid-value":53}],29:[function(require,module,exports){ +},{"../../number/to-pos-integer":25,"../../object/valid-value":46}],20:[function(require,module,exports){ 'use strict'; +var toString = Object.prototype.toString + + , id = toString.call((function () { return arguments; }())); + +module.exports = function (x) { return (toString.call(x) === id); }; + +},{}],21:[function(require,module,exports){ +'use strict'; + module.exports = require('./is-implemented')() ? Math.sign : require('./shim'); -},{"./is-implemented":30,"./shim":31}],30:[function(require,module,exports){ +},{"./is-implemented":22,"./shim":23}],22:[function(require,module,exports){ 'use strict'; module.exports = function () { var sign = Math.sign; if (typeof sign !== 'function') return false; return ((sign(10) === 1) && (sign(-20) === -1)); }; -},{}],31:[function(require,module,exports){ +},{}],23:[function(require,module,exports){ 'use strict'; module.exports = function (value) { value = Number(value); if (isNaN(value) || (value === 0)) return value; return (value > 0) ? 1 : -1; }; -},{}],32:[function(require,module,exports){ +},{}],24:[function(require,module,exports){ 'use strict'; var sign = require('../math/sign') , abs = Math.abs, floor = Math.floor; @@ -13529,69 +11763,69 @@ value = Number(value); if ((value === 0) || !isFinite(value)) return value; return sign(value) * floor(abs(value)); }; -},{"../math/sign":29}],33:[function(require,module,exports){ +},{"../math/sign":21}],25:[function(require,module,exports){ 'use strict'; var toInteger = require('./to-integer') , max = Math.max; module.exports = function (value) { return max(0, toInteger(value)); }; -},{"./to-integer":32}],34:[function(require,module,exports){ +},{"./to-integer":24}],26:[function(require,module,exports){ // Internal method, used by iteration functions. // Calls a function for each key-value pair found in object // Optionally takes compareFn to iterate object in specific order 'use strict'; -var isCallable = require('./is-callable') - , callable = require('./valid-callable') - , value = require('./valid-value') +var callable = require('./valid-callable') + , value = require('./valid-value') - , call = Function.prototype.call, keys = Object.keys + , bind = Function.prototype.bind, call = Function.prototype.call, keys = Object.keys , propertyIsEnumerable = Object.prototype.propertyIsEnumerable; module.exports = function (method, defVal) { return function (obj, cb/*, thisArg, compareFn*/) { var list, thisArg = arguments[2], compareFn = arguments[3]; obj = Object(value(obj)); callable(cb); list = keys(obj); if (compareFn) { - list.sort(isCallable(compareFn) ? compareFn.bind(obj) : undefined); + list.sort((typeof compareFn === 'function') ? bind.call(compareFn, obj) : undefined); } - return list[method](function (key, index) { + if (typeof method !== 'function') method = list[method]; + return call.call(method, list, function (key, index) { if (!propertyIsEnumerable.call(obj, key)) return defVal; return call.call(cb, thisArg, obj[key], key, obj, index); }); }; }; -},{"./is-callable":41,"./valid-callable":52,"./valid-value":53}],35:[function(require,module,exports){ +},{"./valid-callable":44,"./valid-value":46}],27:[function(require,module,exports){ 'use strict'; module.exports = require('./is-implemented')() ? Object.assign : require('./shim'); -},{"./is-implemented":36,"./shim":37}],36:[function(require,module,exports){ +},{"./is-implemented":28,"./shim":29}],28:[function(require,module,exports){ 'use strict'; module.exports = function () { var assign = Object.assign, obj; if (typeof assign !== 'function') return false; obj = { foo: 'raz' }; assign(obj, { bar: 'dwa' }, { trzy: 'trzy' }); return (obj.foo + obj.bar + obj.trzy) === 'razdwatrzy'; }; -},{}],37:[function(require,module,exports){ +},{}],29:[function(require,module,exports){ 'use strict'; var keys = require('../keys') , value = require('../valid-value') @@ -13611,11 +11845,11 @@ } if (error !== undefined) throw error; return dest; }; -},{"../keys":43,"../valid-value":53}],38:[function(require,module,exports){ +},{"../keys":35,"../valid-value":46}],30:[function(require,module,exports){ 'use strict'; var assign = require('./assign') , value = require('./valid-value'); @@ -13623,11 +11857,11 @@ var copy = Object(value(obj)); if (copy !== obj) return copy; return assign({}, obj); }; -},{"./assign":35,"./valid-value":53}],39:[function(require,module,exports){ +},{"./assign":27,"./valid-value":46}],31:[function(require,module,exports){ // Workaround for http://code.google.com/p/v8/issues/detail?id=2804 'use strict'; var create = Object.create, shim; @@ -13661,58 +11895,58 @@ return function (prototype, props) { return create((prototype === null) ? nullObject : prototype, props); }; }()); -},{"./set-prototype-of/is-implemented":50,"./set-prototype-of/shim":51}],40:[function(require,module,exports){ +},{"./set-prototype-of/is-implemented":42,"./set-prototype-of/shim":43}],32:[function(require,module,exports){ 'use strict'; module.exports = require('./_iterate')('forEach'); -},{"./_iterate":34}],41:[function(require,module,exports){ +},{"./_iterate":26}],33:[function(require,module,exports){ // Deprecated 'use strict'; module.exports = function (obj) { return typeof obj === 'function'; }; -},{}],42:[function(require,module,exports){ +},{}],34:[function(require,module,exports){ 'use strict'; var map = { function: true, object: true }; module.exports = function (x) { return ((x != null) && map[typeof x]) || false; }; -},{}],43:[function(require,module,exports){ +},{}],35:[function(require,module,exports){ 'use strict'; module.exports = require('./is-implemented')() ? Object.keys : require('./shim'); -},{"./is-implemented":44,"./shim":45}],44:[function(require,module,exports){ +},{"./is-implemented":36,"./shim":37}],36:[function(require,module,exports){ 'use strict'; module.exports = function () { try { Object.keys('primitive'); return true; } catch (e) { return false; } }; -},{}],45:[function(require,module,exports){ +},{}],37:[function(require,module,exports){ 'use strict'; var keys = Object.keys; module.exports = function (object) { return keys(object == null ? object : Object(object)); }; -},{}],46:[function(require,module,exports){ +},{}],38:[function(require,module,exports){ 'use strict'; var callable = require('./valid-callable') , forEach = require('./for-each') @@ -13725,11 +11959,11 @@ o[key] = call.call(cb, thisArg, value, key, obj, index); }); return o; }; -},{"./for-each":40,"./valid-callable":52}],47:[function(require,module,exports){ +},{"./for-each":32,"./valid-callable":44}],39:[function(require,module,exports){ 'use strict'; var forEach = Array.prototype.forEach, create = Object.create; var process = function (src, obj) { @@ -13744,29 +11978,29 @@ process(Object(options), result); }); return result; }; -},{}],48:[function(require,module,exports){ +},{}],40:[function(require,module,exports){ 'use strict'; var forEach = Array.prototype.forEach, create = Object.create; module.exports = function (arg/*, …args*/) { var set = create(null); forEach.call(arguments, function (name) { set[name] = true; }); return set; }; -},{}],49:[function(require,module,exports){ +},{}],41:[function(require,module,exports){ 'use strict'; module.exports = require('./is-implemented')() ? Object.setPrototypeOf : require('./shim'); -},{"./is-implemented":50,"./shim":51}],50:[function(require,module,exports){ +},{"./is-implemented":42,"./shim":43}],42:[function(require,module,exports){ 'use strict'; var create = Object.create, getPrototypeOf = Object.getPrototypeOf , x = {}; @@ -13775,11 +12009,11 @@ , customCreate = arguments[0] || create; if (typeof setPrototypeOf !== 'function') return false; return getPrototypeOf(setPrototypeOf(customCreate(null), x)) === x; }; -},{}],51:[function(require,module,exports){ +},{}],43:[function(require,module,exports){ // Big thanks to @WebReflection for sorting this out // https://gist.github.com/WebReflection/5593554 'use strict'; @@ -13850,53 +12084,63 @@ return false; }()))); require('../create'); -},{"../create":39,"../is-object":42,"../valid-value":53}],52:[function(require,module,exports){ +},{"../create":31,"../is-object":34,"../valid-value":46}],44:[function(require,module,exports){ 'use strict'; module.exports = function (fn) { if (typeof fn !== 'function') throw new TypeError(fn + " is not a function"); return fn; }; -},{}],53:[function(require,module,exports){ +},{}],45:[function(require,module,exports){ 'use strict'; +var isObject = require('./is-object'); + module.exports = function (value) { + if (!isObject(value)) throw new TypeError(value + " is not an Object"); + return value; +}; + +},{"./is-object":34}],46:[function(require,module,exports){ +'use strict'; + +module.exports = function (value) { if (value == null) throw new TypeError("Cannot use null or undefined"); return value; }; -},{}],54:[function(require,module,exports){ +},{}],47:[function(require,module,exports){ 'use strict'; module.exports = require('./is-implemented')() ? String.prototype.contains : require('./shim'); -},{"./is-implemented":55,"./shim":56}],55:[function(require,module,exports){ +},{"./is-implemented":48,"./shim":49}],48:[function(require,module,exports){ 'use strict'; var str = 'razdwatrzy'; module.exports = function () { if (typeof str.contains !== 'function') return false; return ((str.contains('dwa') === true) && (str.contains('foo') === false)); }; -},{}],56:[function(require,module,exports){ +},{}],49:[function(require,module,exports){ 'use strict'; var indexOf = String.prototype.indexOf; module.exports = function (searchString/*, position*/) { return indexOf.call(this, searchString, arguments[1]) > -1; }; -},{}],57:[function(require,module,exports){ +},{}],50:[function(require,module,exports){ 'use strict'; var toString = Object.prototype.toString , id = toString.call(''); @@ -13904,13 +12148,26 @@ module.exports = function (x) { return (typeof x === 'string') || (x && (typeof x === 'object') && ((x instanceof String) || (toString.call(x) === id))) || false; }; -},{}],58:[function(require,module,exports){ +},{}],51:[function(require,module,exports){ 'use strict'; +var generated = Object.create(null) + + , random = Math.random; + +module.exports = function () { + var str; + do { str = random().toString(36).slice(2); } while (generated[str]); + return str; +}; + +},{}],52:[function(require,module,exports){ +'use strict'; + var setPrototypeOf = require('es5-ext/object/set-prototype-of') , contains = require('es5-ext/string/#/contains') , d = require('d') , Iterator = require('./') @@ -13936,29 +12193,31 @@ return i; }), toString: d(function () { return '[object Array Iterator]'; }) }); -},{"./":61,"d":26,"es5-ext/object/set-prototype-of":49,"es5-ext/string/#/contains":54}],59:[function(require,module,exports){ +},{"./":55,"d":7,"es5-ext/object/set-prototype-of":41,"es5-ext/string/#/contains":47}],53:[function(require,module,exports){ 'use strict'; -var callable = require('es5-ext/object/valid-callable') - , isString = require('es5-ext/string/is-string') - , get = require('./get') +var isArguments = require('es5-ext/function/is-arguments') + , callable = require('es5-ext/object/valid-callable') + , isString = require('es5-ext/string/is-string') + , get = require('./get') - , isArray = Array.isArray, call = Function.prototype.call; + , isArray = Array.isArray, call = Function.prototype.call + , some = Array.prototype.some; module.exports = function (iterable, cb/*, thisArg*/) { var mode, thisArg = arguments[2], result, doBreak, broken, i, l, char, code; - if (isArray(iterable)) mode = 'array'; + if (isArray(iterable) || isArguments(iterable)) mode = 'array'; else if (isString(iterable)) mode = 'string'; else iterable = get(iterable); callable(cb); doBreak = function () { broken = true; }; if (mode === 'array') { - iterable.some(function (value) { + some.call(iterable, function (value) { call.call(cb, thisArg, value, doBreak); if (broken) return true; }); return; } @@ -13982,26 +12241,28 @@ if (broken) return; result = iterable.next(); } }; -},{"./get":60,"es5-ext/object/valid-callable":52,"es5-ext/string/is-string":57}],60:[function(require,module,exports){ +},{"./get":54,"es5-ext/function/is-arguments":20,"es5-ext/object/valid-callable":44,"es5-ext/string/is-string":50}],54:[function(require,module,exports){ 'use strict'; -var isString = require('es5-ext/string/is-string') +var isArguments = require('es5-ext/function/is-arguments') + , isString = require('es5-ext/string/is-string') , ArrayIterator = require('./array') , StringIterator = require('./string') , iterable = require('./valid-iterable') , iteratorSymbol = require('es6-symbol').iterator; module.exports = function (obj) { if (typeof iterable(obj)[iteratorSymbol] === 'function') return obj[iteratorSymbol](); + if (isArguments(obj)) return new ArrayIterator(obj); if (isString(obj)) return new StringIterator(obj); return new ArrayIterator(obj); }; -},{"./array":58,"./string":68,"./valid-iterable":69,"es5-ext/string/is-string":57,"es6-symbol":63}],61:[function(require,module,exports){ +},{"./array":52,"./string":57,"./valid-iterable":58,"es5-ext/function/is-arguments":20,"es5-ext/string/is-string":50,"es6-symbol":65}],55:[function(require,module,exports){ 'use strict'; var clear = require('es5-ext/array/#/clear') , assign = require('es5-ext/object/assign') , callable = require('es5-ext/object/valid-callable') @@ -14089,147 +12350,28 @@ defineProperty(Iterator.prototype, Symbol.iterator, d(function () { return this; })); defineProperty(Iterator.prototype, Symbol.toStringTag, d('', 'Iterator')); -},{"d":26,"d/auto-bind":25,"es5-ext/array/#/clear":27,"es5-ext/object/assign":35,"es5-ext/object/valid-callable":52,"es5-ext/object/valid-value":53,"es6-symbol":63}],62:[function(require,module,exports){ +},{"d":7,"d/auto-bind":6,"es5-ext/array/#/clear":18,"es5-ext/object/assign":27,"es5-ext/object/valid-callable":44,"es5-ext/object/valid-value":46,"es6-symbol":65}],56:[function(require,module,exports){ 'use strict'; -var isString = require('es5-ext/string/is-string') +var isArguments = require('es5-ext/function/is-arguments') + , isString = require('es5-ext/string/is-string') , iteratorSymbol = require('es6-symbol').iterator , isArray = Array.isArray; module.exports = function (value) { if (value == null) return false; if (isArray(value)) return true; if (isString(value)) return true; + if (isArguments(value)) return true; return (typeof value[iteratorSymbol] === 'function'); }; -},{"es5-ext/string/is-string":57,"es6-symbol":63}],63:[function(require,module,exports){ -'use strict'; - -module.exports = require('./is-implemented')() ? Symbol : require('./polyfill'); - -},{"./is-implemented":64,"./polyfill":66}],64:[function(require,module,exports){ -'use strict'; - -module.exports = function () { - var symbol; - if (typeof Symbol !== 'function') return false; - symbol = Symbol('test symbol'); - try { String(symbol); } catch (e) { return false; } - if (typeof Symbol.iterator === 'symbol') return true; - - // Return 'true' for polyfills - if (typeof Symbol.isConcatSpreadable !== 'object') return false; - if (typeof Symbol.iterator !== 'object') return false; - if (typeof Symbol.toPrimitive !== 'object') return false; - if (typeof Symbol.toStringTag !== 'object') return false; - if (typeof Symbol.unscopables !== 'object') return false; - - return true; -}; - -},{}],65:[function(require,module,exports){ -'use strict'; - -module.exports = function (x) { - return (x && ((typeof x === 'symbol') || (x['@@toStringTag'] === 'Symbol'))) || false; -}; - -},{}],66:[function(require,module,exports){ -'use strict'; - -var d = require('d') - , validateSymbol = require('./validate-symbol') - - , create = Object.create, defineProperties = Object.defineProperties - , defineProperty = Object.defineProperty, objPrototype = Object.prototype - , Symbol, HiddenSymbol, globalSymbols = create(null); - -var generateName = (function () { - var created = create(null); - return function (desc) { - var postfix = 0, name; - while (created[desc + (postfix || '')]) ++postfix; - desc += (postfix || ''); - created[desc] = true; - name = '@@' + desc; - defineProperty(objPrototype, name, d.gs(null, function (value) { - defineProperty(this, name, d(value)); - })); - return name; - }; -}()); - -HiddenSymbol = function Symbol(description) { - if (this instanceof HiddenSymbol) throw new TypeError('TypeError: Symbol is not a constructor'); - return Symbol(description); -}; -module.exports = Symbol = function Symbol(description) { - var symbol; - if (this instanceof Symbol) throw new TypeError('TypeError: Symbol is not a constructor'); - symbol = create(HiddenSymbol.prototype); - description = (description === undefined ? '' : String(description)); - return defineProperties(symbol, { - __description__: d('', description), - __name__: d('', generateName(description)) - }); -}; -defineProperties(Symbol, { - for: d(function (key) { - if (globalSymbols[key]) return globalSymbols[key]; - return (globalSymbols[key] = Symbol(String(key))); - }), - keyFor: d(function (s) { - var key; - validateSymbol(s); - for (key in globalSymbols) if (globalSymbols[key] === s) return key; - }), - hasInstance: d('', Symbol('hasInstance')), - isConcatSpreadable: d('', Symbol('isConcatSpreadable')), - iterator: d('', Symbol('iterator')), - match: d('', Symbol('match')), - replace: d('', Symbol('replace')), - search: d('', Symbol('search')), - species: d('', Symbol('species')), - split: d('', Symbol('split')), - toPrimitive: d('', Symbol('toPrimitive')), - toStringTag: d('', Symbol('toStringTag')), - unscopables: d('', Symbol('unscopables')) -}); -defineProperties(HiddenSymbol.prototype, { - constructor: d(Symbol), - toString: d('', function () { return this.__name__; }) -}); - -defineProperties(Symbol.prototype, { - toString: d(function () { return 'Symbol (' + validateSymbol(this).__description__ + ')'; }), - valueOf: d(function () { return validateSymbol(this); }) -}); -defineProperty(Symbol.prototype, Symbol.toPrimitive, d('', - function () { return validateSymbol(this); })); -defineProperty(Symbol.prototype, Symbol.toStringTag, d('c', 'Symbol')); - -defineProperty(HiddenSymbol.prototype, Symbol.toPrimitive, - d('c', Symbol.prototype[Symbol.toPrimitive])); -defineProperty(HiddenSymbol.prototype, Symbol.toStringTag, - d('c', Symbol.prototype[Symbol.toStringTag])); - -},{"./validate-symbol":67,"d":26}],67:[function(require,module,exports){ -'use strict'; - -var isSymbol = require('./is-symbol'); - -module.exports = function (value) { - if (!isSymbol(value)) throw new TypeError(value + " is not a symbol"); - return value; -}; - -},{"./is-symbol":65}],68:[function(require,module,exports){ +},{"es5-ext/function/is-arguments":20,"es5-ext/string/is-string":50,"es6-symbol":65}],57:[function(require,module,exports){ // Thanks @mathiasbynens // http://mathiasbynens.be/notes/javascript-unicode#iterating-over-symbols 'use strict'; @@ -14264,233 +12406,117 @@ return char; }), toString: d(function () { return '[object String Iterator]'; }) }); -},{"./":61,"d":26,"es5-ext/object/set-prototype-of":49}],69:[function(require,module,exports){ +},{"./":55,"d":7,"es5-ext/object/set-prototype-of":41}],58:[function(require,module,exports){ 'use strict'; var isIterable = require('./is-iterable'); module.exports = function (value) { if (!isIterable(value)) throw new TypeError(value + " is not iterable"); return value; }; -},{"./is-iterable":62}],70:[function(require,module,exports){ -arguments[4][63][0].apply(exports,arguments) -},{"./is-implemented":71,"./polyfill":72,"dup":63}],71:[function(require,module,exports){ +},{"./is-iterable":56}],59:[function(require,module,exports){ 'use strict'; +module.exports = require('./is-implemented')() ? Map : require('./polyfill'); + +},{"./is-implemented":60,"./polyfill":64}],60:[function(require,module,exports){ +'use strict'; + module.exports = function () { - var symbol; - if (typeof Symbol !== 'function') return false; - symbol = Symbol('test symbol'); - try { String(symbol); } catch (e) { return false; } - if (typeof Symbol.iterator === 'symbol') return true; + var map, iterator, result; + if (typeof Map !== 'function') return false; + try { + // WebKit doesn't support arguments and crashes + map = new Map([['raz', 'one'], ['dwa', 'two'], ['trzy', 'three']]); + } catch (e) { + return false; + } + if (String(map) !== '[object Map]') return false; + if (map.size !== 3) return false; + if (typeof map.clear !== 'function') return false; + if (typeof map.delete !== 'function') return false; + if (typeof map.entries !== 'function') return false; + if (typeof map.forEach !== 'function') return false; + if (typeof map.get !== 'function') return false; + if (typeof map.has !== 'function') return false; + if (typeof map.keys !== 'function') return false; + if (typeof map.set !== 'function') return false; + if (typeof map.values !== 'function') return false; - // Return 'true' for polyfills - if (typeof Symbol.isConcatSpreadable !== 'object') return false; - if (typeof Symbol.isRegExp !== 'object') return false; - if (typeof Symbol.iterator !== 'object') return false; - if (typeof Symbol.toPrimitive !== 'object') return false; - if (typeof Symbol.toStringTag !== 'object') return false; - if (typeof Symbol.unscopables !== 'object') return false; + iterator = map.entries(); + result = iterator.next(); + if (result.done !== false) return false; + if (!result.value) return false; + if (result.value[0] !== 'raz') return false; + if (result.value[1] !== 'one') return false; return true; }; -},{}],72:[function(require,module,exports){ +},{}],61:[function(require,module,exports){ +// Exports true if environment provides native `Map` implementation, +// whatever that is. + 'use strict'; -var d = require('d') - - , create = Object.create, defineProperties = Object.defineProperties - , generateName, Symbol; - -generateName = (function () { - var created = create(null); - return function (desc) { - var postfix = 0; - while (created[desc + (postfix || '')]) ++postfix; - desc += (postfix || ''); - created[desc] = true; - return '@@' + desc; - }; +module.exports = (function () { + if (typeof Map === 'undefined') return false; + return (Object.prototype.toString.call(new Map()) === '[object Map]'); }()); -module.exports = Symbol = function (description) { - var symbol; - if (this instanceof Symbol) { - throw new TypeError('TypeError: Symbol is not a constructor'); - } - symbol = create(Symbol.prototype); - description = (description === undefined ? '' : String(description)); - return defineProperties(symbol, { - __description__: d('', description), - __name__: d('', generateName(description)) - }); -}; +},{}],62:[function(require,module,exports){ +'use strict'; -Object.defineProperties(Symbol, { - create: d('', Symbol('create')), - hasInstance: d('', Symbol('hasInstance')), - isConcatSpreadable: d('', Symbol('isConcatSpreadable')), - isRegExp: d('', Symbol('isRegExp')), - iterator: d('', Symbol('iterator')), - toPrimitive: d('', Symbol('toPrimitive')), - toStringTag: d('', Symbol('toStringTag')), - unscopables: d('', Symbol('unscopables')) -}); +module.exports = require('es5-ext/object/primitive-set')('key', + 'value', 'key+value'); -defineProperties(Symbol.prototype, { - properToString: d(function () { - return 'Symbol (' + this.__description__ + ')'; - }), - toString: d('', function () { return this.__name__; }) -}); -Object.defineProperty(Symbol.prototype, Symbol.toPrimitive, d('', - function (hint) { - throw new TypeError("Conversion of symbol objects is not allowed"); - })); -Object.defineProperty(Symbol.prototype, Symbol.toStringTag, d('c', 'Symbol')); - -},{"d":26}],73:[function(require,module,exports){ +},{"es5-ext/object/primitive-set":40}],63:[function(require,module,exports){ 'use strict'; -var d = require('d') - , callable = require('es5-ext/object/valid-callable') +var setPrototypeOf = require('es5-ext/object/set-prototype-of') + , d = require('d') + , Iterator = require('es6-iterator') + , toStringTagSymbol = require('es6-symbol').toStringTag + , kinds = require('./iterator-kinds') - , apply = Function.prototype.apply, call = Function.prototype.call - , create = Object.create, defineProperty = Object.defineProperty , defineProperties = Object.defineProperties - , hasOwnProperty = Object.prototype.hasOwnProperty - , descriptor = { configurable: true, enumerable: false, writable: true } + , unBind = Iterator.prototype._unBind + , MapIterator; - , on, once, off, emit, methods, descriptors, base; - -on = function (type, listener) { - var data; - - callable(listener); - - if (!hasOwnProperty.call(this, '__ee__')) { - data = descriptor.value = create(null); - defineProperty(this, '__ee__', descriptor); - descriptor.value = null; - } else { - data = this.__ee__; - } - if (!data[type]) data[type] = listener; - else if (typeof data[type] === 'object') data[type].push(listener); - else data[type] = [data[type], listener]; - - return this; -}; - -once = function (type, listener) { - var once, self; - - callable(listener); - self = this; - on.call(this, type, once = function () { - off.call(self, type, once); - apply.call(listener, this, arguments); +MapIterator = module.exports = function (map, kind) { + if (!(this instanceof MapIterator)) return new MapIterator(map, kind); + Iterator.call(this, map.__mapKeysData__, map); + if (!kind || !kinds[kind]) kind = 'key+value'; + defineProperties(this, { + __kind__: d('', kind), + __values__: d('w', map.__mapValuesData__) }); - - once.__eeOnceListener__ = listener; - return this; }; +if (setPrototypeOf) setPrototypeOf(MapIterator, Iterator); -off = function (type, listener) { - var data, listeners, candidate, i; +MapIterator.prototype = Object.create(Iterator.prototype, { + constructor: d(MapIterator), + _resolve: d(function (i) { + if (this.__kind__ === 'value') return this.__values__[i]; + if (this.__kind__ === 'key') return this.__list__[i]; + return [this.__list__[i], this.__values__[i]]; + }), + _unBind: d(function () { + this.__values__ = null; + unBind.call(this); + }), + toString: d(function () { return '[object Map Iterator]'; }) +}); +Object.defineProperty(MapIterator.prototype, toStringTagSymbol, + d('c', 'Map Iterator')); - callable(listener); - - if (!hasOwnProperty.call(this, '__ee__')) return this; - data = this.__ee__; - if (!data[type]) return this; - listeners = data[type]; - - if (typeof listeners === 'object') { - for (i = 0; (candidate = listeners[i]); ++i) { - if ((candidate === listener) || - (candidate.__eeOnceListener__ === listener)) { - if (listeners.length === 2) data[type] = listeners[i ? 0 : 1]; - else listeners.splice(i, 1); - } - } - } else { - if ((listeners === listener) || - (listeners.__eeOnceListener__ === listener)) { - delete data[type]; - } - } - - return this; -}; - -emit = function (type) { - var i, l, listener, listeners, args; - - if (!hasOwnProperty.call(this, '__ee__')) return; - listeners = this.__ee__[type]; - if (!listeners) return; - - if (typeof listeners === 'object') { - l = arguments.length; - args = new Array(l - 1); - for (i = 1; i < l; ++i) args[i - 1] = arguments[i]; - - listeners = listeners.slice(); - for (i = 0; (listener = listeners[i]); ++i) { - apply.call(listener, this, args); - } - } else { - switch (arguments.length) { - case 1: - call.call(listeners, this); - break; - case 2: - call.call(listeners, this, arguments[1]); - break; - case 3: - call.call(listeners, this, arguments[1], arguments[2]); - break; - default: - l = arguments.length; - args = new Array(l - 1); - for (i = 1; i < l; ++i) { - args[i - 1] = arguments[i]; - } - apply.call(listeners, this, args); - } - } -}; - -methods = { - on: on, - once: once, - off: off, - emit: emit -}; - -descriptors = { - on: d(on), - once: d(once), - off: d(off), - emit: d(emit) -}; - -base = defineProperties({}, descriptors); - -module.exports = exports = function (o) { - return (o == null) ? create(base) : defineProperties(Object(o), descriptors); -}; -exports.methods = methods; - -},{"d":26,"es5-ext/object/valid-callable":52}],74:[function(require,module,exports){ +},{"./iterator-kinds":62,"d":7,"es5-ext/object/set-prototype-of":41,"es6-iterator":55,"es6-symbol":65}],64:[function(require,module,exports){ 'use strict'; var clear = require('es5-ext/array/#/clear') , eIndexOf = require('es5-ext/array/#/e-index-of') , setPrototypeOf = require('es5-ext/object/set-prototype-of') @@ -14502,32 +12528,36 @@ , iterator = require('es6-iterator/valid-iterable') , forOf = require('es6-iterator/for-of') , Iterator = require('./lib/iterator') , isNative = require('./is-native-implemented') - , call = Function.prototype.call, defineProperties = Object.defineProperties + , call = Function.prototype.call + , defineProperties = Object.defineProperties, getPrototypeOf = Object.getPrototypeOf , MapPoly; module.exports = MapPoly = function (/*iterable*/) { - var iterable = arguments[0], keys, values; - if (!(this instanceof MapPoly)) return new MapPoly(iterable); - if (this.__mapKeysData__ !== undefined) { - throw new TypeError(this + " cannot be reinitialized"); + var iterable = arguments[0], keys, values, self; + if (!(this instanceof MapPoly)) throw new TypeError('Constructor requires \'new\''); + if (isNative && setPrototypeOf && (Map !== MapPoly)) { + self = setPrototypeOf(new Map(), getPrototypeOf(this)); + } else { + self = this; } if (iterable != null) iterator(iterable); - defineProperties(this, { + defineProperties(self, { __mapKeysData__: d('c', keys = []), __mapValuesData__: d('c', values = []) }); - if (!iterable) return; + if (!iterable) return self; forOf(iterable, function (value) { var key = validValue(value)[0]; value = value[1]; if (eIndexOf.call(keys, key) !== -1) return; keys.push(key); values.push(value); - }, this); + }, self); + return self; }; if (isNative) { if (setPrototypeOf) setPrototypeOf(MapPoly, Map); MapPoly.prototype = Object.create(Map.prototype, { @@ -14588,190 +12618,223 @@ Object.defineProperty(MapPoly.prototype, Symbol.iterator, d(function () { return this.entries(); })); Object.defineProperty(MapPoly.prototype, Symbol.toStringTag, d('c', 'Map')); -},{"./is-native-implemented":22,"./lib/iterator":24,"d":26,"es5-ext/array/#/clear":27,"es5-ext/array/#/e-index-of":28,"es5-ext/object/set-prototype-of":49,"es5-ext/object/valid-callable":52,"es5-ext/object/valid-value":53,"es6-iterator/for-of":59,"es6-iterator/valid-iterable":69,"es6-symbol":70,"event-emitter":73}],75:[function(require,module,exports){ +},{"./is-native-implemented":61,"./lib/iterator":63,"d":7,"es5-ext/array/#/clear":18,"es5-ext/array/#/e-index-of":19,"es5-ext/object/set-prototype-of":41,"es5-ext/object/valid-callable":44,"es5-ext/object/valid-value":46,"es6-iterator/for-of":53,"es6-iterator/valid-iterable":58,"es6-symbol":65,"event-emitter":95}],65:[function(require,module,exports){ 'use strict'; -module.exports = require('./is-implemented')() ? - WeakMap : require('./polyfill'); +module.exports = require('./is-implemented')() ? Symbol : require('./polyfill'); -},{"./is-implemented":76,"./polyfill":120}],76:[function(require,module,exports){ +},{"./is-implemented":66,"./polyfill":68}],66:[function(require,module,exports){ 'use strict'; module.exports = function () { - var map; - if (typeof WeakMap !== 'function') return false; - map = new WeakMap(); - if (typeof map.set !== 'function') return false; - if (map.set({}, 1) !== map) return false; - if (typeof map.clear !== 'function') return false; - if (typeof map.delete !== 'function') return false; - if (typeof map.has !== 'function') return false; + var symbol; + if (typeof Symbol !== 'function') return false; + symbol = Symbol('test symbol'); + try { String(symbol); } catch (e) { return false; } + if (typeof Symbol.iterator === 'symbol') return true; + // Return 'true' for polyfills + if (typeof Symbol.isConcatSpreadable !== 'object') return false; + if (typeof Symbol.iterator !== 'object') return false; + if (typeof Symbol.toPrimitive !== 'object') return false; + if (typeof Symbol.toStringTag !== 'object') return false; + if (typeof Symbol.unscopables !== 'object') return false; + return true; }; -},{}],77:[function(require,module,exports){ -// Exports true if environment provides native `WeakMap` implementation, -// whatever that is. +},{}],67:[function(require,module,exports){ +'use strict'; +module.exports = function (x) { + return (x && ((typeof x === 'symbol') || (x['@@toStringTag'] === 'Symbol'))) || false; +}; + +},{}],68:[function(require,module,exports){ 'use strict'; -module.exports = (function () { - if (typeof WeakMap === 'undefined') return false; - return (Object.prototype.toString.call(WeakMap.prototype) === - '[object WeakMap]'); +var d = require('d') + , validateSymbol = require('./validate-symbol') + + , create = Object.create, defineProperties = Object.defineProperties + , defineProperty = Object.defineProperty, objPrototype = Object.prototype + , NativeSymbol, SymbolPolyfill, HiddenSymbol, globalSymbols = create(null); + +if (typeof Symbol === 'function') NativeSymbol = Symbol; + +var generateName = (function () { + var created = create(null); + return function (desc) { + var postfix = 0, name, ie11BugWorkaround; + while (created[desc + (postfix || '')]) ++postfix; + desc += (postfix || ''); + created[desc] = true; + name = '@@' + desc; + defineProperty(objPrototype, name, d.gs(null, function (value) { + // For IE11 issue see: + // https://connect.microsoft.com/IE/feedbackdetail/view/1928508/ + // ie11-broken-getters-on-dom-objects + // https://github.com/medikoo/es6-symbol/issues/12 + if (ie11BugWorkaround) return; + ie11BugWorkaround = true; + defineProperty(this, name, d(value)); + ie11BugWorkaround = false; + })); + return name; + }; }()); -},{}],78:[function(require,module,exports){ -arguments[4][25][0].apply(exports,arguments) -},{"dup":25,"es5-ext/object/copy":85,"es5-ext/object/map":93,"es5-ext/object/valid-callable":98,"es5-ext/object/valid-value":100}],79:[function(require,module,exports){ -arguments[4][26][0].apply(exports,arguments) -},{"dup":26,"es5-ext/object/assign":82,"es5-ext/object/is-callable":88,"es5-ext/object/normalize-options":94,"es5-ext/string/#/contains":101}],80:[function(require,module,exports){ -arguments[4][27][0].apply(exports,arguments) -},{"../../object/valid-value":100,"dup":27}],81:[function(require,module,exports){ -arguments[4][34][0].apply(exports,arguments) -},{"./is-callable":88,"./valid-callable":98,"./valid-value":100,"dup":34}],82:[function(require,module,exports){ -arguments[4][35][0].apply(exports,arguments) -},{"./is-implemented":83,"./shim":84,"dup":35}],83:[function(require,module,exports){ -arguments[4][36][0].apply(exports,arguments) -},{"dup":36}],84:[function(require,module,exports){ -arguments[4][37][0].apply(exports,arguments) -},{"../keys":90,"../valid-value":100,"dup":37}],85:[function(require,module,exports){ -arguments[4][38][0].apply(exports,arguments) -},{"./assign":82,"./valid-value":100,"dup":38}],86:[function(require,module,exports){ -arguments[4][39][0].apply(exports,arguments) -},{"./set-prototype-of/is-implemented":96,"./set-prototype-of/shim":97,"dup":39}],87:[function(require,module,exports){ -arguments[4][40][0].apply(exports,arguments) -},{"./_iterate":81,"dup":40}],88:[function(require,module,exports){ -arguments[4][41][0].apply(exports,arguments) -},{"dup":41}],89:[function(require,module,exports){ -arguments[4][42][0].apply(exports,arguments) -},{"dup":42}],90:[function(require,module,exports){ -arguments[4][43][0].apply(exports,arguments) -},{"./is-implemented":91,"./shim":92,"dup":43}],91:[function(require,module,exports){ -arguments[4][44][0].apply(exports,arguments) -},{"dup":44}],92:[function(require,module,exports){ -arguments[4][45][0].apply(exports,arguments) -},{"dup":45}],93:[function(require,module,exports){ -arguments[4][46][0].apply(exports,arguments) -},{"./for-each":87,"./valid-callable":98,"dup":46}],94:[function(require,module,exports){ -arguments[4][47][0].apply(exports,arguments) -},{"dup":47}],95:[function(require,module,exports){ -arguments[4][49][0].apply(exports,arguments) -},{"./is-implemented":96,"./shim":97,"dup":49}],96:[function(require,module,exports){ -arguments[4][50][0].apply(exports,arguments) -},{"dup":50}],97:[function(require,module,exports){ -arguments[4][51][0].apply(exports,arguments) -},{"../create":86,"../is-object":89,"../valid-value":100,"dup":51}],98:[function(require,module,exports){ -arguments[4][52][0].apply(exports,arguments) -},{"dup":52}],99:[function(require,module,exports){ +HiddenSymbol = function Symbol(description) { + if (this instanceof HiddenSymbol) throw new TypeError('TypeError: Symbol is not a constructor'); + return SymbolPolyfill(description); +}; +module.exports = SymbolPolyfill = function Symbol(description) { + var symbol; + if (this instanceof Symbol) throw new TypeError('TypeError: Symbol is not a constructor'); + symbol = create(HiddenSymbol.prototype); + description = (description === undefined ? '' : String(description)); + return defineProperties(symbol, { + __description__: d('', description), + __name__: d('', generateName(description)) + }); +}; +defineProperties(SymbolPolyfill, { + for: d(function (key) { + if (globalSymbols[key]) return globalSymbols[key]; + return (globalSymbols[key] = SymbolPolyfill(String(key))); + }), + keyFor: d(function (s) { + var key; + validateSymbol(s); + for (key in globalSymbols) if (globalSymbols[key] === s) return key; + }), + hasInstance: d('', (NativeSymbol && NativeSymbol.hasInstance) || SymbolPolyfill('hasInstance')), + isConcatSpreadable: d('', (NativeSymbol && NativeSymbol.isConcatSpreadable) || + SymbolPolyfill('isConcatSpreadable')), + iterator: d('', (NativeSymbol && NativeSymbol.iterator) || SymbolPolyfill('iterator')), + match: d('', (NativeSymbol && NativeSymbol.match) || SymbolPolyfill('match')), + replace: d('', (NativeSymbol && NativeSymbol.replace) || SymbolPolyfill('replace')), + search: d('', (NativeSymbol && NativeSymbol.search) || SymbolPolyfill('search')), + species: d('', (NativeSymbol && NativeSymbol.species) || SymbolPolyfill('species')), + split: d('', (NativeSymbol && NativeSymbol.split) || SymbolPolyfill('split')), + toPrimitive: d('', (NativeSymbol && NativeSymbol.toPrimitive) || SymbolPolyfill('toPrimitive')), + toStringTag: d('', (NativeSymbol && NativeSymbol.toStringTag) || SymbolPolyfill('toStringTag')), + unscopables: d('', (NativeSymbol && NativeSymbol.unscopables) || SymbolPolyfill('unscopables')) +}); +defineProperties(HiddenSymbol.prototype, { + constructor: d(SymbolPolyfill), + toString: d('', function () { return this.__name__; }) +}); + +defineProperties(SymbolPolyfill.prototype, { + toString: d(function () { return 'Symbol (' + validateSymbol(this).__description__ + ')'; }), + valueOf: d(function () { return validateSymbol(this); }) +}); +defineProperty(SymbolPolyfill.prototype, SymbolPolyfill.toPrimitive, d('', + function () { return validateSymbol(this); })); +defineProperty(SymbolPolyfill.prototype, SymbolPolyfill.toStringTag, d('c', 'Symbol')); + +defineProperty(HiddenSymbol.prototype, SymbolPolyfill.toPrimitive, + d('c', SymbolPolyfill.prototype[SymbolPolyfill.toPrimitive])); +defineProperty(HiddenSymbol.prototype, SymbolPolyfill.toStringTag, + d('c', SymbolPolyfill.prototype[SymbolPolyfill.toStringTag])); + +},{"./validate-symbol":69,"d":7}],69:[function(require,module,exports){ 'use strict'; -var isObject = require('./is-object'); +var isSymbol = require('./is-symbol'); module.exports = function (value) { - if (!isObject(value)) throw new TypeError(value + " is not an Object"); + if (!isSymbol(value)) throw new TypeError(value + " is not a symbol"); return value; }; -},{"./is-object":89}],100:[function(require,module,exports){ -arguments[4][53][0].apply(exports,arguments) -},{"dup":53}],101:[function(require,module,exports){ -arguments[4][54][0].apply(exports,arguments) -},{"./is-implemented":102,"./shim":103,"dup":54}],102:[function(require,module,exports){ -arguments[4][55][0].apply(exports,arguments) -},{"dup":55}],103:[function(require,module,exports){ -arguments[4][56][0].apply(exports,arguments) -},{"dup":56}],104:[function(require,module,exports){ -arguments[4][57][0].apply(exports,arguments) -},{"dup":57}],105:[function(require,module,exports){ -arguments[4][58][0].apply(exports,arguments) -},{"./":108,"d":79,"dup":58,"es5-ext/object/set-prototype-of":95,"es5-ext/string/#/contains":101}],106:[function(require,module,exports){ -arguments[4][59][0].apply(exports,arguments) -},{"./get":107,"dup":59,"es5-ext/object/valid-callable":98,"es5-ext/string/is-string":104}],107:[function(require,module,exports){ -arguments[4][60][0].apply(exports,arguments) -},{"./array":105,"./string":115,"./valid-iterable":116,"dup":60,"es5-ext/string/is-string":104,"es6-symbol":110}],108:[function(require,module,exports){ -arguments[4][61][0].apply(exports,arguments) -},{"d":79,"d/auto-bind":78,"dup":61,"es5-ext/array/#/clear":80,"es5-ext/object/assign":82,"es5-ext/object/valid-callable":98,"es5-ext/object/valid-value":100,"es6-symbol":110}],109:[function(require,module,exports){ -arguments[4][62][0].apply(exports,arguments) -},{"dup":62,"es5-ext/string/is-string":104,"es6-symbol":110}],110:[function(require,module,exports){ -arguments[4][63][0].apply(exports,arguments) -},{"./is-implemented":111,"./polyfill":113,"dup":63}],111:[function(require,module,exports){ -arguments[4][64][0].apply(exports,arguments) -},{"dup":64}],112:[function(require,module,exports){ -arguments[4][65][0].apply(exports,arguments) -},{"dup":65}],113:[function(require,module,exports){ -arguments[4][66][0].apply(exports,arguments) -},{"./validate-symbol":114,"d":79,"dup":66}],114:[function(require,module,exports){ -arguments[4][67][0].apply(exports,arguments) -},{"./is-symbol":112,"dup":67}],115:[function(require,module,exports){ -arguments[4][68][0].apply(exports,arguments) -},{"./":108,"d":79,"dup":68,"es5-ext/object/set-prototype-of":95}],116:[function(require,module,exports){ -arguments[4][69][0].apply(exports,arguments) -},{"./is-iterable":109,"dup":69}],117:[function(require,module,exports){ -arguments[4][63][0].apply(exports,arguments) -},{"./is-implemented":118,"./polyfill":119,"dup":63}],118:[function(require,module,exports){ -arguments[4][71][0].apply(exports,arguments) -},{"dup":71}],119:[function(require,module,exports){ -arguments[4][72][0].apply(exports,arguments) -},{"d":79,"dup":72}],120:[function(require,module,exports){ +},{"./is-symbol":67}],70:[function(require,module,exports){ 'use strict'; +module.exports = require('./is-implemented')() ? WeakMap : require('./polyfill'); + +},{"./is-implemented":71,"./polyfill":73}],71:[function(require,module,exports){ +'use strict'; + +module.exports = function () { + var weakMap, x; + if (typeof WeakMap !== 'function') return false; + try { + // WebKit doesn't support arguments and crashes + weakMap = new WeakMap([[x = {}, 'one'], [{}, 'two'], [{}, 'three']]); + } catch (e) { + return false; + } + if (String(weakMap) !== '[object WeakMap]') return false; + if (typeof weakMap.set !== 'function') return false; + if (weakMap.set({}, 1) !== weakMap) return false; + if (typeof weakMap.delete !== 'function') return false; + if (typeof weakMap.has !== 'function') return false; + if (weakMap.get(x) !== 'one') return false; + + return true; +}; + +},{}],72:[function(require,module,exports){ +// Exports true if environment provides native `WeakMap` implementation, whatever that is. + +'use strict'; + +module.exports = (function () { + if (typeof WeakMap !== 'function') return false; + return (Object.prototype.toString.call(new WeakMap()) === '[object WeakMap]'); +}()); + +},{}],73:[function(require,module,exports){ +'use strict'; + var setPrototypeOf = require('es5-ext/object/set-prototype-of') , object = require('es5-ext/object/valid-object') , value = require('es5-ext/object/valid-value') + , randomUniq = require('es5-ext/string/random-uniq') , d = require('d') , getIterator = require('es6-iterator/get') , forOf = require('es6-iterator/for-of') , toStringTagSymbol = require('es6-symbol').toStringTag , isNative = require('./is-native-implemented') - , isArray = Array.isArray, defineProperty = Object.defineProperty, random = Math.random - , hasOwnProperty = Object.prototype.hasOwnProperty - , genId, WeakMapPoly; + , isArray = Array.isArray, defineProperty = Object.defineProperty + , hasOwnProperty = Object.prototype.hasOwnProperty, getPrototypeOf = Object.getPrototypeOf + , WeakMapPoly; -genId = (function () { - var generated = Object.create(null); - return function () { - var id; - do { id = random().toString(36).slice(2); } while (generated[id]); - generated[id] = true; - return id; - }; -}()); - module.exports = WeakMapPoly = function (/*iterable*/) { - var iterable = arguments[0]; - if (!(this instanceof WeakMapPoly)) return new WeakMapPoly(iterable); - if (this.__weakMapData__ !== undefined) { - throw new TypeError(this + " cannot be reinitialized"); + var iterable = arguments[0], self; + if (!(this instanceof WeakMapPoly)) throw new TypeError('Constructor requires \'new\''); + if (isNative && setPrototypeOf && (WeakMap !== WeakMapPoly)) { + self = setPrototypeOf(new WeakMap(), getPrototypeOf(this)); + } else { + self = this; } if (iterable != null) { if (!isArray(iterable)) iterable = getIterator(iterable); } - defineProperty(this, '__weakMapData__', d('c', '$weakMap$' + genId())); - if (!iterable) return; + defineProperty(self, '__weakMapData__', d('c', '$weakMap$' + randomUniq())); + if (!iterable) return self; forOf(iterable, function (val) { value(val); - this.set(val[0], val[1]); - }, this); + self.set(val[0], val[1]); + }); + return self; }; if (isNative) { if (setPrototypeOf) setPrototypeOf(WeakMapPoly, WeakMap); WeakMapPoly.prototype = Object.create(WeakMap.prototype, { constructor: d(WeakMapPoly) }); } Object.defineProperties(WeakMapPoly.prototype, { - clear: d(function () { - defineProperty(this, '__weakMapData__', d('c', '$weakMap$' + genId())); - }), delete: d(function (key) { if (hasOwnProperty.call(object(key), this.__weakMapData__)) { delete key[this.__weakMapData__]; return true; } @@ -14791,12 +12854,2513 @@ }), toString: d(function () { return '[object WeakMap]'; }) }); defineProperty(WeakMapPoly.prototype, toStringTagSymbol, d('c', 'WeakMap')); -},{"./is-native-implemented":77,"d":79,"es5-ext/object/set-prototype-of":95,"es5-ext/object/valid-object":99,"es5-ext/object/valid-value":100,"es6-iterator/for-of":106,"es6-iterator/get":107,"es6-symbol":117}],121:[function(require,module,exports){ +},{"./is-native-implemented":72,"d":7,"es5-ext/object/set-prototype-of":41,"es5-ext/object/valid-object":45,"es5-ext/object/valid-value":46,"es5-ext/string/random-uniq":51,"es6-iterator/for-of":53,"es6-iterator/get":54,"es6-symbol":65}],74:[function(require,module,exports){ +'use strict'; + +var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; + +module.exports = function (str) { + if (typeof str !== 'string') { + throw new TypeError('Expected a string'); + } + + return str.replace(matchOperatorsRe, '\\$&'); +}; + +},{}],75:[function(require,module,exports){ +"use strict"; + +var _interopRequire = function (obj) { return obj && obj.__esModule ? obj["default"] : obj; }; + +var _get = function get(object, property, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc && desc.writable) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + +Object.defineProperty(exports, "__esModule", { + value: true +}); /* + Copyright (C) 2015 Yusuke Suzuki <utatane.tea@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. +*/ + +var Variable = _interopRequire(require("./variable")); + +/** + * @class Definition + */ + +var Definition = function Definition(type, name, node, parent, index, kind) { + _classCallCheck(this, Definition); + + /** + * @member {String} Definition#type - type of the occurrence (e.g. "Parameter", "Variable", ...). + */ + this.type = type; + /** + * @member {esprima.Identifier} Definition#name - the identifier AST node of the occurrence. + */ + this.name = name; + /** + * @member {esprima.Node} Definition#node - the enclosing node of the identifier. + */ + this.node = node; + /** + * @member {esprima.Node?} Definition#parent - the enclosing statement node of the identifier. + */ + this.parent = parent; + /** + * @member {Number?} Definition#index - the index in the declaration statement. + */ + this.index = index; + /** + * @member {String?} Definition#kind - the kind of the declaration statement. + */ + this.kind = kind; +}; + +exports["default"] = Definition; + +/** + * @class ParameterDefinition + */ + +var ParameterDefinition = (function (_Definition) { + function ParameterDefinition(name, node, index, rest) { + _classCallCheck(this, ParameterDefinition); + + _get(Object.getPrototypeOf(ParameterDefinition.prototype), "constructor", this).call(this, Variable.Parameter, name, node, null, index, null); + /** + * Whether the parameter definition is a part of a rest parameter. + * @member {boolean} ParameterDefinition#rest + */ + this.rest = rest; + } + + _inherits(ParameterDefinition, _Definition); + + return ParameterDefinition; +})(Definition); + +exports.ParameterDefinition = ParameterDefinition; + +/* vim: set sw=4 ts=4 et tw=80 : */ +exports.Definition = Definition; + + +},{"./variable":82}],76:[function(require,module,exports){ +"use strict"; + +var _interopRequire = function (obj) { return obj && obj.__esModule ? obj["default"] : obj; }; + +/** + * Main interface function. Takes an Esprima syntax tree and returns the + * analyzed scopes. + * @function analyze + * @param {esprima.Tree} tree + * @param {Object} providedOptions - Options that tailor the scope analysis + * @param {boolean} [providedOptions.optimistic=false] - the optimistic flag + * @param {boolean} [providedOptions.directive=false]- the directive flag + * @param {boolean} [providedOptions.ignoreEval=false]- whether to check 'eval()' calls + * @param {boolean} [providedOptions.nodejsScope=false]- whether the whole + * script is executed under node.js environment. When enabled, escope adds + * a function scope immediately following the global scope. + * @param {string} [providedOptions.sourceType='script']- the source type of the script. one of 'script' and 'module' + * @param {number} [providedOptions.ecmaVersion=5]- which ECMAScript version is considered + * @return {ScopeManager} + */ +exports.analyze = analyze; +Object.defineProperty(exports, "__esModule", { + value: true +}); +/* + Copyright (C) 2012-2014 Yusuke Suzuki <utatane.tea@gmail.com> + Copyright (C) 2013 Alex Seville <hi@alexanderseville.com> + Copyright (C) 2014 Thiago de Arruda <tpadilha84@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. +*/ + +/** + * Escope (<a href="http://github.com/estools/escope">escope</a>) is an <a + * href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript</a> + * scope analyzer extracted from the <a + * href="http://github.com/estools/esmangle">esmangle project</a/>. + * <p> + * <em>escope</em> finds lexical scopes in a source program, i.e. areas of that + * program where different occurrences of the same identifier refer to the same + * variable. With each scope the contained variables are collected, and each + * identifier reference in code is linked to its corresponding variable (if + * possible). + * <p> + * <em>escope</em> works on a syntax tree of the parsed source code which has + * to adhere to the <a + * href="https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API"> + * Mozilla Parser API</a>. E.g. <a href="http://esprima.org">esprima</a> is a parser + * that produces such syntax trees. + * <p> + * The main interface is the {@link analyze} function. + * @module escope + */ + +/*jslint bitwise:true */ + +var assert = _interopRequire(require("assert")); + +var ScopeManager = _interopRequire(require("./scope-manager")); + +var Referencer = _interopRequire(require("./referencer")); + +var Reference = _interopRequire(require("./reference")); + +var Variable = _interopRequire(require("./variable")); + +var Scope = _interopRequire(require("./scope")); + +var version = require("../package.json").version; + +function defaultOptions() { + return { + optimistic: false, + directive: false, + nodejsScope: false, + sourceType: "script", // one of ['script', 'module'] + ecmaVersion: 5 + }; +} + +function updateDeeply(target, override) { + var key, val; + + function isHashObject(target) { + return typeof target === "object" && target instanceof Object && !(target instanceof RegExp); + } + + for (key in override) { + if (override.hasOwnProperty(key)) { + val = override[key]; + if (isHashObject(val)) { + if (isHashObject(target[key])) { + updateDeeply(target[key], val); + } else { + target[key] = updateDeeply({}, val); + } + } else { + target[key] = val; + } + } + } + return target; +} +function analyze(tree, providedOptions) { + var scopeManager, referencer, options; + + options = updateDeeply(defaultOptions(), providedOptions); + + scopeManager = new ScopeManager(options); + + referencer = new Referencer(scopeManager); + referencer.visit(tree); + + assert(scopeManager.__currentScope === null, "currentScope should be null."); + + return scopeManager; +} + +exports.version = version; + +/* vim: set sw=4 ts=4 et tw=80 : */ +exports.Reference = Reference; +exports.Variable = Variable; +exports.Scope = Scope; +exports.ScopeManager = ScopeManager; + +/** @name module:escope.version */ + +/** @name module:escope.Reference */ + +/** @name module:escope.Variable */ + +/** @name module:escope.Scope */ + +/** @name module:escope.ScopeManager */ + + +},{"../package.json":83,"./reference":78,"./referencer":79,"./scope":81,"./scope-manager":80,"./variable":82,"assert":5}],77:[function(require,module,exports){ +"use strict"; + +var _interopRequire = function (obj) { return obj && obj.__esModule ? obj["default"] : obj; }; + +var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +var _get = function get(object, property, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc && desc.writable) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + +/* + Copyright (C) 2015 Yusuke Suzuki <utatane.tea@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. +*/ + +var Syntax = require("estraverse").Syntax; + +var esrecurse = _interopRequire(require("esrecurse")); + +function getLast(xs) { + return xs[xs.length - 1] || null; +} + +var PatternVisitor = (function (_esrecurse$Visitor) { + function PatternVisitor(rootPattern, callback) { + _classCallCheck(this, PatternVisitor); + + _get(Object.getPrototypeOf(PatternVisitor.prototype), "constructor", this).call(this); + this.rootPattern = rootPattern; + this.callback = callback; + this.assignments = []; + this.rightHandNodes = []; + this.restElements = []; + } + + _inherits(PatternVisitor, _esrecurse$Visitor); + + _createClass(PatternVisitor, { + Identifier: { + value: function Identifier(pattern) { + var lastRestElement = getLast(this.restElements); + this.callback(pattern, { + topLevel: pattern === this.rootPattern, + rest: lastRestElement != null && lastRestElement.argument === pattern, + assignments: this.assignments + }); + } + }, + Property: { + value: function Property(property) { + // Computed property's key is a right hand node. + if (property.computed) { + this.rightHandNodes.push(property.key); + } + + // If it's shorthand, its key is same as its value. + // If it's shorthand and has its default value, its key is same as its value.left (the value is AssignmentPattern). + // If it's not shorthand, the name of new variable is its value's. + this.visit(property.value); + } + }, + ArrayPattern: { + value: function ArrayPattern(pattern) { + var i, iz, element; + for (i = 0, iz = pattern.elements.length; i < iz; ++i) { + element = pattern.elements[i]; + this.visit(element); + } + } + }, + AssignmentPattern: { + value: function AssignmentPattern(pattern) { + this.assignments.push(pattern); + this.visit(pattern.left); + this.rightHandNodes.push(pattern.right); + this.assignments.pop(); + } + }, + RestElement: { + value: function RestElement(pattern) { + this.restElements.push(pattern); + this.visit(pattern.argument); + this.restElements.pop(); + } + }, + MemberExpression: { + value: function MemberExpression(node) { + // Computed property's key is a right hand node. + if (node.computed) { + this.rightHandNodes.push(node.property); + } + // the object is only read, write to its property. + this.rightHandNodes.push(node.object); + } + }, + SpreadElement: { + + // + // ForInStatement.left and AssignmentExpression.left are LeftHandSideExpression. + // By spec, LeftHandSideExpression is Pattern or MemberExpression. + // (see also: https://github.com/estree/estree/pull/20#issuecomment-74584758) + // But espree 2.0 and esprima 2.0 parse to ArrayExpression, ObjectExpression, etc... + // + + value: function SpreadElement(node) { + this.visit(node.argument); + } + }, + ArrayExpression: { + value: function ArrayExpression(node) { + node.elements.forEach(this.visit, this); + } + }, + AssignmentExpression: { + value: function AssignmentExpression(node) { + this.assignments.push(node); + this.visit(node.left); + this.rightHandNodes.push(node.right); + this.assignments.pop(); + } + }, + CallExpression: { + value: function CallExpression(node) { + var _this = this; + + // arguments are right hand nodes. + node.arguments.forEach(function (a) { + _this.rightHandNodes.push(a); + }); + this.visit(node.callee); + } + } + }, { + isPattern: { + value: function isPattern(node) { + var nodeType = node.type; + return nodeType === Syntax.Identifier || nodeType === Syntax.ObjectPattern || nodeType === Syntax.ArrayPattern || nodeType === Syntax.SpreadElement || nodeType === Syntax.RestElement || nodeType === Syntax.AssignmentPattern; + } + } + }); + + return PatternVisitor; +})(esrecurse.Visitor); + +module.exports = PatternVisitor; + +/* vim: set sw=4 ts=4 et tw=80 : */ + + +},{"esrecurse":84,"estraverse":89}],78:[function(require,module,exports){ +"use strict"; + +var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + +/* + Copyright (C) 2015 Yusuke Suzuki <utatane.tea@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. +*/ + +var READ = 1; +var WRITE = 2; +var RW = READ | WRITE; + +/** + * A Reference represents a single occurrence of an identifier in code. + * @class Reference + */ + +var Reference = (function () { + function Reference(ident, scope, flag, writeExpr, maybeImplicitGlobal, partial, init) { + _classCallCheck(this, Reference); + + /** + * Identifier syntax node. + * @member {esprima#Identifier} Reference#identifier + */ + this.identifier = ident; + /** + * Reference to the enclosing Scope. + * @member {Scope} Reference#from + */ + this.from = scope; + /** + * Whether the reference comes from a dynamic scope (such as 'eval', + * 'with', etc.), and may be trapped by dynamic scopes. + * @member {boolean} Reference#tainted + */ + this.tainted = false; + /** + * The variable this reference is resolved with. + * @member {Variable} Reference#resolved + */ + this.resolved = null; + /** + * The read-write mode of the reference. (Value is one of {@link + * Reference.READ}, {@link Reference.RW}, {@link Reference.WRITE}). + * @member {number} Reference#flag + * @private + */ + this.flag = flag; + if (this.isWrite()) { + /** + * If reference is writeable, this is the tree being written to it. + * @member {esprima#Node} Reference#writeExpr + */ + this.writeExpr = writeExpr; + /** + * Whether the Reference might refer to a partial value of writeExpr. + * @member {boolean} Reference#partial + */ + this.partial = partial; + /** + * Whether the Reference is to write of initialization. + * @member {boolean} Reference#init + */ + this.init = init; + } + this.__maybeImplicitGlobal = maybeImplicitGlobal; + } + + _createClass(Reference, { + isStatic: { + + /** + * Whether the reference is static. + * @method Reference#isStatic + * @return {boolean} + */ + + value: function isStatic() { + return !this.tainted && this.resolved && this.resolved.scope.isStatic(); + } + }, + isWrite: { + + /** + * Whether the reference is writeable. + * @method Reference#isWrite + * @return {boolean} + */ + + value: function isWrite() { + return !!(this.flag & Reference.WRITE); + } + }, + isRead: { + + /** + * Whether the reference is readable. + * @method Reference#isRead + * @return {boolean} + */ + + value: function isRead() { + return !!(this.flag & Reference.READ); + } + }, + isReadOnly: { + + /** + * Whether the reference is read-only. + * @method Reference#isReadOnly + * @return {boolean} + */ + + value: function isReadOnly() { + return this.flag === Reference.READ; + } + }, + isWriteOnly: { + + /** + * Whether the reference is write-only. + * @method Reference#isWriteOnly + * @return {boolean} + */ + + value: function isWriteOnly() { + return this.flag === Reference.WRITE; + } + }, + isReadWrite: { + + /** + * Whether the reference is read-write. + * @method Reference#isReadWrite + * @return {boolean} + */ + + value: function isReadWrite() { + return this.flag === Reference.RW; + } + } + }); + + return Reference; +})(); + +module.exports = Reference; + +/** + * @constant Reference.READ + * @private + */ +Reference.READ = READ; +/** + * @constant Reference.WRITE + * @private + */ +Reference.WRITE = WRITE; +/** + * @constant Reference.RW + * @private + */ +Reference.RW = RW; + +/* vim: set sw=4 ts=4 et tw=80 : */ + + +},{}],79:[function(require,module,exports){ +"use strict"; + +var _interopRequire = function (obj) { return obj && obj.__esModule ? obj["default"] : obj; }; + +var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +var _get = function get(object, property, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc && desc.writable) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + +/* + Copyright (C) 2015 Yusuke Suzuki <utatane.tea@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. +*/ + +var Syntax = require("estraverse").Syntax; + +var esrecurse = _interopRequire(require("esrecurse")); + +var Reference = _interopRequire(require("./reference")); + +var Variable = _interopRequire(require("./variable")); + +var PatternVisitor = _interopRequire(require("./pattern-visitor")); + +var _definition = require("./definition"); + +var ParameterDefinition = _definition.ParameterDefinition; +var Definition = _definition.Definition; + +var assert = _interopRequire(require("assert")); + +function traverseIdentifierInPattern(rootPattern, referencer, callback) { + // Call the callback at left hand identifier nodes, and Collect right hand nodes. + var visitor = new PatternVisitor(rootPattern, callback); + visitor.visit(rootPattern); + + // Process the right hand nodes recursively. + if (referencer != null) { + visitor.rightHandNodes.forEach(referencer.visit, referencer); + } +} + +// Importing ImportDeclaration. +// http://people.mozilla.org/~jorendorff/es6-draft.html#sec-moduledeclarationinstantiation +// https://github.com/estree/estree/blob/master/es6.md#importdeclaration +// FIXME: Now, we don't create module environment, because the context is +// implementation dependent. + +var Importer = (function (_esrecurse$Visitor) { + function Importer(declaration, referencer) { + _classCallCheck(this, Importer); + + _get(Object.getPrototypeOf(Importer.prototype), "constructor", this).call(this); + this.declaration = declaration; + this.referencer = referencer; + } + + _inherits(Importer, _esrecurse$Visitor); + + _createClass(Importer, { + visitImport: { + value: function visitImport(id, specifier) { + var _this = this; + + this.referencer.visitPattern(id, function (pattern) { + _this.referencer.currentScope().__define(pattern, new Definition(Variable.ImportBinding, pattern, specifier, _this.declaration, null, null)); + }); + } + }, + ImportNamespaceSpecifier: { + value: function ImportNamespaceSpecifier(node) { + var local = node.local || node.id; + if (local) { + this.visitImport(local, node); + } + } + }, + ImportDefaultSpecifier: { + value: function ImportDefaultSpecifier(node) { + var local = node.local || node.id; + this.visitImport(local, node); + } + }, + ImportSpecifier: { + value: function ImportSpecifier(node) { + var local = node.local || node.id; + if (node.name) { + this.visitImport(node.name, node); + } else { + this.visitImport(local, node); + } + } + } + }); + + return Importer; +})(esrecurse.Visitor); + +// Referencing variables and creating bindings. + +var Referencer = (function (_esrecurse$Visitor2) { + function Referencer(scopeManager) { + _classCallCheck(this, Referencer); + + _get(Object.getPrototypeOf(Referencer.prototype), "constructor", this).call(this); + this.scopeManager = scopeManager; + this.parent = null; + this.isInnerMethodDefinition = false; + } + + _inherits(Referencer, _esrecurse$Visitor2); + + _createClass(Referencer, { + currentScope: { + value: function currentScope() { + return this.scopeManager.__currentScope; + } + }, + close: { + value: function close(node) { + while (this.currentScope() && node === this.currentScope().block) { + this.scopeManager.__currentScope = this.currentScope().__close(this.scopeManager); + } + } + }, + pushInnerMethodDefinition: { + value: function pushInnerMethodDefinition(isInnerMethodDefinition) { + var previous = this.isInnerMethodDefinition; + this.isInnerMethodDefinition = isInnerMethodDefinition; + return previous; + } + }, + popInnerMethodDefinition: { + value: function popInnerMethodDefinition(isInnerMethodDefinition) { + this.isInnerMethodDefinition = isInnerMethodDefinition; + } + }, + materializeTDZScope: { + value: function materializeTDZScope(node, iterationNode) { + // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-runtime-semantics-forin-div-ofexpressionevaluation-abstract-operation + // TDZ scope hides the declaration's names. + this.scopeManager.__nestTDZScope(node, iterationNode); + this.visitVariableDeclaration(this.currentScope(), Variable.TDZ, iterationNode.left, 0, true); + } + }, + materializeIterationScope: { + value: function materializeIterationScope(node) { + var _this = this; + + // Generate iteration scope for upper ForIn/ForOf Statements. + var letOrConstDecl; + this.scopeManager.__nestForScope(node); + letOrConstDecl = node.left; + this.visitVariableDeclaration(this.currentScope(), Variable.Variable, letOrConstDecl, 0); + this.visitPattern(letOrConstDecl.declarations[0].id, function (pattern) { + _this.currentScope().__referencing(pattern, Reference.WRITE, node.right, null, true, true); + }); + } + }, + referencingDefaultValue: { + value: function referencingDefaultValue(pattern, assignments, maybeImplicitGlobal, init) { + var scope = this.currentScope(); + assignments.forEach(function (assignment) { + scope.__referencing(pattern, Reference.WRITE, assignment.right, maybeImplicitGlobal, pattern !== assignment.left, init); + }); + } + }, + visitPattern: { + value: function visitPattern(node, options, callback) { + if (typeof options === "function") { + callback = options; + options = { processRightHandNodes: false }; + } + traverseIdentifierInPattern(node, options.processRightHandNodes ? this : null, callback); + } + }, + visitFunction: { + value: function visitFunction(node) { + var _this = this; + + var i, iz; + // FunctionDeclaration name is defined in upper scope + // NOTE: Not referring variableScope. It is intended. + // Since + // in ES5, FunctionDeclaration should be in FunctionBody. + // in ES6, FunctionDeclaration should be block scoped. + if (node.type === Syntax.FunctionDeclaration) { + // id is defined in upper scope + this.currentScope().__define(node.id, new Definition(Variable.FunctionName, node.id, node, null, null, null)); + } + + // FunctionExpression with name creates its special scope; + // FunctionExpressionNameScope. + if (node.type === Syntax.FunctionExpression && node.id) { + this.scopeManager.__nestFunctionExpressionNameScope(node); + } + + // Consider this function is in the MethodDefinition. + this.scopeManager.__nestFunctionScope(node, this.isInnerMethodDefinition); + + // Process parameter declarations. + for (i = 0, iz = node.params.length; i < iz; ++i) { + this.visitPattern(node.params[i], { processRightHandNodes: true }, function (pattern, info) { + _this.currentScope().__define(pattern, new ParameterDefinition(pattern, node, i, info.rest)); + + _this.referencingDefaultValue(pattern, info.assignments, null, true); + }); + } + + // if there's a rest argument, add that + if (node.rest) { + this.visitPattern({ + type: "RestElement", + argument: node.rest + }, function (pattern) { + _this.currentScope().__define(pattern, new ParameterDefinition(pattern, node, node.params.length, true)); + }); + } + + // Skip BlockStatement to prevent creating BlockStatement scope. + if (node.body.type === Syntax.BlockStatement) { + this.visitChildren(node.body); + } else { + this.visit(node.body); + } + + this.close(node); + } + }, + visitClass: { + value: function visitClass(node) { + if (node.type === Syntax.ClassDeclaration) { + this.currentScope().__define(node.id, new Definition(Variable.ClassName, node.id, node, null, null, null)); + } + + // FIXME: Maybe consider TDZ. + this.visit(node.superClass); + + this.scopeManager.__nestClassScope(node); + + if (node.id) { + this.currentScope().__define(node.id, new Definition(Variable.ClassName, node.id, node)); + } + this.visit(node.body); + + this.close(node); + } + }, + visitProperty: { + value: function visitProperty(node) { + var previous, isMethodDefinition; + if (node.computed) { + this.visit(node.key); + } + + isMethodDefinition = node.type === Syntax.MethodDefinition; + if (isMethodDefinition) { + previous = this.pushInnerMethodDefinition(true); + } + this.visit(node.value); + if (isMethodDefinition) { + this.popInnerMethodDefinition(previous); + } + } + }, + visitForIn: { + value: function visitForIn(node) { + var _this = this; + + if (node.left.type === Syntax.VariableDeclaration && node.left.kind !== "var") { + this.materializeTDZScope(node.right, node); + this.visit(node.right); + this.close(node.right); + + this.materializeIterationScope(node); + this.visit(node.body); + this.close(node); + } else { + if (node.left.type === Syntax.VariableDeclaration) { + this.visit(node.left); + this.visitPattern(node.left.declarations[0].id, function (pattern) { + _this.currentScope().__referencing(pattern, Reference.WRITE, node.right, null, true, true); + }); + } else { + this.visitPattern(node.left, { processRightHandNodes: true }, function (pattern, info) { + var maybeImplicitGlobal = null; + if (!_this.currentScope().isStrict) { + maybeImplicitGlobal = { + pattern: pattern, + node: node + }; + } + _this.referencingDefaultValue(pattern, info.assignments, maybeImplicitGlobal, false); + _this.currentScope().__referencing(pattern, Reference.WRITE, node.right, maybeImplicitGlobal, true, false); + }); + } + this.visit(node.right); + this.visit(node.body); + } + } + }, + visitVariableDeclaration: { + value: function visitVariableDeclaration(variableTargetScope, type, node, index, fromTDZ) { + var _this = this; + + // If this was called to initialize a TDZ scope, this needs to make definitions, but doesn't make references. + var decl, init; + + decl = node.declarations[index]; + init = decl.init; + this.visitPattern(decl.id, { processRightHandNodes: !fromTDZ }, function (pattern, info) { + variableTargetScope.__define(pattern, new Definition(type, pattern, decl, node, index, node.kind)); + + if (!fromTDZ) { + _this.referencingDefaultValue(pattern, info.assignments, null, true); + } + if (init) { + _this.currentScope().__referencing(pattern, Reference.WRITE, init, null, !info.topLevel, true); + } + }); + } + }, + AssignmentExpression: { + value: function AssignmentExpression(node) { + var _this = this; + + if (PatternVisitor.isPattern(node.left)) { + if (node.operator === "=") { + this.visitPattern(node.left, { processRightHandNodes: true }, function (pattern, info) { + var maybeImplicitGlobal = null; + if (!_this.currentScope().isStrict) { + maybeImplicitGlobal = { + pattern: pattern, + node: node + }; + } + _this.referencingDefaultValue(pattern, info.assignments, maybeImplicitGlobal, false); + _this.currentScope().__referencing(pattern, Reference.WRITE, node.right, maybeImplicitGlobal, !info.topLevel, false); + }); + } else { + this.currentScope().__referencing(node.left, Reference.RW, node.right); + } + } else { + this.visit(node.left); + } + this.visit(node.right); + } + }, + CatchClause: { + value: function CatchClause(node) { + var _this = this; + + this.scopeManager.__nestCatchScope(node); + + this.visitPattern(node.param, { processRightHandNodes: true }, function (pattern, info) { + _this.currentScope().__define(pattern, new Definition(Variable.CatchClause, node.param, node, null, null, null)); + _this.referencingDefaultValue(pattern, info.assignments, null, true); + }); + this.visit(node.body); + + this.close(node); + } + }, + Program: { + value: function Program(node) { + this.scopeManager.__nestGlobalScope(node); + + if (this.scopeManager.__isNodejsScope()) { + // Force strictness of GlobalScope to false when using node.js scope. + this.currentScope().isStrict = false; + this.scopeManager.__nestFunctionScope(node, false); + } + + if (this.scopeManager.__isES6() && this.scopeManager.isModule()) { + this.scopeManager.__nestModuleScope(node); + } + + this.visitChildren(node); + this.close(node); + } + }, + Identifier: { + value: function Identifier(node) { + this.currentScope().__referencing(node); + } + }, + UpdateExpression: { + value: function UpdateExpression(node) { + if (PatternVisitor.isPattern(node.argument)) { + this.currentScope().__referencing(node.argument, Reference.RW, null); + } else { + this.visitChildren(node); + } + } + }, + MemberExpression: { + value: function MemberExpression(node) { + this.visit(node.object); + if (node.computed) { + this.visit(node.property); + } + } + }, + Property: { + value: function Property(node) { + this.visitProperty(node); + } + }, + MethodDefinition: { + value: function MethodDefinition(node) { + this.visitProperty(node); + } + }, + BreakStatement: { + value: function BreakStatement() {} + }, + ContinueStatement: { + value: function ContinueStatement() {} + }, + LabeledStatement: { + value: function LabeledStatement(node) { + this.visit(node.body); + } + }, + ForStatement: { + value: function ForStatement(node) { + // Create ForStatement declaration. + // NOTE: In ES6, ForStatement dynamically generates + // per iteration environment. However, escope is + // a static analyzer, we only generate one scope for ForStatement. + if (node.init && node.init.type === Syntax.VariableDeclaration && node.init.kind !== "var") { + this.scopeManager.__nestForScope(node); + } + + this.visitChildren(node); + + this.close(node); + } + }, + ClassExpression: { + value: function ClassExpression(node) { + this.visitClass(node); + } + }, + ClassDeclaration: { + value: function ClassDeclaration(node) { + this.visitClass(node); + } + }, + CallExpression: { + value: function CallExpression(node) { + // Check this is direct call to eval + if (!this.scopeManager.__ignoreEval() && node.callee.type === Syntax.Identifier && node.callee.name === "eval") { + // NOTE: This should be `variableScope`. Since direct eval call always creates Lexical environment and + // let / const should be enclosed into it. Only VariableDeclaration affects on the caller's environment. + this.currentScope().variableScope.__detectEval(); + } + this.visitChildren(node); + } + }, + BlockStatement: { + value: function BlockStatement(node) { + if (this.scopeManager.__isES6()) { + this.scopeManager.__nestBlockScope(node); + } + + this.visitChildren(node); + + this.close(node); + } + }, + ThisExpression: { + value: function ThisExpression() { + this.currentScope().variableScope.__detectThis(); + } + }, + WithStatement: { + value: function WithStatement(node) { + this.visit(node.object); + // Then nest scope for WithStatement. + this.scopeManager.__nestWithScope(node); + + this.visit(node.body); + + this.close(node); + } + }, + VariableDeclaration: { + value: function VariableDeclaration(node) { + var variableTargetScope, i, iz, decl; + variableTargetScope = node.kind === "var" ? this.currentScope().variableScope : this.currentScope(); + for (i = 0, iz = node.declarations.length; i < iz; ++i) { + decl = node.declarations[i]; + this.visitVariableDeclaration(variableTargetScope, Variable.Variable, node, i); + if (decl.init) { + this.visit(decl.init); + } + } + } + }, + SwitchStatement: { + + // sec 13.11.8 + + value: function SwitchStatement(node) { + var i, iz; + + this.visit(node.discriminant); + + if (this.scopeManager.__isES6()) { + this.scopeManager.__nestSwitchScope(node); + } + + for (i = 0, iz = node.cases.length; i < iz; ++i) { + this.visit(node.cases[i]); + } + + this.close(node); + } + }, + FunctionDeclaration: { + value: function FunctionDeclaration(node) { + this.visitFunction(node); + } + }, + FunctionExpression: { + value: function FunctionExpression(node) { + this.visitFunction(node); + } + }, + ForOfStatement: { + value: function ForOfStatement(node) { + this.visitForIn(node); + } + }, + ForInStatement: { + value: function ForInStatement(node) { + this.visitForIn(node); + } + }, + ArrowFunctionExpression: { + value: function ArrowFunctionExpression(node) { + this.visitFunction(node); + } + }, + ImportDeclaration: { + value: function ImportDeclaration(node) { + var importer; + + assert(this.scopeManager.__isES6() && this.scopeManager.isModule(), "ImportDeclaration should appear when the mode is ES6 and in the module context."); + + importer = new Importer(node, this); + importer.visit(node); + } + }, + visitExportDeclaration: { + value: function visitExportDeclaration(node) { + if (node.source) { + return; + } + if (node.declaration) { + this.visit(node.declaration); + return; + } + + this.visitChildren(node); + } + }, + ExportDeclaration: { + value: function ExportDeclaration(node) { + this.visitExportDeclaration(node); + } + }, + ExportNamedDeclaration: { + value: function ExportNamedDeclaration(node) { + this.visitExportDeclaration(node); + } + }, + ExportSpecifier: { + value: function ExportSpecifier(node) { + var local = node.id || node.local; + this.visit(local); + } + } + }); + + return Referencer; +})(esrecurse.Visitor); + +module.exports = Referencer; + +/* vim: set sw=4 ts=4 et tw=80 : */ + + +},{"./definition":75,"./pattern-visitor":77,"./reference":78,"./variable":82,"assert":5,"esrecurse":84,"estraverse":89}],80:[function(require,module,exports){ +"use strict"; + +var _interopRequire = function (obj) { return obj && obj.__esModule ? obj["default"] : obj; }; + +var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + +/* + Copyright (C) 2015 Yusuke Suzuki <utatane.tea@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. +*/ + +var WeakMap = _interopRequire(require("es6-weak-map")); + +var _scope = require("./scope"); + +var Scope = _interopRequire(_scope); + +var assert = _interopRequire(require("assert")); + +var GlobalScope = _scope.GlobalScope; +var CatchScope = _scope.CatchScope; +var WithScope = _scope.WithScope; +var ModuleScope = _scope.ModuleScope; +var ClassScope = _scope.ClassScope; +var SwitchScope = _scope.SwitchScope; +var FunctionScope = _scope.FunctionScope; +var ForScope = _scope.ForScope; +var TDZScope = _scope.TDZScope; +var FunctionExpressionNameScope = _scope.FunctionExpressionNameScope; +var BlockScope = _scope.BlockScope; + +/** + * @class ScopeManager + */ + +var ScopeManager = (function () { + function ScopeManager(options) { + _classCallCheck(this, ScopeManager); + + this.scopes = []; + this.globalScope = null; + this.__nodeToScope = new WeakMap(); + this.__currentScope = null; + this.__options = options; + this.__declaredVariables = new WeakMap(); + } + + _createClass(ScopeManager, { + __useDirective: { + value: function __useDirective() { + return this.__options.directive; + } + }, + __isOptimistic: { + value: function __isOptimistic() { + return this.__options.optimistic; + } + }, + __ignoreEval: { + value: function __ignoreEval() { + return this.__options.ignoreEval; + } + }, + __isNodejsScope: { + value: function __isNodejsScope() { + return this.__options.nodejsScope; + } + }, + isModule: { + value: function isModule() { + return this.__options.sourceType === "module"; + } + }, + __get: { + + // Returns appropriate scope for this node. + + value: function __get(node) { + return this.__nodeToScope.get(node); + } + }, + getDeclaredVariables: { + + /** + * Get variables that are declared by the node. + * + * "are declared by the node" means the node is same as `Variable.defs[].node` or `Variable.defs[].parent`. + * If the node declares nothing, this method returns an empty array. + * CAUTION: This API is experimental. See https://github.com/estools/escope/pull/69 for more details. + * + * @param {Esprima.Node} node - a node to get. + * @returns {Variable[]} variables that declared by the node. + */ + + value: function getDeclaredVariables(node) { + return this.__declaredVariables.get(node) || []; + } + }, + acquire: { + + /** + * acquire scope from node. + * @method ScopeManager#acquire + * @param {Esprima.Node} node - node for the acquired scope. + * @param {boolean=} inner - look up the most inner scope, default value is false. + * @return {Scope?} + */ + + value: function acquire(node, inner) { + var scopes, scope, i, iz; + + function predicate(scope) { + if (scope.type === "function" && scope.functionExpressionScope) { + return false; + } + if (scope.type === "TDZ") { + return false; + } + return true; + } + + scopes = this.__get(node); + if (!scopes || scopes.length === 0) { + return null; + } + + // Heuristic selection from all scopes. + // If you would like to get all scopes, please use ScopeManager#acquireAll. + if (scopes.length === 1) { + return scopes[0]; + } + + if (inner) { + for (i = scopes.length - 1; i >= 0; --i) { + scope = scopes[i]; + if (predicate(scope)) { + return scope; + } + } + } else { + for (i = 0, iz = scopes.length; i < iz; ++i) { + scope = scopes[i]; + if (predicate(scope)) { + return scope; + } + } + } + + return null; + } + }, + acquireAll: { + + /** + * acquire all scopes from node. + * @method ScopeManager#acquireAll + * @param {Esprima.Node} node - node for the acquired scope. + * @return {Scope[]?} + */ + + value: function acquireAll(node) { + return this.__get(node); + } + }, + release: { + + /** + * release the node. + * @method ScopeManager#release + * @param {Esprima.Node} node - releasing node. + * @param {boolean=} inner - look up the most inner scope, default value is false. + * @return {Scope?} upper scope for the node. + */ + + value: function release(node, inner) { + var scopes, scope; + scopes = this.__get(node); + if (scopes && scopes.length) { + scope = scopes[0].upper; + if (!scope) { + return null; + } + return this.acquire(scope.block, inner); + } + return null; + } + }, + attach: { + value: function attach() {} + }, + detach: { + value: function detach() {} + }, + __nestScope: { + value: function __nestScope(scope) { + if (scope instanceof GlobalScope) { + assert(this.__currentScope === null); + this.globalScope = scope; + } + this.__currentScope = scope; + return scope; + } + }, + __nestGlobalScope: { + value: function __nestGlobalScope(node) { + return this.__nestScope(new GlobalScope(this, node)); + } + }, + __nestBlockScope: { + value: function __nestBlockScope(node, isMethodDefinition) { + return this.__nestScope(new BlockScope(this, this.__currentScope, node)); + } + }, + __nestFunctionScope: { + value: function __nestFunctionScope(node, isMethodDefinition) { + return this.__nestScope(new FunctionScope(this, this.__currentScope, node, isMethodDefinition)); + } + }, + __nestForScope: { + value: function __nestForScope(node) { + return this.__nestScope(new ForScope(this, this.__currentScope, node)); + } + }, + __nestCatchScope: { + value: function __nestCatchScope(node) { + return this.__nestScope(new CatchScope(this, this.__currentScope, node)); + } + }, + __nestWithScope: { + value: function __nestWithScope(node) { + return this.__nestScope(new WithScope(this, this.__currentScope, node)); + } + }, + __nestClassScope: { + value: function __nestClassScope(node) { + return this.__nestScope(new ClassScope(this, this.__currentScope, node)); + } + }, + __nestSwitchScope: { + value: function __nestSwitchScope(node) { + return this.__nestScope(new SwitchScope(this, this.__currentScope, node)); + } + }, + __nestModuleScope: { + value: function __nestModuleScope(node) { + return this.__nestScope(new ModuleScope(this, this.__currentScope, node)); + } + }, + __nestTDZScope: { + value: function __nestTDZScope(node) { + return this.__nestScope(new TDZScope(this, this.__currentScope, node)); + } + }, + __nestFunctionExpressionNameScope: { + value: function __nestFunctionExpressionNameScope(node) { + return this.__nestScope(new FunctionExpressionNameScope(this, this.__currentScope, node)); + } + }, + __isES6: { + value: function __isES6() { + return this.__options.ecmaVersion >= 6; + } + } + }); + + return ScopeManager; +})(); + +module.exports = ScopeManager; + +/* vim: set sw=4 ts=4 et tw=80 : */ + + +},{"./scope":81,"assert":5,"es6-weak-map":70}],81:[function(require,module,exports){ +"use strict"; + +var _interopRequire = function (obj) { return obj && obj.__esModule ? obj["default"] : obj; }; + +var _get = function get(object, property, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc && desc.writable) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; + +var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +/* + Copyright (C) 2015 Yusuke Suzuki <utatane.tea@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. +*/ + +var Syntax = require("estraverse").Syntax; + +var Map = _interopRequire(require("es6-map")); + +var Reference = _interopRequire(require("./reference")); + +var Variable = _interopRequire(require("./variable")); + +var Definition = _interopRequire(require("./definition")); + +var assert = _interopRequire(require("assert")); + +function isStrictScope(scope, block, isMethodDefinition, useDirective) { + var body, i, iz, stmt, expr; + + // When upper scope is exists and strict, inner scope is also strict. + if (scope.upper && scope.upper.isStrict) { + return true; + } + + // ArrowFunctionExpression's scope is always strict scope. + if (block.type === Syntax.ArrowFunctionExpression) { + return true; + } + + if (isMethodDefinition) { + return true; + } + + if (scope.type === "class" || scope.type === "module") { + return true; + } + + if (scope.type === "block" || scope.type === "switch") { + return false; + } + + if (scope.type === "function") { + if (block.type === Syntax.Program) { + body = block; + } else { + body = block.body; + } + } else if (scope.type === "global") { + body = block; + } else { + return false; + } + + // Search 'use strict' directive. + if (useDirective) { + for (i = 0, iz = body.body.length; i < iz; ++i) { + stmt = body.body[i]; + if (stmt.type !== Syntax.DirectiveStatement) { + break; + } + if (stmt.raw === "\"use strict\"" || stmt.raw === "'use strict'") { + return true; + } + } + } else { + for (i = 0, iz = body.body.length; i < iz; ++i) { + stmt = body.body[i]; + if (stmt.type !== Syntax.ExpressionStatement) { + break; + } + expr = stmt.expression; + if (expr.type !== Syntax.Literal || typeof expr.value !== "string") { + break; + } + if (expr.raw != null) { + if (expr.raw === "\"use strict\"" || expr.raw === "'use strict'") { + return true; + } + } else { + if (expr.value === "use strict") { + return true; + } + } + } + } + return false; +} + +function registerScope(scopeManager, scope) { + var scopes; + + scopeManager.scopes.push(scope); + + scopes = scopeManager.__nodeToScope.get(scope.block); + if (scopes) { + scopes.push(scope); + } else { + scopeManager.__nodeToScope.set(scope.block, [scope]); + } +} + +function shouldBeStatically(def) { + return def.type === Variable.ClassName || def.type === Variable.Variable && def.parent.kind !== "var"; +} + +/** + * @class Scope + */ + +var Scope = (function () { + function Scope(scopeManager, type, upperScope, block, isMethodDefinition) { + _classCallCheck(this, Scope); + + /** + * One of 'TDZ', 'module', 'block', 'switch', 'function', 'catch', 'with', 'function', 'class', 'global'. + * @member {String} Scope#type + */ + this.type = type; + /** + * The scoped {@link Variable}s of this scope, as <code>{ Variable.name + * : Variable }</code>. + * @member {Map} Scope#set + */ + this.set = new Map(); + /** + * The tainted variables of this scope, as <code>{ Variable.name : + * boolean }</code>. + * @member {Map} Scope#taints */ + this.taints = new Map(); + /** + * Generally, through the lexical scoping of JS you can always know + * which variable an identifier in the source code refers to. There are + * a few exceptions to this rule. With 'global' and 'with' scopes you + * can only decide at runtime which variable a reference refers to. + * Moreover, if 'eval()' is used in a scope, it might introduce new + * bindings in this or its parent scopes. + * All those scopes are considered 'dynamic'. + * @member {boolean} Scope#dynamic + */ + this.dynamic = this.type === "global" || this.type === "with"; + /** + * A reference to the scope-defining syntax node. + * @member {esprima.Node} Scope#block + */ + this.block = block; + /** + * The {@link Reference|references} that are not resolved with this scope. + * @member {Reference[]} Scope#through + */ + this.through = []; + /** + * The scoped {@link Variable}s of this scope. In the case of a + * 'function' scope this includes the automatic argument <em>arguments</em> as + * its first element, as well as all further formal arguments. + * @member {Variable[]} Scope#variables + */ + this.variables = []; + /** + * Any variable {@link Reference|reference} found in this scope. This + * includes occurrences of local variables as well as variables from + * parent scopes (including the global scope). For local variables + * this also includes defining occurrences (like in a 'var' statement). + * In a 'function' scope this does not include the occurrences of the + * formal parameter in the parameter list. + * @member {Reference[]} Scope#references + */ + this.references = []; + + /** + * For 'global' and 'function' scopes, this is a self-reference. For + * other scope types this is the <em>variableScope</em> value of the + * parent scope. + * @member {Scope} Scope#variableScope + */ + this.variableScope = this.type === "global" || this.type === "function" || this.type === "module" ? this : upperScope.variableScope; + /** + * Whether this scope is created by a FunctionExpression. + * @member {boolean} Scope#functionExpressionScope + */ + this.functionExpressionScope = false; + /** + * Whether this is a scope that contains an 'eval()' invocation. + * @member {boolean} Scope#directCallToEvalScope + */ + this.directCallToEvalScope = false; + /** + * @member {boolean} Scope#thisFound + */ + this.thisFound = false; + + this.__left = []; + + /** + * Reference to the parent {@link Scope|scope}. + * @member {Scope} Scope#upper + */ + this.upper = upperScope; + /** + * Whether 'use strict' is in effect in this scope. + * @member {boolean} Scope#isStrict + */ + this.isStrict = isStrictScope(this, block, isMethodDefinition, scopeManager.__useDirective()); + + /** + * List of nested {@link Scope}s. + * @member {Scope[]} Scope#childScopes + */ + this.childScopes = []; + if (this.upper) { + this.upper.childScopes.push(this); + } + + this.__declaredVariables = scopeManager.__declaredVariables; + + registerScope(scopeManager, this); + } + + _createClass(Scope, { + __shouldStaticallyClose: { + value: function __shouldStaticallyClose(scopeManager) { + return !this.dynamic || scopeManager.__isOptimistic(); + } + }, + __shouldStaticallyCloseForGlobal: { + value: function __shouldStaticallyCloseForGlobal(ref) { + // On global scope, let/const/class declarations should be resolved statically. + var name = ref.identifier.name; + if (!this.set.has(name)) { + return false; + } + + var variable = this.set.get(name); + var defs = variable.defs; + return defs.length > 0 && defs.every(shouldBeStatically); + } + }, + __staticCloseRef: { + value: function __staticCloseRef(ref) { + if (!this.__resolve(ref)) { + this.__delegateToUpperScope(ref); + } + } + }, + __dynamicCloseRef: { + value: function __dynamicCloseRef(ref) { + // notify all names are through to global + var current = this; + do { + current.through.push(ref); + current = current.upper; + } while (current); + } + }, + __globalCloseRef: { + value: function __globalCloseRef(ref) { + // let/const/class declarations should be resolved statically. + // others should be resolved dynamically. + if (this.__shouldStaticallyCloseForGlobal(ref)) { + this.__staticCloseRef(ref); + } else { + this.__dynamicCloseRef(ref); + } + } + }, + __close: { + value: function __close(scopeManager) { + var closeRef; + if (this.__shouldStaticallyClose(scopeManager)) { + closeRef = this.__staticCloseRef; + } else if (this.type !== "global") { + closeRef = this.__dynamicCloseRef; + } else { + closeRef = this.__globalCloseRef; + } + + // Try Resolving all references in this scope. + for (var i = 0, iz = this.__left.length; i < iz; ++i) { + var ref = this.__left[i]; + closeRef.call(this, ref); + } + this.__left = null; + + return this.upper; + } + }, + __resolve: { + value: function __resolve(ref) { + var variable, name; + name = ref.identifier.name; + if (this.set.has(name)) { + variable = this.set.get(name); + variable.references.push(ref); + variable.stack = variable.stack && ref.from.variableScope === this.variableScope; + if (ref.tainted) { + variable.tainted = true; + this.taints.set(variable.name, true); + } + ref.resolved = variable; + return true; + } + return false; + } + }, + __delegateToUpperScope: { + value: function __delegateToUpperScope(ref) { + if (this.upper) { + this.upper.__left.push(ref); + } + this.through.push(ref); + } + }, + __addDeclaredVariablesOfNode: { + value: function __addDeclaredVariablesOfNode(variable, node) { + if (node == null) { + return; + } + + var variables = this.__declaredVariables.get(node); + if (variables == null) { + variables = []; + this.__declaredVariables.set(node, variables); + } + if (variables.indexOf(variable) === -1) { + variables.push(variable); + } + } + }, + __defineGeneric: { + value: function __defineGeneric(name, set, variables, node, def) { + var variable; + + variable = set.get(name); + if (!variable) { + variable = new Variable(name, this); + set.set(name, variable); + variables.push(variable); + } + + if (def) { + variable.defs.push(def); + if (def.type !== Variable.TDZ) { + this.__addDeclaredVariablesOfNode(variable, def.node); + this.__addDeclaredVariablesOfNode(variable, def.parent); + } + } + if (node) { + variable.identifiers.push(node); + } + } + }, + __define: { + value: function __define(node, def) { + if (node && node.type === Syntax.Identifier) { + this.__defineGeneric(node.name, this.set, this.variables, node, def); + } + } + }, + __referencing: { + value: function __referencing(node, assign, writeExpr, maybeImplicitGlobal, partial, init) { + // because Array element may be null + if (!node || node.type !== Syntax.Identifier) { + return; + } + + // Specially handle like `this`. + if (node.name === "super") { + return; + } + + var ref = new Reference(node, this, assign || Reference.READ, writeExpr, maybeImplicitGlobal, !!partial, !!init); + this.references.push(ref); + this.__left.push(ref); + } + }, + __detectEval: { + value: function __detectEval() { + var current; + current = this; + this.directCallToEvalScope = true; + do { + current.dynamic = true; + current = current.upper; + } while (current); + } + }, + __detectThis: { + value: function __detectThis() { + this.thisFound = true; + } + }, + __isClosed: { + value: function __isClosed() { + return this.__left === null; + } + }, + resolve: { + + /** + * returns resolved {Reference} + * @method Scope#resolve + * @param {Esprima.Identifier} ident - identifier to be resolved. + * @return {Reference} + */ + + value: function resolve(ident) { + var ref, i, iz; + assert(this.__isClosed(), "Scope should be closed."); + assert(ident.type === Syntax.Identifier, "Target should be identifier."); + for (i = 0, iz = this.references.length; i < iz; ++i) { + ref = this.references[i]; + if (ref.identifier === ident) { + return ref; + } + } + return null; + } + }, + isStatic: { + + /** + * returns this scope is static + * @method Scope#isStatic + * @return {boolean} + */ + + value: function isStatic() { + return !this.dynamic; + } + }, + isArgumentsMaterialized: { + + /** + * returns this scope has materialized arguments + * @method Scope#isArgumentsMaterialized + * @return {boolean} + */ + + value: function isArgumentsMaterialized() { + return true; + } + }, + isThisMaterialized: { + + /** + * returns this scope has materialized `this` reference + * @method Scope#isThisMaterialized + * @return {boolean} + */ + + value: function isThisMaterialized() { + return true; + } + }, + isUsedName: { + value: function isUsedName(name) { + if (this.set.has(name)) { + return true; + } + for (var i = 0, iz = this.through.length; i < iz; ++i) { + if (this.through[i].identifier.name === name) { + return true; + } + } + return false; + } + } + }); + + return Scope; +})(); + +exports["default"] = Scope; + +var GlobalScope = exports.GlobalScope = (function (_Scope) { + function GlobalScope(scopeManager, block) { + _classCallCheck(this, GlobalScope); + + _get(Object.getPrototypeOf(GlobalScope.prototype), "constructor", this).call(this, scopeManager, "global", null, block, false); + this.implicit = { + set: new Map(), + variables: [], + /** + * List of {@link Reference}s that are left to be resolved (i.e. which + * need to be linked to the variable they refer to). + * @member {Reference[]} Scope#implicit#left + */ + left: [] + }; + } + + _inherits(GlobalScope, _Scope); + + _createClass(GlobalScope, { + __close: { + value: function __close(scopeManager) { + var implicit = []; + for (var i = 0, iz = this.__left.length; i < iz; ++i) { + var ref = this.__left[i]; + if (ref.__maybeImplicitGlobal && !this.set.has(ref.identifier.name)) { + implicit.push(ref.__maybeImplicitGlobal); + } + } + + // create an implicit global variable from assignment expression + for (var i = 0, iz = implicit.length; i < iz; ++i) { + var info = implicit[i]; + this.__defineImplicit(info.pattern, new Definition(Variable.ImplicitGlobalVariable, info.pattern, info.node, null, null, null)); + } + + this.implicit.left = this.__left; + + return _get(Object.getPrototypeOf(GlobalScope.prototype), "__close", this).call(this, scopeManager); + } + }, + __defineImplicit: { + value: function __defineImplicit(node, def) { + if (node && node.type === Syntax.Identifier) { + this.__defineGeneric(node.name, this.implicit.set, this.implicit.variables, node, def); + } + } + } + }); + + return GlobalScope; +})(Scope); + +var ModuleScope = exports.ModuleScope = (function (_Scope2) { + function ModuleScope(scopeManager, upperScope, block) { + _classCallCheck(this, ModuleScope); + + _get(Object.getPrototypeOf(ModuleScope.prototype), "constructor", this).call(this, scopeManager, "module", upperScope, block, false); + } + + _inherits(ModuleScope, _Scope2); + + return ModuleScope; +})(Scope); + +var FunctionExpressionNameScope = exports.FunctionExpressionNameScope = (function (_Scope3) { + function FunctionExpressionNameScope(scopeManager, upperScope, block) { + _classCallCheck(this, FunctionExpressionNameScope); + + _get(Object.getPrototypeOf(FunctionExpressionNameScope.prototype), "constructor", this).call(this, scopeManager, "function-expression-name", upperScope, block, false); + this.__define(block.id, new Definition(Variable.FunctionName, block.id, block, null, null, null)); + this.functionExpressionScope = true; + } + + _inherits(FunctionExpressionNameScope, _Scope3); + + return FunctionExpressionNameScope; +})(Scope); + +var CatchScope = exports.CatchScope = (function (_Scope4) { + function CatchScope(scopeManager, upperScope, block) { + _classCallCheck(this, CatchScope); + + _get(Object.getPrototypeOf(CatchScope.prototype), "constructor", this).call(this, scopeManager, "catch", upperScope, block, false); + } + + _inherits(CatchScope, _Scope4); + + return CatchScope; +})(Scope); + +var WithScope = exports.WithScope = (function (_Scope5) { + function WithScope(scopeManager, upperScope, block) { + _classCallCheck(this, WithScope); + + _get(Object.getPrototypeOf(WithScope.prototype), "constructor", this).call(this, scopeManager, "with", upperScope, block, false); + } + + _inherits(WithScope, _Scope5); + + _createClass(WithScope, { + __close: { + value: function __close(scopeManager) { + if (this.__shouldStaticallyClose(scopeManager)) { + return _get(Object.getPrototypeOf(WithScope.prototype), "__close", this).call(this, scopeManager); + } + + for (var i = 0, iz = this.__left.length; i < iz; ++i) { + var ref = this.__left[i]; + ref.tainted = true; + this.__delegateToUpperScope(ref); + } + this.__left = null; + + return this.upper; + } + } + }); + + return WithScope; +})(Scope); + +var TDZScope = exports.TDZScope = (function (_Scope6) { + function TDZScope(scopeManager, upperScope, block) { + _classCallCheck(this, TDZScope); + + _get(Object.getPrototypeOf(TDZScope.prototype), "constructor", this).call(this, scopeManager, "TDZ", upperScope, block, false); + } + + _inherits(TDZScope, _Scope6); + + return TDZScope; +})(Scope); + +var BlockScope = exports.BlockScope = (function (_Scope7) { + function BlockScope(scopeManager, upperScope, block) { + _classCallCheck(this, BlockScope); + + _get(Object.getPrototypeOf(BlockScope.prototype), "constructor", this).call(this, scopeManager, "block", upperScope, block, false); + } + + _inherits(BlockScope, _Scope7); + + return BlockScope; +})(Scope); + +var SwitchScope = exports.SwitchScope = (function (_Scope8) { + function SwitchScope(scopeManager, upperScope, block) { + _classCallCheck(this, SwitchScope); + + _get(Object.getPrototypeOf(SwitchScope.prototype), "constructor", this).call(this, scopeManager, "switch", upperScope, block, false); + } + + _inherits(SwitchScope, _Scope8); + + return SwitchScope; +})(Scope); + +var FunctionScope = exports.FunctionScope = (function (_Scope9) { + function FunctionScope(scopeManager, upperScope, block, isMethodDefinition) { + _classCallCheck(this, FunctionScope); + + _get(Object.getPrototypeOf(FunctionScope.prototype), "constructor", this).call(this, scopeManager, "function", upperScope, block, isMethodDefinition); + + // section 9.2.13, FunctionDeclarationInstantiation. + // NOTE Arrow functions never have an arguments objects. + if (this.block.type !== Syntax.ArrowFunctionExpression) { + this.__defineArguments(); + } + } + + _inherits(FunctionScope, _Scope9); + + _createClass(FunctionScope, { + isArgumentsMaterialized: { + value: function isArgumentsMaterialized() { + // TODO(Constellation) + // We can more aggressive on this condition like this. + // + // function t() { + // // arguments of t is always hidden. + // function arguments() { + // } + // } + if (this.block.type === Syntax.ArrowFunctionExpression) { + return false; + } + + if (!this.isStatic()) { + return true; + } + + var variable = this.set.get("arguments"); + assert(variable, "Always have arguments variable."); + return variable.tainted || variable.references.length !== 0; + } + }, + isThisMaterialized: { + value: function isThisMaterialized() { + if (!this.isStatic()) { + return true; + } + return this.thisFound; + } + }, + __defineArguments: { + value: function __defineArguments() { + this.__defineGeneric("arguments", this.set, this.variables, null, null); + this.taints.set("arguments", true); + } + } + }); + + return FunctionScope; +})(Scope); + +var ForScope = exports.ForScope = (function (_Scope10) { + function ForScope(scopeManager, upperScope, block) { + _classCallCheck(this, ForScope); + + _get(Object.getPrototypeOf(ForScope.prototype), "constructor", this).call(this, scopeManager, "for", upperScope, block, false); + } + + _inherits(ForScope, _Scope10); + + return ForScope; +})(Scope); + +var ClassScope = exports.ClassScope = (function (_Scope11) { + function ClassScope(scopeManager, upperScope, block) { + _classCallCheck(this, ClassScope); + + _get(Object.getPrototypeOf(ClassScope.prototype), "constructor", this).call(this, scopeManager, "class", upperScope, block, false); + } + + _inherits(ClassScope, _Scope11); + + return ClassScope; +})(Scope); + +/* vim: set sw=4 ts=4 et tw=80 : */ + + +},{"./definition":75,"./reference":78,"./variable":82,"assert":5,"es6-map":59,"estraverse":89}],82:[function(require,module,exports){ +"use strict"; + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + +/* + Copyright (C) 2015 Yusuke Suzuki <utatane.tea@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. +*/ + +/** + * A Variable represents a locally scoped identifier. These include arguments to + * functions. + * @class Variable + */ + +var Variable = function Variable(name, scope) { + _classCallCheck(this, Variable); + + /** + * The variable name, as given in the source code. + * @member {String} Variable#name + */ + this.name = name; + /** + * List of defining occurrences of this variable (like in 'var ...' + * statements or as parameter), as AST nodes. + * @member {esprima.Identifier[]} Variable#identifiers + */ + this.identifiers = []; + /** + * List of {@link Reference|references} of this variable (excluding parameter entries) + * in its defining scope and all nested scopes. For defining + * occurrences only see {@link Variable#defs}. + * @member {Reference[]} Variable#references + */ + this.references = []; + + /** + * List of defining occurrences of this variable (like in 'var ...' + * statements or as parameter), as custom objects. + * @member {Definition[]} Variable#defs + */ + this.defs = []; + + this.tainted = false; + /** + * Whether this is a stack variable. + * @member {boolean} Variable#stack + */ + this.stack = true; + /** + * Reference to the enclosing Scope. + * @member {Scope} Variable#scope + */ + this.scope = scope; +}; + +module.exports = Variable; + +Variable.CatchClause = "CatchClause"; +Variable.Parameter = "Parameter"; +Variable.FunctionName = "FunctionName"; +Variable.ClassName = "ClassName"; +Variable.Variable = "Variable"; +Variable.ImportBinding = "ImportBinding"; +Variable.TDZ = "TDZ"; +Variable.ImplicitGlobalVariable = "ImplicitGlobalVariable"; + +/* vim: set sw=4 ts=4 et tw=80 : */ + + +},{}],83:[function(require,module,exports){ +module.exports={ + "_args": [ + [ + "escope@^3.2.1", + "/Users/force/code/eslint" + ] + ], + "_from": "escope@>=3.2.1 <4.0.0", + "_id": "escope@3.3.0", + "_inCache": true, + "_installable": true, + "_location": "/escope", + "_nodeVersion": "4.1.1", + "_npmUser": { + "email": "utatane.tea@gmail.com", + "name": "constellation" + }, + "_npmVersion": "2.14.4", + "_phantomChildren": {}, + "_requested": { + "name": "escope", + "raw": "escope@^3.2.1", + "rawSpec": "^3.2.1", + "scope": null, + "spec": ">=3.2.1 <4.0.0", + "type": "range" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/escope/-/escope-3.3.0.tgz", + "_shasum": "6201c97285c2c13643afe4453b58de64481aa1a4", + "_shrinkwrap": null, + "_spec": "escope@^3.2.1", + "_where": "/Users/force/code/eslint", + "bugs": { + "url": "https://github.com/estools/escope/issues" + }, + "dependencies": { + "es6-map": "^0.1.2", + "es6-weak-map": "^2.0.1", + "esrecurse": "^3.1.1", + "estraverse": "^4.1.1" + }, + "description": "ECMAScript scope analyzer", + "devDependencies": { + "acorn": "^2.5.2", + "babel": "^4.7.12", + "browserify": "^12.0.1", + "chai": "^3.4.0", + "coffee-script": "^1.10.0", + "espree": "^2.2.5", + "esprima": "^2.7.0", + "gulp": "^3.9.0", + "gulp-babel": "^4.0.0", + "gulp-bump": "^1.0.0", + "gulp-coffee": "^2.3.1", + "gulp-eslint": "^1.0.0", + "gulp-espower": "^1.0.1", + "gulp-filter": "^3.0.1", + "gulp-git": "^1.6.0", + "gulp-mocha": "^2.1.3", + "gulp-plumber": "^1.0.1", + "gulp-sourcemaps": "^1.6.0", + "gulp-tag-version": "^1.3.0", + "jsdoc": "^3.3.3", + "lazypipe": "^1.0.1", + "minimist": "^1.2.0", + "vinyl-source-stream": "^1.1.0" + }, + "directories": {}, + "dist": { + "shasum": "6201c97285c2c13643afe4453b58de64481aa1a4", + "tarball": "http://registry.npmjs.org/escope/-/escope-3.3.0.tgz" + }, + "engines": { + "node": ">=0.4.0" + }, + "gitHead": "a3402c3e5c04f4e3dc15c88fd2d7ce8608d26ba7", + "homepage": "http://github.com/estools/escope", + "license": "BSD-2-Clause", + "main": "lib/index.js", + "maintainers": [ + { + "name": "constellation", + "email": "utatane.tea@gmail.com" + }, + { + "name": "michaelficarra", + "email": "npm@michael.ficarra.me" + }, + { + "name": "nzakas", + "email": "nicholas@nczconsulting.com" + } + ], + "name": "escope", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+https://github.com/estools/escope.git" + }, + "scripts": { + "jsdoc": "jsdoc src/*.js README.md", + "lint": "gulp lint", + "test": "gulp travis", + "unit-test": "gulp test" + }, + "version": "3.3.0" +} + +},{}],84:[function(require,module,exports){ +/* Copyright (C) 2014 Yusuke Suzuki <utatane.tea@gmail.com> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -14851,11 +15415,11 @@ function isProperty(nodeType, key) { return (nodeType === estraverse.Syntax.ObjectExpression || nodeType === estraverse.Syntax.ObjectPattern) && key === 'properties'; } function Visitor(visitor) { - this.__visitor = visitor; + this.__visitor = visitor || this; } /* Default method for visiting children. * When you need to call default visiting operation inside custom visiting * operation, you can use it with `this.visitChildren(node)`. @@ -14915,195 +15479,1046 @@ v.visit(node); }; }()); /* vim: set sw=4 ts=4 et tw=80 : */ -},{"./package.json":122,"estraverse":127}],122:[function(require,module,exports){ +},{"./package.json":87,"estraverse":85}],85:[function(require,module,exports){ +/* + Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com> + Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@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. +*/ +/*jslint vars:false, bitwise:true*/ +/*jshint indent:4*/ +/*global exports:true*/ +(function clone(exports) { + 'use strict'; + + var Syntax, + isArray, + VisitorOption, + VisitorKeys, + objectCreate, + objectKeys, + BREAK, + SKIP, + REMOVE; + + function ignoreJSHintError() { } + + isArray = Array.isArray; + if (!isArray) { + isArray = function isArray(array) { + return Object.prototype.toString.call(array) === '[object Array]'; + }; + } + + function deepCopy(obj) { + var ret = {}, key, val; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + val = obj[key]; + if (typeof val === 'object' && val !== null) { + ret[key] = deepCopy(val); + } else { + ret[key] = val; + } + } + } + return ret; + } + + function shallowCopy(obj) { + var ret = {}, key; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + ret[key] = obj[key]; + } + } + return ret; + } + ignoreJSHintError(shallowCopy); + + // based on LLVM libc++ upper_bound / lower_bound + // MIT License + + function upperBound(array, func) { + var diff, len, i, current; + + len = array.length; + i = 0; + + while (len) { + diff = len >>> 1; + current = i + diff; + if (func(array[current])) { + len = diff; + } else { + i = current + 1; + len -= diff + 1; + } + } + return i; + } + + function lowerBound(array, func) { + var diff, len, i, current; + + len = array.length; + i = 0; + + while (len) { + diff = len >>> 1; + current = i + diff; + if (func(array[current])) { + i = current + 1; + len -= diff + 1; + } else { + len = diff; + } + } + return i; + } + ignoreJSHintError(lowerBound); + + objectCreate = Object.create || (function () { + function F() { } + + return function (o) { + F.prototype = o; + return new F(); + }; + })(); + + objectKeys = Object.keys || function (o) { + var keys = [], key; + for (key in o) { + keys.push(key); + } + return keys; + }; + + function extend(to, from) { + var keys = objectKeys(from), key, i, len; + for (i = 0, len = keys.length; i < len; i += 1) { + key = keys[i]; + to[key] = from[key]; + } + return to; + } + + Syntax = { + AssignmentExpression: 'AssignmentExpression', + AssignmentPattern: 'AssignmentPattern', + ArrayExpression: 'ArrayExpression', + ArrayPattern: 'ArrayPattern', + ArrowFunctionExpression: 'ArrowFunctionExpression', + AwaitExpression: 'AwaitExpression', // CAUTION: It's deferred to ES7. + BlockStatement: 'BlockStatement', + BinaryExpression: 'BinaryExpression', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ClassBody: 'ClassBody', + ClassDeclaration: 'ClassDeclaration', + ClassExpression: 'ClassExpression', + ComprehensionBlock: 'ComprehensionBlock', // CAUTION: It's deferred to ES7. + ComprehensionExpression: 'ComprehensionExpression', // CAUTION: It's deferred to ES7. + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DebuggerStatement: 'DebuggerStatement', + DirectiveStatement: 'DirectiveStatement', + DoWhileStatement: 'DoWhileStatement', + EmptyStatement: 'EmptyStatement', + ExportAllDeclaration: 'ExportAllDeclaration', + ExportDefaultDeclaration: 'ExportDefaultDeclaration', + ExportNamedDeclaration: 'ExportNamedDeclaration', + ExportSpecifier: 'ExportSpecifier', + ExpressionStatement: 'ExpressionStatement', + ForStatement: 'ForStatement', + ForInStatement: 'ForInStatement', + ForOfStatement: 'ForOfStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + GeneratorExpression: 'GeneratorExpression', // CAUTION: It's deferred to ES7. + Identifier: 'Identifier', + IfStatement: 'IfStatement', + ImportDeclaration: 'ImportDeclaration', + ImportDefaultSpecifier: 'ImportDefaultSpecifier', + ImportNamespaceSpecifier: 'ImportNamespaceSpecifier', + ImportSpecifier: 'ImportSpecifier', + Literal: 'Literal', + LabeledStatement: 'LabeledStatement', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + MethodDefinition: 'MethodDefinition', + ModuleSpecifier: 'ModuleSpecifier', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + ObjectPattern: 'ObjectPattern', + Program: 'Program', + Property: 'Property', + RestElement: 'RestElement', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SpreadElement: 'SpreadElement', + SuperExpression: 'SuperExpression', + SwitchStatement: 'SwitchStatement', + SwitchCase: 'SwitchCase', + TaggedTemplateExpression: 'TaggedTemplateExpression', + TemplateElement: 'TemplateElement', + TemplateLiteral: 'TemplateLiteral', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement', + YieldExpression: 'YieldExpression' + }; + + VisitorKeys = { + AssignmentExpression: ['left', 'right'], + AssignmentPattern: ['left', 'right'], + ArrayExpression: ['elements'], + ArrayPattern: ['elements'], + ArrowFunctionExpression: ['params', 'body'], + AwaitExpression: ['argument'], // CAUTION: It's deferred to ES7. + BlockStatement: ['body'], + BinaryExpression: ['left', 'right'], + BreakStatement: ['label'], + CallExpression: ['callee', 'arguments'], + CatchClause: ['param', 'body'], + ClassBody: ['body'], + ClassDeclaration: ['id', 'superClass', 'body'], + ClassExpression: ['id', 'superClass', 'body'], + ComprehensionBlock: ['left', 'right'], // CAUTION: It's deferred to ES7. + ComprehensionExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. + ConditionalExpression: ['test', 'consequent', 'alternate'], + ContinueStatement: ['label'], + DebuggerStatement: [], + DirectiveStatement: [], + DoWhileStatement: ['body', 'test'], + EmptyStatement: [], + ExportAllDeclaration: ['source'], + ExportDefaultDeclaration: ['declaration'], + ExportNamedDeclaration: ['declaration', 'specifiers', 'source'], + ExportSpecifier: ['exported', 'local'], + ExpressionStatement: ['expression'], + ForStatement: ['init', 'test', 'update', 'body'], + ForInStatement: ['left', 'right', 'body'], + ForOfStatement: ['left', 'right', 'body'], + FunctionDeclaration: ['id', 'params', 'body'], + FunctionExpression: ['id', 'params', 'body'], + GeneratorExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. + Identifier: [], + IfStatement: ['test', 'consequent', 'alternate'], + ImportDeclaration: ['specifiers', 'source'], + ImportDefaultSpecifier: ['local'], + ImportNamespaceSpecifier: ['local'], + ImportSpecifier: ['imported', 'local'], + Literal: [], + LabeledStatement: ['label', 'body'], + LogicalExpression: ['left', 'right'], + MemberExpression: ['object', 'property'], + MethodDefinition: ['key', 'value'], + ModuleSpecifier: [], + NewExpression: ['callee', 'arguments'], + ObjectExpression: ['properties'], + ObjectPattern: ['properties'], + Program: ['body'], + Property: ['key', 'value'], + RestElement: [ 'argument' ], + ReturnStatement: ['argument'], + SequenceExpression: ['expressions'], + SpreadElement: ['argument'], + SuperExpression: ['super'], + SwitchStatement: ['discriminant', 'cases'], + SwitchCase: ['test', 'consequent'], + TaggedTemplateExpression: ['tag', 'quasi'], + TemplateElement: [], + TemplateLiteral: ['quasis', 'expressions'], + ThisExpression: [], + ThrowStatement: ['argument'], + TryStatement: ['block', 'handler', 'finalizer'], + UnaryExpression: ['argument'], + UpdateExpression: ['argument'], + VariableDeclaration: ['declarations'], + VariableDeclarator: ['id', 'init'], + WhileStatement: ['test', 'body'], + WithStatement: ['object', 'body'], + YieldExpression: ['argument'] + }; + + // unique id + BREAK = {}; + SKIP = {}; + REMOVE = {}; + + VisitorOption = { + Break: BREAK, + Skip: SKIP, + Remove: REMOVE + }; + + function Reference(parent, key) { + this.parent = parent; + this.key = key; + } + + Reference.prototype.replace = function replace(node) { + this.parent[this.key] = node; + }; + + Reference.prototype.remove = function remove() { + if (isArray(this.parent)) { + this.parent.splice(this.key, 1); + return true; + } else { + this.replace(null); + return false; + } + }; + + function Element(node, path, wrap, ref) { + this.node = node; + this.path = path; + this.wrap = wrap; + this.ref = ref; + } + + function Controller() { } + + // API: + // return property path array from root to current node + Controller.prototype.path = function path() { + var i, iz, j, jz, result, element; + + function addToPath(result, path) { + if (isArray(path)) { + for (j = 0, jz = path.length; j < jz; ++j) { + result.push(path[j]); + } + } else { + result.push(path); + } + } + + // root node + if (!this.__current.path) { + return null; + } + + // first node is sentinel, second node is root element + result = []; + for (i = 2, iz = this.__leavelist.length; i < iz; ++i) { + element = this.__leavelist[i]; + addToPath(result, element.path); + } + addToPath(result, this.__current.path); + return result; + }; + + // API: + // return type of current node + Controller.prototype.type = function () { + var node = this.current(); + return node.type || this.__current.wrap; + }; + + // API: + // return array of parent elements + Controller.prototype.parents = function parents() { + var i, iz, result; + + // first node is sentinel + result = []; + for (i = 1, iz = this.__leavelist.length; i < iz; ++i) { + result.push(this.__leavelist[i].node); + } + + return result; + }; + + // API: + // return current node + Controller.prototype.current = function current() { + return this.__current.node; + }; + + Controller.prototype.__execute = function __execute(callback, element) { + var previous, result; + + result = undefined; + + previous = this.__current; + this.__current = element; + this.__state = null; + if (callback) { + result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node); + } + this.__current = previous; + + return result; + }; + + // API: + // notify control skip / break + Controller.prototype.notify = function notify(flag) { + this.__state = flag; + }; + + // API: + // skip child nodes of current node + Controller.prototype.skip = function () { + this.notify(SKIP); + }; + + // API: + // break traversals + Controller.prototype['break'] = function () { + this.notify(BREAK); + }; + + // API: + // remove node + Controller.prototype.remove = function () { + this.notify(REMOVE); + }; + + Controller.prototype.__initialize = function(root, visitor) { + this.visitor = visitor; + this.root = root; + this.__worklist = []; + this.__leavelist = []; + this.__current = null; + this.__state = null; + this.__fallback = visitor.fallback === 'iteration'; + this.__keys = VisitorKeys; + if (visitor.keys) { + this.__keys = extend(objectCreate(this.__keys), visitor.keys); + } + }; + + function isNode(node) { + if (node == null) { + return false; + } + return typeof node === 'object' && typeof node.type === 'string'; + } + + function isProperty(nodeType, key) { + return (nodeType === Syntax.ObjectExpression || nodeType === Syntax.ObjectPattern) && 'properties' === key; + } + + Controller.prototype.traverse = function traverse(root, visitor) { + var worklist, + leavelist, + element, + node, + nodeType, + ret, + key, + current, + current2, + candidates, + candidate, + sentinel; + + this.__initialize(root, visitor); + + sentinel = {}; + + // reference + worklist = this.__worklist; + leavelist = this.__leavelist; + + // initialize + worklist.push(new Element(root, null, null, null)); + leavelist.push(new Element(null, null, null, null)); + + while (worklist.length) { + element = worklist.pop(); + + if (element === sentinel) { + element = leavelist.pop(); + + ret = this.__execute(visitor.leave, element); + + if (this.__state === BREAK || ret === BREAK) { + return; + } + continue; + } + + if (element.node) { + + ret = this.__execute(visitor.enter, element); + + if (this.__state === BREAK || ret === BREAK) { + return; + } + + worklist.push(sentinel); + leavelist.push(element); + + if (this.__state === SKIP || ret === SKIP) { + continue; + } + + node = element.node; + nodeType = element.wrap || node.type; + candidates = this.__keys[nodeType]; + if (!candidates) { + if (this.__fallback) { + candidates = objectKeys(node); + } else { + throw new Error('Unknown node type ' + nodeType + '.'); + } + } + + current = candidates.length; + while ((current -= 1) >= 0) { + key = candidates[current]; + candidate = node[key]; + if (!candidate) { + continue; + } + + if (isArray(candidate)) { + current2 = candidate.length; + while ((current2 -= 1) >= 0) { + if (!candidate[current2]) { + continue; + } + if (isProperty(nodeType, candidates[current])) { + element = new Element(candidate[current2], [key, current2], 'Property', null); + } else if (isNode(candidate[current2])) { + element = new Element(candidate[current2], [key, current2], null, null); + } else { + continue; + } + worklist.push(element); + } + } else if (isNode(candidate)) { + worklist.push(new Element(candidate, key, null, null)); + } + } + } + } + }; + + Controller.prototype.replace = function replace(root, visitor) { + function removeElem(element) { + var i, + key, + nextElem, + parent; + + if (element.ref.remove()) { + // When the reference is an element of an array. + key = element.ref.key; + parent = element.ref.parent; + + // If removed from array, then decrease following items' keys. + i = worklist.length; + while (i--) { + nextElem = worklist[i]; + if (nextElem.ref && nextElem.ref.parent === parent) { + if (nextElem.ref.key < key) { + break; + } + --nextElem.ref.key; + } + } + } + } + + var worklist, + leavelist, + node, + nodeType, + target, + element, + current, + current2, + candidates, + candidate, + sentinel, + outer, + key; + + this.__initialize(root, visitor); + + sentinel = {}; + + // reference + worklist = this.__worklist; + leavelist = this.__leavelist; + + // initialize + outer = { + root: root + }; + element = new Element(root, null, null, new Reference(outer, 'root')); + worklist.push(element); + leavelist.push(element); + + while (worklist.length) { + element = worklist.pop(); + + if (element === sentinel) { + element = leavelist.pop(); + + target = this.__execute(visitor.leave, element); + + // node may be replaced with null, + // so distinguish between undefined and null in this place + if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) { + // replace + element.ref.replace(target); + } + + if (this.__state === REMOVE || target === REMOVE) { + removeElem(element); + } + + if (this.__state === BREAK || target === BREAK) { + return outer.root; + } + continue; + } + + target = this.__execute(visitor.enter, element); + + // node may be replaced with null, + // so distinguish between undefined and null in this place + if (target !== undefined && target !== BREAK && target !== SKIP && target !== REMOVE) { + // replace + element.ref.replace(target); + element.node = target; + } + + if (this.__state === REMOVE || target === REMOVE) { + removeElem(element); + element.node = null; + } + + if (this.__state === BREAK || target === BREAK) { + return outer.root; + } + + // node may be null + node = element.node; + if (!node) { + continue; + } + + worklist.push(sentinel); + leavelist.push(element); + + if (this.__state === SKIP || target === SKIP) { + continue; + } + + nodeType = element.wrap || node.type; + candidates = this.__keys[nodeType]; + if (!candidates) { + if (this.__fallback) { + candidates = objectKeys(node); + } else { + throw new Error('Unknown node type ' + nodeType + '.'); + } + } + + current = candidates.length; + while ((current -= 1) >= 0) { + key = candidates[current]; + candidate = node[key]; + if (!candidate) { + continue; + } + + if (isArray(candidate)) { + current2 = candidate.length; + while ((current2 -= 1) >= 0) { + if (!candidate[current2]) { + continue; + } + if (isProperty(nodeType, candidates[current])) { + element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2)); + } else if (isNode(candidate[current2])) { + element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2)); + } else { + continue; + } + worklist.push(element); + } + } else if (isNode(candidate)) { + worklist.push(new Element(candidate, key, null, new Reference(node, key))); + } + } + } + + return outer.root; + }; + + function traverse(root, visitor) { + var controller = new Controller(); + return controller.traverse(root, visitor); + } + + function replace(root, visitor) { + var controller = new Controller(); + return controller.replace(root, visitor); + } + + function extendCommentRange(comment, tokens) { + var target; + + target = upperBound(tokens, function search(token) { + return token.range[0] > comment.range[0]; + }); + + comment.extendedRange = [comment.range[0], comment.range[1]]; + + if (target !== tokens.length) { + comment.extendedRange[1] = tokens[target].range[0]; + } + + target -= 1; + if (target >= 0) { + comment.extendedRange[0] = tokens[target].range[1]; + } + + return comment; + } + + function attachComments(tree, providedComments, tokens) { + // At first, we should calculate extended comment ranges. + var comments = [], comment, len, i, cursor; + + if (!tree.range) { + throw new Error('attachComments needs range information'); + } + + // tokens array is empty, we attach comments to tree as 'leadingComments' + if (!tokens.length) { + if (providedComments.length) { + for (i = 0, len = providedComments.length; i < len; i += 1) { + comment = deepCopy(providedComments[i]); + comment.extendedRange = [0, tree.range[0]]; + comments.push(comment); + } + tree.leadingComments = comments; + } + return tree; + } + + for (i = 0, len = providedComments.length; i < len; i += 1) { + comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); + } + + // This is based on John Freeman's implementation. + cursor = 0; + traverse(tree, { + enter: function (node) { + var comment; + + while (cursor < comments.length) { + comment = comments[cursor]; + if (comment.extendedRange[1] > node.range[0]) { + break; + } + + if (comment.extendedRange[1] === node.range[0]) { + if (!node.leadingComments) { + node.leadingComments = []; + } + node.leadingComments.push(comment); + comments.splice(cursor, 1); + } else { + cursor += 1; + } + } + + // already out of owned node + if (cursor === comments.length) { + return VisitorOption.Break; + } + + if (comments[cursor].extendedRange[0] > node.range[1]) { + return VisitorOption.Skip; + } + } + }); + + cursor = 0; + traverse(tree, { + leave: function (node) { + var comment; + + while (cursor < comments.length) { + comment = comments[cursor]; + if (node.range[1] < comment.extendedRange[0]) { + break; + } + + if (node.range[1] === comment.extendedRange[0]) { + if (!node.trailingComments) { + node.trailingComments = []; + } + node.trailingComments.push(comment); + comments.splice(cursor, 1); + } else { + cursor += 1; + } + } + + // already out of owned node + if (cursor === comments.length) { + return VisitorOption.Break; + } + + if (comments[cursor].extendedRange[0] > node.range[1]) { + return VisitorOption.Skip; + } + } + }); + + return tree; + } + + exports.version = require('./package.json').version; + exports.Syntax = Syntax; + exports.traverse = traverse; + exports.replace = replace; + exports.attachComments = attachComments; + exports.VisitorKeys = VisitorKeys; + exports.VisitorOption = VisitorOption; + exports.Controller = Controller; + exports.cloneEnvironment = function () { return clone({}); }; + + return exports; +}(exports)); +/* vim: set sw=4 ts=4 et tw=80 : */ + +},{"./package.json":86}],86:[function(require,module,exports){ module.exports={ - "name": "esrecurse", - "description": "ECMAScript scope analyzer", - "homepage": "http://github.com/estools/esrecurse", - "main": "esrecurse.js", - "version": "1.2.0", + "_args": [ + [ + "estraverse@~3.1.0", + "/Users/force/code/eslint/node_modules/esrecurse" + ] + ], + "_from": "estraverse@>=3.1.0 <3.2.0", + "_id": "estraverse@3.1.0", + "_inCache": true, + "_installable": true, + "_location": "/esrecurse/estraverse", + "_npmUser": { + "email": "utatane.tea@gmail.com", + "name": "constellation" + }, + "_npmVersion": "2.0.0-alpha-5", + "_phantomChildren": {}, + "_requested": { + "name": "estraverse", + "raw": "estraverse@~3.1.0", + "rawSpec": "~3.1.0", + "scope": null, + "spec": ">=3.1.0 <3.2.0", + "type": "range" + }, + "_requiredBy": [ + "/esrecurse" + ], + "_resolved": "https://registry.npmjs.org/estraverse/-/estraverse-3.1.0.tgz", + "_shasum": "15e28a446b8b82bc700ccc8b96c78af4da0d6cba", + "_shrinkwrap": null, + "_spec": "estraverse@~3.1.0", + "_where": "/Users/force/code/eslint/node_modules/esrecurse", + "bugs": { + "url": "https://github.com/estools/estraverse/issues" + }, + "dependencies": {}, + "description": "ECMAScript JS AST traversal functions", + "devDependencies": { + "chai": "^2.1.1", + "coffee-script": "^1.8.0", + "espree": "^1.11.0", + "gulp": "^3.8.10", + "gulp-bump": "^0.2.2", + "gulp-filter": "^2.0.0", + "gulp-git": "^1.0.1", + "gulp-tag-version": "^1.2.1", + "jshint": "^2.5.6", + "mocha": "^2.1.0" + }, + "directories": {}, + "dist": { + "shasum": "15e28a446b8b82bc700ccc8b96c78af4da0d6cba", + "tarball": "http://registry.npmjs.org/estraverse/-/estraverse-3.1.0.tgz" + }, "engines": { "node": ">=0.10.0" }, + "gitHead": "166ebbe0a8d45ceb2391b6f5ef5d1bab6bfb267a", + "homepage": "https://github.com/estools/estraverse", + "licenses": [ + { + "type": "BSD", + "url": "http://github.com/estools/estraverse/raw/master/LICENSE.BSD" + } + ], + "main": "estraverse.js", "maintainers": [ { "name": "constellation", "email": "utatane.tea@gmail.com" + }, + { + "name": "michaelficarra", + "email": "npm@michael.ficarra.me" } ], + "name": "estraverse", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", "repository": { "type": "git", - "url": "http://github.com/estools/esrecurse.git" + "url": "git+ssh://git@github.com/estools/estraverse.git" }, + "scripts": { + "lint": "jshint estraverse.js", + "test": "npm run-script lint && npm run-script unit-test", + "unit-test": "mocha --compilers coffee:coffee-script/register" + }, + "version": "3.1.0" +} + +},{}],87:[function(require,module,exports){ +module.exports={ + "_args": [ + [ + "esrecurse@^3.1.1", + "/Users/force/code/eslint/node_modules/escope" + ] + ], + "_from": "esrecurse@>=3.1.1 <4.0.0", + "_id": "esrecurse@3.1.1", + "_inCache": true, + "_installable": true, + "_location": "/esrecurse", + "_npmUser": { + "email": "utatane.tea@gmail.com", + "name": "constellation" + }, + "_npmVersion": "2.0.0-alpha-5", + "_phantomChildren": {}, + "_requested": { + "name": "esrecurse", + "raw": "esrecurse@^3.1.1", + "rawSpec": "^3.1.1", + "scope": null, + "spec": ">=3.1.1 <4.0.0", + "type": "range" + }, + "_requiredBy": [ + "/escope" + ], + "_resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-3.1.1.tgz", + "_shasum": "8feb963699d4d1b2d65a576cd4b1296672a0f0e9", + "_shrinkwrap": null, + "_spec": "esrecurse@^3.1.1", + "_where": "/Users/force/code/eslint/node_modules/escope", + "bugs": { + "url": "https://github.com/estools/esrecurse/issues" + }, "dependencies": { - "estraverse": ">=1.9.0" + "estraverse": "~3.1.0" }, + "description": "ECMAScript scope analyzer", "devDependencies": { - "chai": "~1.10.0", - "coffee-script": "~1.8.0", - "esprima": "~1.2.2", + "chai": "^2.1.1", + "coffee-script": "^1.9.1", + "esprima": "^2.1.0", "gulp": "~3.8.10", - "gulp-eslint": "^0.2.0", + "gulp-bump": "^0.2.2", + "gulp-eslint": "^0.6.0", + "gulp-filter": "^2.0.2", + "gulp-git": "^1.1.0", "gulp-mocha": "~2.0.0", + "gulp-tag-version": "^1.2.1", "jsdoc": "~3.3.0-alpha10", "minimist": "^1.1.0" }, + "directories": {}, + "dist": { + "shasum": "8feb963699d4d1b2d65a576cd4b1296672a0f0e9", + "tarball": "http://registry.npmjs.org/esrecurse/-/esrecurse-3.1.1.tgz" + }, + "engines": { + "node": ">=0.10.0" + }, + "gitHead": "600a8aac5e7b313875a873134fd110b47a76fc77", + "homepage": "http://github.com/estools/esrecurse", "licenses": [ { "type": "BSD", "url": "http://github.com/estools/esrecurse/raw/master/LICENSE.BSD" } ], - "scripts": { - "test": "gulp travis", - "unit-test": "gulp test", - "lint": "gulp lint" - }, - "gitHead": "9b363cee6d6b6b29b5236f4b98066ba0735fe9e4", - "bugs": { - "url": "https://github.com/estools/esrecurse/issues" - }, - "_id": "esrecurse@1.2.0", - "_shasum": "25e3b3ab76ad8a1da2d38e9393fd76b8456a706f", - "_from": "esrecurse@>=1.2.0 <2.0.0", - "_npmVersion": "2.0.0-alpha-5", - "_npmUser": { - "name": "constellation", - "email": "utatane.tea@gmail.com" - }, - "dist": { - "shasum": "25e3b3ab76ad8a1da2d38e9393fd76b8456a706f", - "tarball": "http://registry.npmjs.org/esrecurse/-/esrecurse-1.2.0.tgz" - }, - "_resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-1.2.0.tgz", - "readme": "ERROR: No README data found!" -} - -},{}],123:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -module.exports = extend; -function extend(origin, add) { - // Don't do anything if add isn't an object - if (!add || typeof add !== 'object') return origin; - - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; -} - -},{}],124:[function(require,module,exports){ -module.exports={ - "name": "escope", - "description": "ECMAScript scope analyzer", - "homepage": "http://github.com/estools/escope.html", - "main": "escope.js", - "version": "2.0.6", - "engines": { - "node": ">=0.4.0" - }, + "main": "esrecurse.js", "maintainers": [ { "name": "constellation", "email": "utatane.tea@gmail.com" + }, + { + "name": "michaelficarra", + "email": "npm@michael.ficarra.me" } ], + "name": "esrecurse", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", "repository": { "type": "git", - "url": "http://github.com/estools/escope.git" + "url": "git+ssh://git@github.com/estools/esrecurse.git" }, - "dependencies": { - "es6-map": "^0.1.1", - "es6-weak-map": "^0.1.2", - "esrecurse": "^1.2.0", - "estraverse": ">=1.9.0", - "util-extend": "^1.0.1" - }, - "devDependencies": { - "browserify": "^7.0.0", - "chai": "~1.10.0", - "coffee-script": "~1.8.0", - "esprima": "~1.2.2", - "gulp": "~3.8.10", - "gulp-eslint": "^0.2.0", - "gulp-mocha": "~2.0.0", - "jsdoc": "~3.3.0-alpha10", - "minimist": "^1.1.0", - "vinyl-source-stream": "^1.0.0" - }, - "licenses": [ - { - "type": "BSD", - "url": "http://github.com/estools/escope/raw/master/LICENSE.BSD" - } - ], "scripts": { - "test": "gulp travis", - "unit-test": "gulp test", "lint": "gulp lint", - "jsdoc": "jsdoc escope.js README.md" + "test": "gulp travis", + "unit-test": "gulp test" }, - "gitHead": "dc4b85631e98011268fc426dd824c74e353d5b48", - "bugs": { - "url": "https://github.com/estools/escope/issues" - }, - "_id": "escope@2.0.6", - "_shasum": "c1bac24870605bb384ba073dce0417c9305eddeb", - "_from": "escope@2.0.6", - "_npmVersion": "1.4.28", - "_npmUser": { - "name": "constellation", - "email": "utatane.tea@gmail.com" - }, - "dist": { - "shasum": "c1bac24870605bb384ba073dce0417c9305eddeb", - "tarball": "http://registry.npmjs.org/escope/-/escope-2.0.6.tgz" - }, - "_resolved": "https://registry.npmjs.org/escope/-/escope-2.0.6.tgz", - "readme": "ERROR: No README data found!" + "version": "3.1.1" } -},{}],125:[function(require,module,exports){ -var estraverse = module.exports = require('estraverse'); - -var VisitorKeys = require('./keys'); - -for (var nodeType in VisitorKeys) { - estraverse.Syntax[nodeType] = nodeType; - - var keys = VisitorKeys[nodeType]; - - if (keys) { - estraverse.VisitorKeys[nodeType] = keys; - } -} -},{"./keys":126,"estraverse":127}],126:[function(require,module,exports){ +},{}],88:[function(require,module,exports){ var unprefixedKeys = { Identifier: [], NamespacedName: ['namespace', 'name'], MemberExpression: ['object', 'property'], EmptyExpression: [], @@ -15157,11 +16572,11 @@ } for (var key in flowKeys) { exports[key] = flowKeys[key]; } -},{}],127:[function(require,module,exports){ +},{}],89:[function(require,module,exports){ /* Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com> Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com> Redistribution and use in source and binary forms, with or without @@ -15345,10 +16760,11 @@ ImportSpecifier: 'ImportSpecifier', Literal: 'Literal', LabeledStatement: 'LabeledStatement', LogicalExpression: 'LogicalExpression', MemberExpression: 'MemberExpression', + MetaProperty: 'MetaProperty', MethodDefinition: 'MethodDefinition', ModuleSpecifier: 'ModuleSpecifier', NewExpression: 'NewExpression', ObjectExpression: 'ObjectExpression', ObjectPattern: 'ObjectPattern', @@ -15356,10 +16772,11 @@ Property: 'Property', RestElement: 'RestElement', ReturnStatement: 'ReturnStatement', SequenceExpression: 'SequenceExpression', SpreadElement: 'SpreadElement', + Super: 'Super', SwitchStatement: 'SwitchStatement', SwitchCase: 'SwitchCase', TaggedTemplateExpression: 'TaggedTemplateExpression', TemplateElement: 'TemplateElement', TemplateLiteral: 'TemplateLiteral', @@ -15378,11 +16795,11 @@ VisitorKeys = { AssignmentExpression: ['left', 'right'], AssignmentPattern: ['left', 'right'], ArrayExpression: ['elements'], ArrayPattern: ['elements'], - ArrowFunctionExpression: ['params', 'defaults', 'rest', 'body'], + ArrowFunctionExpression: ['params', 'body'], AwaitExpression: ['argument'], // CAUTION: It's deferred to ES7. BlockStatement: ['body'], BinaryExpression: ['left', 'right'], BreakStatement: ['label'], CallExpression: ['callee', 'arguments'], @@ -15404,12 +16821,12 @@ ExportSpecifier: ['exported', 'local'], ExpressionStatement: ['expression'], ForStatement: ['init', 'test', 'update', 'body'], ForInStatement: ['left', 'right', 'body'], ForOfStatement: ['left', 'right', 'body'], - FunctionDeclaration: ['id', 'params', 'defaults', 'rest', 'body'], - FunctionExpression: ['id', 'params', 'defaults', 'rest', 'body'], + FunctionDeclaration: ['id', 'params', 'body'], + FunctionExpression: ['id', 'params', 'body'], GeneratorExpression: ['blocks', 'filter', 'body'], // CAUTION: It's deferred to ES7. Identifier: [], IfStatement: ['test', 'consequent', 'alternate'], ImportDeclaration: ['specifiers', 'source'], ImportDefaultSpecifier: ['local'], @@ -15417,10 +16834,11 @@ ImportSpecifier: ['imported', 'local'], Literal: [], LabeledStatement: ['label', 'body'], LogicalExpression: ['left', 'right'], MemberExpression: ['object', 'property'], + MetaProperty: ['meta', 'property'], MethodDefinition: ['key', 'value'], ModuleSpecifier: [], NewExpression: ['callee', 'arguments'], ObjectExpression: ['properties'], ObjectPattern: ['properties'], @@ -15428,18 +16846,19 @@ Property: ['key', 'value'], RestElement: [ 'argument' ], ReturnStatement: ['argument'], SequenceExpression: ['expressions'], SpreadElement: ['argument'], + Super: [], SwitchStatement: ['discriminant', 'cases'], SwitchCase: ['test', 'consequent'], TaggedTemplateExpression: ['tag', 'quasi'], TemplateElement: [], TemplateLiteral: ['quasis', 'expressions'], ThisExpression: [], ThrowStatement: ['argument'], - TryStatement: ['block', 'handlers', 'handler', 'guardedHandlers', 'finalizer'], + TryStatement: ['block', 'handler', 'finalizer'], UnaryExpression: ['argument'], UpdateExpression: ['argument'], VariableDeclaration: ['declarations'], VariableDeclarator: ['id', 'init'], WhileStatement: ['test', 'body'], @@ -15662,11 +17081,11 @@ if (this.__state === SKIP || ret === SKIP) { continue; } node = element.node; - nodeType = element.wrap || node.type; + nodeType = node.type || element.wrap; candidates = this.__keys[nodeType]; if (!candidates) { if (this.__fallback) { candidates = objectKeys(node); } else { @@ -15816,11 +17235,11 @@ if (this.__state === SKIP || target === SKIP) { continue; } - nodeType = element.wrap || node.type; + nodeType = node.type || element.wrap; candidates = this.__keys[nodeType]; if (!candidates) { if (this.__fallback) { candidates = objectKeys(node); } else { @@ -15998,30 +17417,52 @@ return exports; }(exports)); /* vim: set sw=4 ts=4 et tw=80 : */ -},{"./package.json":128}],128:[function(require,module,exports){ +},{"./package.json":90}],90:[function(require,module,exports){ module.exports={ - "name": "estraverse", - "description": "ECMAScript JS AST traversal functions", - "homepage": "https://github.com/estools/estraverse", - "main": "estraverse.js", - "version": "2.0.0", - "engines": { - "node": ">=0.10.0" + "_args": [ + [ + "estraverse@^4.1.1", + "/Users/force/code/eslint" + ] + ], + "_from": "estraverse@>=4.1.1 <5.0.0", + "_id": "estraverse@4.1.1", + "_inCache": true, + "_installable": true, + "_location": "/estraverse", + "_nodeVersion": "4.1.1", + "_npmUser": { + "email": "utatane.tea@gmail.com", + "name": "constellation" }, - "maintainers": [ - { - "name": "constellation", - "email": "utatane.tea@gmail.com" - } + "_npmVersion": "2.14.4", + "_phantomChildren": {}, + "_requested": { + "name": "estraverse", + "raw": "estraverse@^4.1.1", + "rawSpec": "^4.1.1", + "scope": null, + "spec": ">=4.1.1 <5.0.0", + "type": "range" + }, + "_requiredBy": [ + "/", + "/escope" ], - "repository": { - "type": "git", - "url": "http://github.com/estools/estraverse.git" + "_resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz", + "_shasum": "f6caca728933a850ef90661d0e17982ba47111a2", + "_shrinkwrap": null, + "_spec": "estraverse@^4.1.1", + "_where": "/Users/force/code/eslint", + "bugs": { + "url": "https://github.com/estools/estraverse/issues" }, + "dependencies": {}, + "description": "ECMAScript JS AST traversal functions", "devDependencies": { "chai": "^2.1.1", "coffee-script": "^1.8.0", "espree": "^1.11.0", "gulp": "^3.8.10", @@ -16030,54 +17471,885 @@ "gulp-git": "^1.0.1", "gulp-tag-version": "^1.2.1", "jshint": "^2.5.6", "mocha": "^2.1.0" }, - "licenses": [ + "directories": {}, + "dist": { + "shasum": "f6caca728933a850ef90661d0e17982ba47111a2", + "tarball": "http://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz" + }, + "engines": { + "node": ">=0.10.0" + }, + "gitHead": "bbcccbfe98296585e4311c8755e1d00dcd581e3c", + "homepage": "https://github.com/estools/estraverse", + "license": "BSD-2-Clause", + "main": "estraverse.js", + "maintainers": [ { - "type": "BSD", - "url": "http://github.com/estools/estraverse/raw/master/LICENSE.BSD" + "name": "constellation", + "email": "utatane.tea@gmail.com" + }, + { + "name": "michaelficarra", + "email": "npm@michael.ficarra.me" + }, + { + "name": "nzakas", + "email": "nicholas@nczconsulting.com" } ], + "name": "estraverse", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/estools/estraverse.git" + }, "scripts": { - "test": "npm run-script lint && npm run-script unit-test", "lint": "jshint estraverse.js", + "test": "npm run-script lint && npm run-script unit-test", "unit-test": "mocha --compilers coffee:coffee-script/register" }, - "gitHead": "d8bc726f126817cc03c7a4e751528edb19db0ffb", - "bugs": { - "url": "https://github.com/estools/estraverse/issues" - }, - "_id": "estraverse@2.0.0", - "_shasum": "5ae46963243600206674ccb24a09e16674fcdca1", - "_from": "estraverse@>=2.0.0 <3.0.0", - "_npmVersion": "2.0.0-alpha-5", - "_npmUser": { - "name": "constellation", - "email": "utatane.tea@gmail.com" - }, - "dist": { - "shasum": "5ae46963243600206674ccb24a09e16674fcdca1", - "tarball": "http://registry.npmjs.org/estraverse/-/estraverse-2.0.0.tgz" - }, - "_resolved": "https://registry.npmjs.org/estraverse/-/estraverse-2.0.0.tgz", - "readme": "ERROR: No README data found!" + "version": "4.1.1" } -},{}],129:[function(require,module,exports){ +},{}],91:[function(require,module,exports){ +arguments[4][13][0].apply(exports,arguments) +},{"dup":13}],92:[function(require,module,exports){ +/* + Copyright (C) 2013-2014 Yusuke Suzuki <utatane.tea@gmail.com> + Copyright (C) 2014 Ivan Nikulin <ifaaan@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. +*/ + +(function () { + 'use strict'; + + var ES6Regex, ES5Regex, NON_ASCII_WHITESPACES, IDENTIFIER_START, IDENTIFIER_PART, ch; + + // See `tools/generate-identifier-regex.js`. + ES5Regex = { + // ECMAScript 5.1/Unicode v7.0.0 NonAsciiIdentifierStart: + NonAsciiIdentifierStart: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/, + // ECMAScript 5.1/Unicode v7.0.0 NonAsciiIdentifierPart: + NonAsciiIdentifierPart: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/ + }; + + ES6Regex = { + // ECMAScript 6/Unicode v7.0.0 NonAsciiIdentifierStart: + NonAsciiIdentifierStart: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDE00-\uDE11\uDE13-\uDE2B\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDE00-\uDE2F\uDE44\uDE80-\uDEAA]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF98]|\uD809[\uDC00-\uDC6E]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D]/, + // ECMAScript 6/Unicode v7.0.0 NonAsciiIdentifierPart: + NonAsciiIdentifierPart: /[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDD0-\uDDDA\uDE00-\uDE11\uDE13-\uDE37\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF01-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF98]|\uD809[\uDC00-\uDC6E]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/ + }; + + function isDecimalDigit(ch) { + return 0x30 <= ch && ch <= 0x39; // 0..9 + } + + function isHexDigit(ch) { + return 0x30 <= ch && ch <= 0x39 || // 0..9 + 0x61 <= ch && ch <= 0x66 || // a..f + 0x41 <= ch && ch <= 0x46; // A..F + } + + function isOctalDigit(ch) { + return ch >= 0x30 && ch <= 0x37; // 0..7 + } + + // 7.2 White Space + + NON_ASCII_WHITESPACES = [ + 0x1680, 0x180E, + 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, + 0x202F, 0x205F, + 0x3000, + 0xFEFF + ]; + + function isWhiteSpace(ch) { + return ch === 0x20 || ch === 0x09 || ch === 0x0B || ch === 0x0C || ch === 0xA0 || + ch >= 0x1680 && NON_ASCII_WHITESPACES.indexOf(ch) >= 0; + } + + // 7.3 Line Terminators + + function isLineTerminator(ch) { + return ch === 0x0A || ch === 0x0D || ch === 0x2028 || ch === 0x2029; + } + + // 7.6 Identifier Names and Identifiers + + function fromCodePoint(cp) { + if (cp <= 0xFFFF) { return String.fromCharCode(cp); } + var cu1 = String.fromCharCode(Math.floor((cp - 0x10000) / 0x400) + 0xD800); + var cu2 = String.fromCharCode(((cp - 0x10000) % 0x400) + 0xDC00); + return cu1 + cu2; + } + + IDENTIFIER_START = new Array(0x80); + for(ch = 0; ch < 0x80; ++ch) { + IDENTIFIER_START[ch] = + ch >= 0x61 && ch <= 0x7A || // a..z + ch >= 0x41 && ch <= 0x5A || // A..Z + ch === 0x24 || ch === 0x5F; // $ (dollar) and _ (underscore) + } + + IDENTIFIER_PART = new Array(0x80); + for(ch = 0; ch < 0x80; ++ch) { + IDENTIFIER_PART[ch] = + ch >= 0x61 && ch <= 0x7A || // a..z + ch >= 0x41 && ch <= 0x5A || // A..Z + ch >= 0x30 && ch <= 0x39 || // 0..9 + ch === 0x24 || ch === 0x5F; // $ (dollar) and _ (underscore) + } + + function isIdentifierStartES5(ch) { + return ch < 0x80 ? IDENTIFIER_START[ch] : ES5Regex.NonAsciiIdentifierStart.test(fromCodePoint(ch)); + } + + function isIdentifierPartES5(ch) { + return ch < 0x80 ? IDENTIFIER_PART[ch] : ES5Regex.NonAsciiIdentifierPart.test(fromCodePoint(ch)); + } + + function isIdentifierStartES6(ch) { + return ch < 0x80 ? IDENTIFIER_START[ch] : ES6Regex.NonAsciiIdentifierStart.test(fromCodePoint(ch)); + } + + function isIdentifierPartES6(ch) { + return ch < 0x80 ? IDENTIFIER_PART[ch] : ES6Regex.NonAsciiIdentifierPart.test(fromCodePoint(ch)); + } + + module.exports = { + isDecimalDigit: isDecimalDigit, + isHexDigit: isHexDigit, + isOctalDigit: isOctalDigit, + isWhiteSpace: isWhiteSpace, + isLineTerminator: isLineTerminator, + isIdentifierStartES5: isIdentifierStartES5, + isIdentifierPartES5: isIdentifierPartES5, + isIdentifierStartES6: isIdentifierStartES6, + isIdentifierPartES6: isIdentifierPartES6 + }; +}()); +/* vim: set sw=4 ts=4 et tw=80 : */ + +},{}],93:[function(require,module,exports){ +/* + Copyright (C) 2013 Yusuke Suzuki <utatane.tea@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. +*/ + +(function () { + 'use strict'; + + var code = require('./code'); + + function isStrictModeReservedWordES6(id) { + switch (id) { + case 'implements': + case 'interface': + case 'package': + case 'private': + case 'protected': + case 'public': + case 'static': + case 'let': + return true; + default: + return false; + } + } + + function isKeywordES5(id, strict) { + // yield should not be treated as keyword under non-strict mode. + if (!strict && id === 'yield') { + return false; + } + return isKeywordES6(id, strict); + } + + function isKeywordES6(id, strict) { + if (strict && isStrictModeReservedWordES6(id)) { + return true; + } + + switch (id.length) { + case 2: + return (id === 'if') || (id === 'in') || (id === 'do'); + case 3: + return (id === 'var') || (id === 'for') || (id === 'new') || (id === 'try'); + case 4: + return (id === 'this') || (id === 'else') || (id === 'case') || + (id === 'void') || (id === 'with') || (id === 'enum'); + case 5: + return (id === 'while') || (id === 'break') || (id === 'catch') || + (id === 'throw') || (id === 'const') || (id === 'yield') || + (id === 'class') || (id === 'super'); + case 6: + return (id === 'return') || (id === 'typeof') || (id === 'delete') || + (id === 'switch') || (id === 'export') || (id === 'import'); + case 7: + return (id === 'default') || (id === 'finally') || (id === 'extends'); + case 8: + return (id === 'function') || (id === 'continue') || (id === 'debugger'); + case 10: + return (id === 'instanceof'); + default: + return false; + } + } + + function isReservedWordES5(id, strict) { + return id === 'null' || id === 'true' || id === 'false' || isKeywordES5(id, strict); + } + + function isReservedWordES6(id, strict) { + return id === 'null' || id === 'true' || id === 'false' || isKeywordES6(id, strict); + } + + function isRestrictedWord(id) { + return id === 'eval' || id === 'arguments'; + } + + function isIdentifierNameES5(id) { + var i, iz, ch; + + if (id.length === 0) { return false; } + + ch = id.charCodeAt(0); + if (!code.isIdentifierStartES5(ch)) { + return false; + } + + for (i = 1, iz = id.length; i < iz; ++i) { + ch = id.charCodeAt(i); + if (!code.isIdentifierPartES5(ch)) { + return false; + } + } + return true; + } + + function decodeUtf16(lead, trail) { + return (lead - 0xD800) * 0x400 + (trail - 0xDC00) + 0x10000; + } + + function isIdentifierNameES6(id) { + var i, iz, ch, lowCh, check; + + if (id.length === 0) { return false; } + + check = code.isIdentifierStartES6; + for (i = 0, iz = id.length; i < iz; ++i) { + ch = id.charCodeAt(i); + if (0xD800 <= ch && ch <= 0xDBFF) { + ++i; + if (i >= iz) { return false; } + lowCh = id.charCodeAt(i); + if (!(0xDC00 <= lowCh && lowCh <= 0xDFFF)) { + return false; + } + ch = decodeUtf16(ch, lowCh); + } + if (!check(ch)) { + return false; + } + check = code.isIdentifierPartES6; + } + return true; + } + + function isIdentifierES5(id, strict) { + return isIdentifierNameES5(id) && !isReservedWordES5(id, strict); + } + + function isIdentifierES6(id, strict) { + return isIdentifierNameES6(id) && !isReservedWordES6(id, strict); + } + + module.exports = { + isKeywordES5: isKeywordES5, + isKeywordES6: isKeywordES6, + isReservedWordES5: isReservedWordES5, + isReservedWordES6: isReservedWordES6, + isRestrictedWord: isRestrictedWord, + isIdentifierNameES5: isIdentifierNameES5, + isIdentifierNameES6: isIdentifierNameES6, + isIdentifierES5: isIdentifierES5, + isIdentifierES6: isIdentifierES6 + }; +}()); +/* vim: set sw=4 ts=4 et tw=80 : */ + +},{"./code":92}],94:[function(require,module,exports){ +arguments[4][16][0].apply(exports,arguments) +},{"./ast":91,"./code":92,"./keyword":93,"dup":16}],95:[function(require,module,exports){ +'use strict'; + +var d = require('d') + , callable = require('es5-ext/object/valid-callable') + + , apply = Function.prototype.apply, call = Function.prototype.call + , create = Object.create, defineProperty = Object.defineProperty + , defineProperties = Object.defineProperties + , hasOwnProperty = Object.prototype.hasOwnProperty + , descriptor = { configurable: true, enumerable: false, writable: true } + + , on, once, off, emit, methods, descriptors, base; + +on = function (type, listener) { + var data; + + callable(listener); + + if (!hasOwnProperty.call(this, '__ee__')) { + data = descriptor.value = create(null); + defineProperty(this, '__ee__', descriptor); + descriptor.value = null; + } else { + data = this.__ee__; + } + if (!data[type]) data[type] = listener; + else if (typeof data[type] === 'object') data[type].push(listener); + else data[type] = [data[type], listener]; + + return this; +}; + +once = function (type, listener) { + var once, self; + + callable(listener); + self = this; + on.call(this, type, once = function () { + off.call(self, type, once); + apply.call(listener, this, arguments); + }); + + once.__eeOnceListener__ = listener; + return this; +}; + +off = function (type, listener) { + var data, listeners, candidate, i; + + callable(listener); + + if (!hasOwnProperty.call(this, '__ee__')) return this; + data = this.__ee__; + if (!data[type]) return this; + listeners = data[type]; + + if (typeof listeners === 'object') { + for (i = 0; (candidate = listeners[i]); ++i) { + if ((candidate === listener) || + (candidate.__eeOnceListener__ === listener)) { + if (listeners.length === 2) data[type] = listeners[i ? 0 : 1]; + else listeners.splice(i, 1); + } + } + } else { + if ((listeners === listener) || + (listeners.__eeOnceListener__ === listener)) { + delete data[type]; + } + } + + return this; +}; + +emit = function (type) { + var i, l, listener, listeners, args; + + if (!hasOwnProperty.call(this, '__ee__')) return; + listeners = this.__ee__[type]; + if (!listeners) return; + + if (typeof listeners === 'object') { + l = arguments.length; + args = new Array(l - 1); + for (i = 1; i < l; ++i) args[i - 1] = arguments[i]; + + listeners = listeners.slice(); + for (i = 0; (listener = listeners[i]); ++i) { + apply.call(listener, this, args); + } + } else { + switch (arguments.length) { + case 1: + call.call(listeners, this); + break; + case 2: + call.call(listeners, this, arguments[1]); + break; + case 3: + call.call(listeners, this, arguments[1], arguments[2]); + break; + default: + l = arguments.length; + args = new Array(l - 1); + for (i = 1; i < l; ++i) { + args[i - 1] = arguments[i]; + } + apply.call(listeners, this, args); + } + } +}; + +methods = { + on: on, + once: once, + off: off, + emit: emit +}; + +descriptors = { + on: d(on), + once: d(once), + off: d(off), + emit: d(emit) +}; + +base = defineProperties({}, descriptors); + +module.exports = exports = function (o) { + return (o == null) ? create(base) : defineProperties(Object(o), descriptors); +}; +exports.methods = methods; + +},{"d":7,"es5-ext/object/valid-callable":44}],96:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +EventEmitter.defaultMaxListeners = 10; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) + throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; +}; + +EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; + + if (!this._events) + this._events = {}; + + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || + (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } + throw TypeError('Uncaught, unspecified "error" event.'); + } + } + + handler = this._events[type]; + + if (isUndefined(handler)) + return false; + + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + args = Array.prototype.slice.call(arguments, 1); + handler.apply(this, args); + } + } else if (isObject(handler)) { + args = Array.prototype.slice.call(arguments, 1); + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) + listeners[i].apply(this, args); + } + + return true; +}; + +EventEmitter.prototype.addListener = function(type, listener) { + var m; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events) + this._events = {}; + + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, + isFunction(listener.listener) ? + listener.listener : listener); + + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + else + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; + } else { + m = EventEmitter.defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } + } + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + var fired = false; + + function g() { + this.removeListener(type, g); + + if (!fired) { + fired = true; + listener.apply(this, arguments); + } + } + + g.listener = listener; + this.on(type, g); + + return this; +}; + +// emits a 'removeListener' event iff the listener was removed +EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events || !this._events[type]) + return this; + + list = this._events[type]; + length = list.length; + position = -1; + + if (list === listener || + (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) + this.emit('removeListener', type, listener); + + } else if (isObject(list)) { + for (i = length; i-- > 0;) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) { + position = i; + break; + } + } + + if (position < 0) + return this; + + if (list.length === 1) { + list.length = 0; + delete this._events[type]; + } else { + list.splice(position, 1); + } + + if (this._events.removeListener) + this.emit('removeListener', type, listener); + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; + + if (!this._events) + return this; + + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) + this._events = {}; + else if (this._events[type]) + delete this._events[type]; + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } + + listeners = this._events[type]; + + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else if (listeners) { + // LIFO order + while (listeners.length) + this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; + + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) + ret = []; + else if (isFunction(this._events[type])) + ret = [this._events[type]]; + else + ret = this._events[type].slice(); + return ret; +}; + +EventEmitter.prototype.listenerCount = function(type) { + if (this._events) { + var evlistener = this._events[type]; + + if (isFunction(evlistener)) + return 1; + else if (evlistener) + return evlistener.length; + } + return 0; +}; + +EventEmitter.listenerCount = function(emitter, type) { + return emitter.listenerCount(type); +}; + +function isFunction(arg) { + return typeof arg === 'function'; +} + +function isNumber(arg) { + return typeof arg === 'number'; +} + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} + +function isUndefined(arg) { + return arg === void 0; +} + +},{}],97:[function(require,module,exports){ +var util = require('util') + +var INDENT_START = /[\{\[]/ +var INDENT_END = /[\}\]]/ + +module.exports = function() { + var lines = [] + var indent = 0 + + var push = function(str) { + var spaces = '' + while (spaces.length < indent*2) spaces += ' ' + lines.push(spaces+str) + } + + var line = function(fmt) { + if (!fmt) return line + + if (INDENT_END.test(fmt.trim()[0]) && INDENT_START.test(fmt[fmt.length-1])) { + indent-- + push(util.format.apply(util, arguments)) + indent++ + return line + } + if (INDENT_START.test(fmt[fmt.length-1])) { + push(util.format.apply(util, arguments)) + indent++ + return line + } + if (INDENT_END.test(fmt.trim()[0])) { + indent-- + push(util.format.apply(util, arguments)) + return line + } + + push(util.format.apply(util, arguments)) + return line + } + + line.toString = function() { + return lines.join('\n') + } + + line.toFunction = function(scope) { + var src = 'return ('+line.toString()+')' + + var keys = Object.keys(scope || {}).map(function(key) { + return key + }) + + var vals = keys.map(function(key) { + return scope[key] + }) + + return Function.apply(null, keys.concat(src)).apply(null, vals) + } + + if (arguments.length) line.apply(null, arguments) + + return line +} + +},{"util":111}],98:[function(require,module,exports){ +var isProperty = require('is-property') + +var gen = function(obj, prop) { + return isProperty(prop) ? obj+'.'+prop : obj+'['+JSON.stringify(prop)+']' +} + +gen.valid = isProperty +gen.property = function (prop) { + return isProperty(prop) ? prop : JSON.stringify(prop) +} + +module.exports = gen + +},{"is-property":104}],99:[function(require,module,exports){ module.exports={ "builtin": { "Array": false, "ArrayBuffer": false, "Boolean": false, "constructor": false, + "DataView": false, "Date": false, "decodeURI": false, "decodeURIComponent": false, "encodeURI": false, "encodeURIComponent": false, "Error": false, + "escape": false, "eval": false, "EvalError": false, "Float32Array": false, "Float64Array": false, "Function": false, @@ -16115,86 +18387,167 @@ "Uint16Array": false, "Uint32Array": false, "Uint8Array": false, "Uint8ClampedArray": false, "undefined": false, + "unescape": false, "URIError": false, "valueOf": false, "WeakMap": false, "WeakSet": false }, - "nonstandard": { - "escape": false, - "unescape": false - }, "browser": { "addEventListener": false, "alert": false, + "AnalyserNode": false, + "AnimationEvent": false, "applicationCache": false, + "ApplicationCache": false, + "ApplicationCacheErrorEvent": false, "atob": false, + "Attr": false, "Audio": false, + "AudioBuffer": false, + "AudioBufferSourceNode": false, + "AudioContext": false, + "AudioDestinationNode": false, + "AudioListener": false, + "AudioNode": false, + "AudioParam": false, "AudioProcessingEvent": false, + "AutocompleteErrorEvent": false, + "BarProp": false, + "BatteryManager": false, "BeforeUnloadEvent": false, + "BiquadFilterNode": false, "Blob": false, "blur": false, "btoa": false, + "Cache": false, + "caches": false, + "CacheStorage": false, "cancelAnimationFrame": false, "CanvasGradient": false, "CanvasPattern": false, "CanvasRenderingContext2D": false, + "CDATASection": false, + "ChannelMergerNode": false, + "ChannelSplitterNode": false, + "CharacterData": false, "clearInterval": false, "clearTimeout": false, + "clientInformation": false, + "ClientRect": false, + "ClientRectList": false, + "ClipboardEvent": false, "close": false, "closed": false, "CloseEvent": false, "Comment": false, "CompositionEvent": false, "confirm": false, "console": false, + "ConvolverNode": false, "crypto": false, + "Crypto": false, + "CryptoKey": false, "CSS": false, + "CSSFontFaceRule": false, + "CSSImportRule": false, + "CSSKeyframeRule": false, + "CSSKeyframesRule": false, + "CSSMediaRule": false, + "CSSPageRule": false, + "CSSRule": false, + "CSSRuleList": false, + "CSSStyleDeclaration": false, + "CSSStyleRule": false, + "CSSStyleSheet": false, + "CSSSupportsRule": false, + "CSSUnknownRule": false, + "CSSViewportRule": false, "CustomEvent": false, - "DataView": false, + "DataTransfer": false, + "DataTransferItem": false, + "DataTransferItemList": false, "Debug": false, "defaultStatus": false, + "defaultstatus": false, + "DelayNode": false, + "DeviceMotionEvent": false, + "DeviceOrientationEvent": false, "devicePixelRatio": false, "dispatchEvent": false, "document": false, "Document": false, "DocumentFragment": false, + "DocumentType": false, + "DOMError": false, + "DOMException": false, + "DOMImplementation": false, "DOMParser": false, + "DOMSettableTokenList": false, + "DOMStringList": false, + "DOMStringMap": false, + "DOMTokenList": false, "DragEvent": false, + "DynamicsCompressorNode": false, "Element": false, "ElementTimeControl": false, "ErrorEvent": false, "event": false, "Event": false, + "EventSource": false, + "EventTarget": false, + "external": false, + "fetch": false, + "File": false, + "FileError": false, + "FileList": false, "FileReader": false, "find": false, "focus": false, "FocusEvent": false, + "FontFace": false, "FormData": false, "frameElement": false, "frames": false, + "GainNode": false, + "Gamepad": false, + "GamepadButton": false, "GamepadEvent": false, "getComputedStyle": false, "getSelection": false, "HashChangeEvent": false, + "Headers": false, "history": false, + "History": false, + "HTMLAllCollection": false, "HTMLAnchorElement": false, + "HTMLAppletElement": false, + "HTMLAreaElement": false, + "HTMLAudioElement": false, "HTMLBaseElement": false, "HTMLBlockquoteElement": false, "HTMLBodyElement": false, "HTMLBRElement": false, "HTMLButtonElement": false, "HTMLCanvasElement": false, + "HTMLCollection": false, + "HTMLContentElement": false, + "HTMLDataListElement": false, + "HTMLDetailsElement": false, + "HTMLDialogElement": false, "HTMLDirectoryElement": false, "HTMLDivElement": false, "HTMLDListElement": false, + "HTMLDocument": false, "HTMLElement": false, + "HTMLEmbedElement": false, "HTMLFieldSetElement": false, "HTMLFontElement": false, + "HTMLFormControlsCollection": false, "HTMLFormElement": false, "HTMLFrameElement": false, "HTMLFrameSetElement": false, "HTMLHeadElement": false, "HTMLHeadingElement": false, @@ -16202,39 +18555,53 @@ "HTMLHtmlElement": false, "HTMLIFrameElement": false, "HTMLImageElement": false, "HTMLInputElement": false, "HTMLIsIndexElement": false, + "HTMLKeygenElement": false, "HTMLLabelElement": false, "HTMLLayerElement": false, "HTMLLegendElement": false, "HTMLLIElement": false, "HTMLLinkElement": false, "HTMLMapElement": false, + "HTMLMarqueeElement": false, + "HTMLMediaElement": false, "HTMLMenuElement": false, "HTMLMetaElement": false, + "HTMLMeterElement": false, "HTMLModElement": false, "HTMLObjectElement": false, "HTMLOListElement": false, "HTMLOptGroupElement": false, "HTMLOptionElement": false, + "HTMLOptionsCollection": false, + "HTMLOutputElement": false, "HTMLParagraphElement": false, "HTMLParamElement": false, + "HTMLPictureElement": false, "HTMLPreElement": false, + "HTMLProgressElement": false, "HTMLQuoteElement": false, "HTMLScriptElement": false, "HTMLSelectElement": false, + "HTMLShadowElement": false, + "HTMLSourceElement": false, + "HTMLSpanElement": false, "HTMLStyleElement": false, "HTMLTableCaptionElement": false, "HTMLTableCellElement": false, "HTMLTableColElement": false, "HTMLTableElement": false, "HTMLTableRowElement": false, "HTMLTableSectionElement": false, + "HTMLTemplateElement": false, "HTMLTextAreaElement": false, "HTMLTitleElement": false, + "HTMLTrackElement": false, "HTMLUListElement": false, + "HTMLUnknownElement": false, "HTMLVideoElement": false, "IDBCursor": false, "IDBCursorWithValue": false, "IDBDatabase": false, "IDBEnvironment": false, @@ -16245,34 +18612,75 @@ "IDBOpenDBRequest": false, "IDBRequest": false, "IDBTransaction": false, "IDBVersionChangeEvent": false, "Image": false, + "ImageBitmap": false, + "ImageData": false, "indexedDB": false, "innerHeight": false, "innerWidth": false, "InputEvent": false, + "InputMethodContext": false, "Intl": false, "KeyboardEvent": false, "length": false, "localStorage": false, "location": false, + "Location": false, + "locationbar": false, "matchMedia": false, + "MediaElementAudioSourceNode": false, + "MediaEncryptedEvent": false, + "MediaError": false, + "MediaKeyError": false, + "MediaKeyEvent": false, + "MediaKeyMessageEvent": false, + "MediaKeys": false, + "MediaKeySession": false, + "MediaKeyStatusMap": false, + "MediaKeySystemAccess": false, + "MediaList": false, + "MediaQueryList": false, + "MediaQueryListEvent": false, + "MediaSource": false, + "MediaStreamAudioDestinationNode": false, + "MediaStreamAudioSourceNode": false, + "MediaStreamEvent": false, + "MediaStreamTrack": false, + "menubar": false, "MessageChannel": false, "MessageEvent": false, "MessagePort": false, + "MIDIAccess": false, + "MIDIConnectionEvent": false, + "MIDIInput": false, + "MIDIInputMap": false, + "MIDIMessageEvent": false, + "MIDIOutput": false, + "MIDIOutputMap": false, + "MIDIPort": false, + "MimeType": false, + "MimeTypeArray": false, "MouseEvent": false, "moveBy": false, "moveTo": false, + "MutationEvent": false, "MutationObserver": false, + "MutationRecord": false, "name": false, + "NamedNodeMap": false, "navigator": false, + "Navigator": false, "Node": false, "NodeFilter": false, + "NodeIterator": false, "NodeList": false, "Notification": false, "OfflineAudioCompletionEvent": false, + "OfflineAudioContext": false, + "offscreenBuffering": false, "onbeforeunload": true, "onblur": true, "onerror": true, "onfocus": true, "onload": true, @@ -16281,44 +18689,90 @@ "open": false, "openDatabase": false, "opener": false, "opera": false, "Option": false, + "OscillatorNode": false, "outerHeight": false, "outerWidth": false, "PageTransitionEvent": false, "pageXOffset": false, "pageYOffset": false, "parent": false, + "Path2D": false, + "performance": false, + "Performance": false, + "PerformanceEntry": false, + "PerformanceMark": false, + "PerformanceMeasure": false, + "PerformanceNavigation": false, + "PerformanceResourceTiming": false, + "PerformanceTiming": false, + "PeriodicWave": false, + "Permissions": false, + "PermissionStatus": false, + "personalbar": false, + "Plugin": false, + "PluginArray": false, "PopStateEvent": false, "postMessage": false, "print": false, + "ProcessingInstruction": false, "ProgressEvent": false, "prompt": false, + "PushManager": false, + "PushSubscription": false, + "RadioNodeList": false, "Range": false, + "ReadableByteStream": false, + "ReadableStream": false, "removeEventListener": false, + "Request": false, "requestAnimationFrame": false, "resizeBy": false, "resizeTo": false, + "Response": false, + "RTCIceCandidate": false, + "RTCSessionDescription": false, "screen": false, + "Screen": false, + "screenLeft": false, + "ScreenOrientation": false, + "screenTop": false, "screenX": false, "screenY": false, + "ScriptProcessorNode": false, "scroll": false, "scrollbars": false, "scrollBy": false, "scrollTo": false, "scrollX": false, "scrollY": false, + "SecurityPolicyViolationEvent": false, + "Selection": false, "self": false, + "ServiceWorker": false, + "ServiceWorkerContainer": false, + "ServiceWorkerRegistration": false, "sessionStorage": false, "setInterval": false, "setTimeout": false, + "ShadowRoot": false, "SharedWorker": false, "showModalDialog": false, + "speechSynthesis": false, + "SpeechSynthesisEvent": false, + "SpeechSynthesisUtterance": false, "status": false, + "statusbar": false, "stop": false, + "Storage": false, "StorageEvent": false, + "styleMedia": false, + "StyleSheet": false, + "StyleSheetList": false, + "SubtleCrypto": false, "SVGAElement": false, "SVGAltGlyphDefElement": false, "SVGAltGlyphElement": false, "SVGAltGlyphItemElement": false, "SVGAngle": false, @@ -16349,10 +18803,11 @@ "SVGComponentTransferFunctionElement": false, "SVGCSSRule": false, "SVGCursorElement": false, "SVGDefsElement": false, "SVGDescElement": false, + "SVGDiscardElement": false, "SVGDocument": false, "SVGElement": false, "SVGElementInstance": false, "SVGElementInstanceList": false, "SVGEllipseElement": false, @@ -16364,10 +18819,11 @@ "SVGFECompositeElement": false, "SVGFEConvolveMatrixElement": false, "SVGFEDiffuseLightingElement": false, "SVGFEDisplacementMapElement": false, "SVGFEDistantLightElement": false, + "SVGFEDropShadowElement": false, "SVGFEFloodElement": false, "SVGFEFuncAElement": false, "SVGFEFuncBElement": false, "SVGFEFuncGElement": false, "SVGFEFuncRElement": false, @@ -16391,13 +18847,15 @@ "SVGFontFaceNameElement": false, "SVGFontFaceSrcElement": false, "SVGFontFaceUriElement": false, "SVGForeignObjectElement": false, "SVGGElement": false, + "SVGGeometryElement": false, "SVGGlyphElement": false, "SVGGlyphRefElement": false, "SVGGradientElement": false, + "SVGGraphicsElement": false, "SVGHKernElement": false, "SVGICCColor": false, "SVGImageElement": false, "SVGLangSpace": false, "SVGLength": false, @@ -16471,18 +18929,35 @@ "SVGUseElement": false, "SVGViewElement": false, "SVGViewSpec": false, "SVGVKernElement": false, "SVGZoomAndPan": false, + "SVGZoomEvent": false, "Text": false, "TextDecoder": false, "TextEncoder": false, + "TextEvent": false, + "TextMetrics": false, + "TextTrack": false, + "TextTrackCue": false, + "TextTrackCueList": false, + "TextTrackList": false, "TimeEvent": false, + "TimeRanges": false, + "toolbar": false, "top": false, + "Touch": false, "TouchEvent": false, + "TouchList": false, + "TrackEvent": false, + "TransitionEvent": false, + "TreeWalker": false, "UIEvent": false, "URL": false, + "ValidityState": false, + "VTTCue": false, + "WaveShaperNode": false, "WebGLActiveInfo": false, "WebGLBuffer": false, "WebGLContextEvent": false, "WebGLFramebuffer": false, "WebGLProgram": false, @@ -16496,44 +18971,116 @@ "WheelEvent": false, "window": false, "Window": false, "Worker": false, "XDomainRequest": false, + "XMLDocument": false, "XMLHttpRequest": false, + "XMLHttpRequestEventTarget": false, + "XMLHttpRequestProgressEvent": false, + "XMLHttpRequestUpload": false, "XMLSerializer": false, "XPathEvaluator": false, "XPathException": false, "XPathExpression": false, "XPathNamespace": false, "XPathNSResolver": false, - "XPathResult": false + "XPathResult": false, + "XSLTProcessor": false }, "worker": { + "applicationCache": false, + "atob": false, + "BroadcastChannel": false, + "btoa": false, + "Cache": false, + "caches": false, + "clearInterval": false, + "clearTimeout": false, + "close": true, + "console": false, + "fetch": false, + "FileReaderSync": false, + "FormData": false, + "Headers": false, + "IDBCursor": false, + "IDBCursorWithValue": false, + "IDBDatabase": false, + "IDBFactory": false, + "IDBIndex": false, + "IDBKeyRange": false, + "IDBObjectStore": false, + "IDBOpenDBRequest": false, + "IDBRequest": false, + "IDBTransaction": false, + "IDBVersionChangeEvent": false, + "ImageData": false, "importScripts": true, + "indexedDB": false, + "location": false, + "MessageChannel": false, + "MessagePort": false, + "name": false, + "navigator": false, + "Notification": false, + "onclose": true, + "onconnect": true, + "onerror": true, + "onlanguagechange": true, + "onmessage": true, + "onoffline": true, + "ononline": true, + "onrejectionhandled": true, + "onunhandledrejection": true, + "performance": false, + "Performance": false, + "PerformanceEntry": false, + "PerformanceMark": false, + "PerformanceMeasure": false, + "PerformanceNavigation": false, + "PerformanceResourceTiming": false, + "PerformanceTiming": false, "postMessage": true, - "self": true + "Promise": false, + "Request": false, + "Response": false, + "self": true, + "ServiceWorkerRegistration": false, + "setInterval": false, + "setTimeout": false, + "TextDecoder": false, + "TextEncoder": false, + "URL": false, + "WebSocket": false, + "Worker": false, + "XMLHttpRequest": false }, "node": { "__dirname": false, "__filename": false, "arguments": false, "Buffer": false, "clearImmediate": false, "clearInterval": false, "clearTimeout": false, "console": false, - "DataView": false, "exports": true, "GLOBAL": false, "global": false, "module": false, "process": false, "require": false, + "root": false, "setImmediate": false, "setInterval": false, "setTimeout": false }, + "commonjs": { + "exports": true, + "module": false, + "require": false + }, "amd": { "define": false, "require": false }, "mocha": { @@ -16542,10 +19089,11 @@ "before": false, "beforeEach": false, "context": false, "describe": false, "it": false, + "mocha": false, "setup": false, "specify": false, "suite": false, "suiteSetup": false, "suiteTeardown": false, @@ -16574,18 +19122,31 @@ "waits": false, "waitsFor": false, "xdescribe": false, "xit": false }, + "jest": { + "afterEach": false, + "beforeEach": false, + "describe": false, + "expect": false, + "it": false, + "jest": false, + "pit": false, + "require": false, + "xdescribe": false, + "xit": false + }, "qunit": { "asyncTest": false, "deepEqual": false, "equal": false, "expect": false, "module": false, "notDeepEqual": false, "notEqual": false, + "notOk": false, "notPropEqual": false, "notStrictEqual": false, "ok": false, "propEqual": false, "QUnit": false, @@ -16637,10 +19198,30 @@ "spawn": false, "sync": false, "toint32": false, "version": false }, + "nashorn": { + "__DIR__": false, + "__FILE__": false, + "__LINE__": false, + "com": false, + "edu": false, + "exit": false, + "Java": false, + "java": false, + "javafx": false, + "JavaImporter": false, + "javax": false, + "JSAdapter": false, + "load": false, + "loadWithNewGlobal": false, + "org": false, + "Packages": false, + "print": false, + "quit": false + }, "wsh": { "ActiveXObject": true, "Enumerator": true, "GetObject": true, "ScriptEngine": true, @@ -16792,91 +19373,2223 @@ "rs": false, "sh": false, "UUID": false, "version": false, "WriteResult": false + }, + "applescript": { + "$": false, + "Application": false, + "Automation": false, + "console": false, + "delay": false, + "Library": false, + "ObjC": false, + "ObjectSpecifier": false, + "Path": false, + "Progress": false, + "Ref": false + }, + "serviceworker": { + "caches": false, + "Cache": false, + "CacheStorage": false, + "Client": false, + "clients": false, + "Clients": false, + "ExtendableEvent": false, + "ExtendableMessageEvent": false, + "FetchEvent": false, + "importScripts": false, + "registration": false, + "self": false, + "ServiceWorker": false, + "ServiceWorkerContainer": false, + "ServiceWorkerGlobalScope": false, + "ServiceWorkerMessageEvent": false, + "ServiceWorkerRegistration": false, + "skipWaiting": false, + "WindowClient": false + }, + "embertest": { + "andThen": false, + "click": false, + "currentPath": false, + "currentRouteName": false, + "currentURL": false, + "fillIn": false, + "find": false, + "keyEvent": false, + "triggerEvent": false, + "visit": false + }, + "protractor": { + "$": false, + "$$": false, + "browser": false, + "By": false, + "by": false, + "DartObject": false, + "element": false, + "protractor": false + }, + "shared-node-browser": { + "clearInterval": false, + "clearTimeout": false, + "console": false, + "setInterval": false, + "setTimeout": false + }, + "webextensions": { + "browser": false, + "chrome": false, + "opr": false } } -},{}],130:[function(require,module,exports){ +},{}],100:[function(require,module,exports){ module.exports = require('./globals.json'); -},{"./globals.json":129}],131:[function(require,module,exports){ +},{"./globals.json":99}],101:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],102:[function(require,module,exports){ +exports['date-time'] = /^\d{4}-(?:0[0-9]{1}|1[0-2]{1})-[0-9]{2}[tT ]\d{2}:\d{2}:\d{2}(\.\d+)?([zZ]|[+-]\d{2}:\d{2})$/ +exports['date'] = /^\d{4}-(?:0[0-9]{1}|1[0-2]{1})-[0-9]{2}$/ +exports['time'] = /^\d{2}:\d{2}:\d{2}$/ +exports['email'] = /^\S+@\S+$/ +exports['ip-address'] = exports['ipv4'] = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ +exports['ipv6'] = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/ +exports['uri'] = /^[a-zA-Z][a-zA-Z0-9+-.]*:[^\s]*$/ +exports['color'] = /(#?([0-9A-Fa-f]{3,6})\b)|(aqua)|(black)|(blue)|(fuchsia)|(gray)|(green)|(lime)|(maroon)|(navy)|(olive)|(orange)|(purple)|(red)|(silver)|(teal)|(white)|(yellow)|(rgb\(\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*\))|(rgb\(\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*\))/ +exports['hostname'] = /^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$/ +exports['alpha'] = /^[a-zA-Z]+$/ +exports['alphanumeric'] = /^[a-zA-Z0-9]+$/ +exports['style'] = /\s*(.+?):\s*([^;]+);?/g +exports['phone'] = /^\+(?:[0-9] ?){6,14}[0-9]$/ +exports['utc-millisec'] = /^[0-9]+(\.?[0-9]+)?$/ + +},{}],103:[function(require,module,exports){ +var genobj = require('generate-object-property') +var genfun = require('generate-function') +var jsonpointer = require('jsonpointer') +var xtend = require('xtend') +var formats = require('./formats') + +var get = function(obj, additionalSchemas, ptr) { + if (/^https?:\/\//.test(ptr)) return null + + var visit = function(sub) { + if (sub && sub.id === ptr) return sub + if (typeof sub !== 'object' || !sub) return null + return Object.keys(sub).reduce(function(res, k) { + return res || visit(sub[k]) + }, null) + } + + var res = visit(obj) + if (res) return res + + ptr = ptr.replace(/^#/, '') + ptr = ptr.replace(/\/$/, '') + + try { + return jsonpointer.get(obj, decodeURI(ptr)) + } catch (err) { + var end = ptr.indexOf('#') + var other + // external reference + if (end !== 0) { + // fragment doesn't exist. + if (end === -1) { + other = additionalSchemas[ptr] + } else { + var ext = ptr.slice(0, end) + other = additionalSchemas[ext] + var fragment = ptr.slice(end).replace(/^#/, '') + try { + return jsonpointer.get(other, fragment) + } catch (err) {} + } + } else { + other = additionalSchemas[ptr] + } + return other || null + } +} + +var formatName = function(field) { + field = JSON.stringify(field) + var pattern = /\[([^\[\]"]+)\]/ + while (pattern.test(field)) field = field.replace(pattern, '."+$1+"') + return field +} + +var types = {} + +types.any = function() { + return 'true' +} + +types.null = function(name) { + return name+' === null' +} + +types.boolean = function(name) { + return 'typeof '+name+' === "boolean"' +} + +types.array = function(name) { + return 'Array.isArray('+name+')' +} + +types.object = function(name) { + return 'typeof '+name+' === "object" && '+name+' && !Array.isArray('+name+')' +} + +types.number = function(name) { + return 'typeof '+name+' === "number"' +} + +types.integer = function(name) { + return 'typeof '+name+' === "number" && (Math.floor('+name+') === '+name+' || '+name+' > 9007199254740992 || '+name+' < -9007199254740992)' +} + +types.string = function(name) { + return 'typeof '+name+' === "string"' +} + +var unique = function(array) { + var list = [] + for (var i = 0; i < array.length; i++) { + list.push(typeof array[i] === 'object' ? JSON.stringify(array[i]) : array[i]) + } + for (var i = 1; i < list.length; i++) { + if (list.indexOf(list[i]) !== i) return false + } + return true +} + +var toType = function(node) { + return node.type +} + +var compile = function(schema, cache, root, reporter, opts) { + var fmts = opts ? xtend(formats, opts.formats) : formats + var scope = {unique:unique, formats:fmts} + var verbose = opts ? !!opts.verbose : false; + var greedy = opts && opts.greedy !== undefined ? + opts.greedy : false; + + var syms = {} + var gensym = function(name) { + return name+(syms[name] = (syms[name] || 0)+1) + } + + var reversePatterns = {} + var patterns = function(p) { + if (reversePatterns[p]) return reversePatterns[p] + var n = gensym('pattern') + scope[n] = new RegExp(p) + reversePatterns[p] = n + return n + } + + var vars = ['i','j','k','l','m','n','o','p','q','r','s','t','u','v','x','y','z'] + var genloop = function() { + var v = vars.shift() + vars.push(v+v[0]) + return v + } + + var visit = function(name, node, reporter, filter) { + var properties = node.properties + var type = node.type + var tuple = false + + if (Array.isArray(node.items)) { // tuple type + properties = {} + node.items.forEach(function(item, i) { + properties[i] = item + }) + type = 'array' + tuple = true + } + + var indent = 0 + var error = function(msg, prop, value) { + validate('errors++') + if (reporter === true) { + validate('if (validate.errors === null) validate.errors = []') + if (verbose) { + validate('validate.errors.push({field:%s,message:%s,value:%s})', formatName(prop || name), JSON.stringify(msg), value || name) + } else { + validate('validate.errors.push({field:%s,message:%s})', formatName(prop || name), JSON.stringify(msg)) + } + } + } + + if (node.required === true) { + indent++ + validate('if (%s === undefined) {', name) + error('is required') + validate('} else {') + } else { + indent++ + validate('if (%s !== undefined) {', name) + } + + var valid = [].concat(type) + .map(function(t) { + return types[t || 'any'](name) + }) + .join(' || ') || 'true' + + if (valid !== 'true') { + indent++ + validate('if (!(%s)) {', valid) + error('is the wrong type') + validate('} else {') + } + + if (tuple) { + if (node.additionalItems === false) { + validate('if (%s.length > %d) {', name, node.items.length) + error('has additional items') + validate('}') + } else if (node.additionalItems) { + var i = genloop() + validate('for (var %s = %d; %s < %s.length; %s++) {', i, node.items.length, i, name, i) + visit(name+'['+i+']', node.additionalItems, reporter, filter) + validate('}') + } + } + + if (node.format && fmts[node.format]) { + if (type !== 'string' && formats[node.format]) validate('if (%s) {', types.string(name)) + var n = gensym('format') + scope[n] = fmts[node.format] + + if (typeof scope[n] === 'function') validate('if (!%s(%s)) {', n, name) + else validate('if (!%s.test(%s)) {', n, name) + error('must be '+node.format+' format') + validate('}') + if (type !== 'string' && formats[node.format]) validate('}') + } + + if (Array.isArray(node.required)) { + var isUndefined = function(req) { + return genobj(name, req) + ' === undefined' + } + + var checkRequired = function (req) { + var prop = genobj(name, req); + validate('if (%s === undefined) {', prop) + error('is required', prop) + validate('missing++') + validate('}') + } + validate('if ((%s)) {', type !== 'object' ? types.object(name) : 'true') + validate('var missing = 0') + node.required.map(checkRequired) + validate('}'); + if (!greedy) { + validate('if (missing === 0) {') + indent++ + } + } + + if (node.uniqueItems) { + if (type !== 'array') validate('if (%s) {', types.array(name)) + validate('if (!(unique(%s))) {', name) + error('must be unique') + validate('}') + if (type !== 'array') validate('}') + } + + if (node.enum) { + var complex = node.enum.some(function(e) { + return typeof e === 'object' + }) + + var compare = complex ? + function(e) { + return 'JSON.stringify('+name+')'+' !== JSON.stringify('+JSON.stringify(e)+')' + } : + function(e) { + return name+' !== '+JSON.stringify(e) + } + + validate('if (%s) {', node.enum.map(compare).join(' && ') || 'false') + error('must be an enum value') + validate('}') + } + + if (node.dependencies) { + if (type !== 'object') validate('if (%s) {', types.object(name)) + + Object.keys(node.dependencies).forEach(function(key) { + var deps = node.dependencies[key] + if (typeof deps === 'string') deps = [deps] + + var exists = function(k) { + return genobj(name, k) + ' !== undefined' + } + + if (Array.isArray(deps)) { + validate('if (%s !== undefined && !(%s)) {', genobj(name, key), deps.map(exists).join(' && ') || 'true') + error('dependencies not set') + validate('}') + } + if (typeof deps === 'object') { + validate('if (%s !== undefined) {', genobj(name, key)) + visit(name, deps, reporter, filter) + validate('}') + } + }) + + if (type !== 'object') validate('}') + } + + if (node.additionalProperties || node.additionalProperties === false) { + if (type !== 'object') validate('if (%s) {', types.object(name)) + + var i = genloop() + var keys = gensym('keys') + + var toCompare = function(p) { + return keys+'['+i+'] !== '+JSON.stringify(p) + } + + var toTest = function(p) { + return '!'+patterns(p)+'.test('+keys+'['+i+'])' + } + + var additionalProp = Object.keys(properties || {}).map(toCompare) + .concat(Object.keys(node.patternProperties || {}).map(toTest)) + .join(' && ') || 'true' + + validate('var %s = Object.keys(%s)', keys, name) + ('for (var %s = 0; %s < %s.length; %s++) {', i, i, keys, i) + ('if (%s) {', additionalProp) + + if (node.additionalProperties === false) { + if (filter) validate('delete %s', name+'['+keys+'['+i+']]') + error('has additional properties', null, JSON.stringify(name+'.') + ' + ' + keys + '['+i+']') + } else { + visit(name+'['+keys+'['+i+']]', node.additionalProperties, reporter, filter) + } + + validate + ('}') + ('}') + + if (type !== 'object') validate('}') + } + + if (node.$ref) { + var sub = get(root, opts && opts.schemas || {}, node.$ref) + if (sub) { + var fn = cache[node.$ref] + if (!fn) { + cache[node.$ref] = function proxy(data) { + return fn(data) + } + fn = compile(sub, cache, root, false, opts) + } + var n = gensym('ref') + scope[n] = fn + validate('if (!(%s(%s))) {', n, name) + error('referenced schema does not match') + validate('}') + } + } + + if (node.not) { + var prev = gensym('prev') + validate('var %s = errors', prev) + visit(name, node.not, false, filter) + validate('if (%s === errors) {', prev) + error('negative schema matches') + validate('} else {') + ('errors = %s', prev) + ('}') + } + + if (node.items && !tuple) { + if (type !== 'array') validate('if (%s) {', types.array(name)) + + var i = genloop() + validate('for (var %s = 0; %s < %s.length; %s++) {', i, i, name, i) + visit(name+'['+i+']', node.items, reporter, filter) + validate('}') + + if (type !== 'array') validate('}') + } + + if (node.patternProperties) { + if (type !== 'object') validate('if (%s) {', types.object(name)) + var keys = gensym('keys') + var i = genloop() + validate + ('var %s = Object.keys(%s)', keys, name) + ('for (var %s = 0; %s < %s.length; %s++) {', i, i, keys, i) + + Object.keys(node.patternProperties).forEach(function(key) { + var p = patterns(key) + validate('if (%s.test(%s)) {', p, keys+'['+i+']') + visit(name+'['+keys+'['+i+']]', node.patternProperties[key], reporter, filter) + validate('}') + }) + + validate('}') + if (type !== 'object') validate('}') + } + + if (node.pattern) { + var p = patterns(node.pattern) + if (type !== 'string') validate('if (%s) {', types.string(name)) + validate('if (!(%s.test(%s))) {', p, name) + error('pattern mismatch') + validate('}') + if (type !== 'string') validate('}') + } + + if (node.allOf) { + node.allOf.forEach(function(sch) { + visit(name, sch, reporter, filter) + }) + } + + if (node.anyOf && node.anyOf.length) { + var prev = gensym('prev') + + node.anyOf.forEach(function(sch, i) { + if (i === 0) { + validate('var %s = errors', prev) + } else { + validate('if (errors !== %s) {', prev) + ('errors = %s', prev) + } + visit(name, sch, false, false) + }) + node.anyOf.forEach(function(sch, i) { + if (i) validate('}') + }) + validate('if (%s !== errors) {', prev) + error('no schemas match') + validate('}') + } + + if (node.oneOf && node.oneOf.length) { + var prev = gensym('prev') + var passes = gensym('passes') + + validate + ('var %s = errors', prev) + ('var %s = 0', passes) + + node.oneOf.forEach(function(sch, i) { + visit(name, sch, false, false) + validate('if (%s === errors) {', prev) + ('%s++', passes) + ('} else {') + ('errors = %s', prev) + ('}') + }) + + validate('if (%s !== 1) {', passes) + error('no (or more than one) schemas match') + validate('}') + } + + if (node.multipleOf !== undefined) { + if (type !== 'number' && type !== 'integer') validate('if (%s) {', types.number(name)) + + var factor = ((node.multipleOf | 0) !== node.multipleOf) ? Math.pow(10, node.multipleOf.toString().split('.').pop().length) : 1 + if (factor > 1) validate('if ((%d*%s) % %d) {', factor, name, factor*node.multipleOf) + else validate('if (%s % %d) {', name, node.multipleOf) + + error('has a remainder') + validate('}') + + if (type !== 'number' && type !== 'integer') validate('}') + } + + if (node.maxProperties !== undefined) { + if (type !== 'object') validate('if (%s) {', types.object(name)) + + validate('if (Object.keys(%s).length > %d) {', name, node.maxProperties) + error('has more properties than allowed') + validate('}') + + if (type !== 'object') validate('}') + } + + if (node.minProperties !== undefined) { + if (type !== 'object') validate('if (%s) {', types.object(name)) + + validate('if (Object.keys(%s).length < %d) {', name, node.minProperties) + error('has less properties than allowed') + validate('}') + + if (type !== 'object') validate('}') + } + + if (node.maxItems !== undefined) { + if (type !== 'array') validate('if (%s) {', types.array(name)) + + validate('if (%s.length > %d) {', name, node.maxItems) + error('has more items than allowed') + validate('}') + + if (type !== 'array') validate('}') + } + + if (node.minItems !== undefined) { + if (type !== 'array') validate('if (%s) {', types.array(name)) + + validate('if (%s.length < %d) {', name, node.minItems) + error('has less items than allowed') + validate('}') + + if (type !== 'array') validate('}') + } + + if (node.maxLength !== undefined) { + if (type !== 'string') validate('if (%s) {', types.string(name)) + + validate('if (%s.length > %d) {', name, node.maxLength) + error('has longer length than allowed') + validate('}') + + if (type !== 'string') validate('}') + } + + if (node.minLength !== undefined) { + if (type !== 'string') validate('if (%s) {', types.string(name)) + + validate('if (%s.length < %d) {', name, node.minLength) + error('has less length than allowed') + validate('}') + + if (type !== 'string') validate('}') + } + + if (node.minimum !== undefined) { + validate('if (%s %s %d) {', name, node.exclusiveMinimum ? '<=' : '<', node.minimum) + error('is less than minimum') + validate('}') + } + + if (node.maximum !== undefined) { + validate('if (%s %s %d) {', name, node.exclusiveMaximum ? '>=' : '>', node.maximum) + error('is more than maximum') + validate('}') + } + + if (properties) { + Object.keys(properties).forEach(function(p) { + if (Array.isArray(type) && type.indexOf('null') !== -1) validate('if (%s !== null) {', name) + + visit(genobj(name, p), properties[p], reporter, filter) + + if (Array.isArray(type) && type.indexOf('null') !== -1) validate('}') + }) + } + + while (indent--) validate('}') + } + + var validate = genfun + ('function validate(data) {') + ('validate.errors = null') + ('var errors = 0') + + visit('data', schema, reporter, opts && opts.filter) + + validate + ('return errors === 0') + ('}') + + validate = validate.toFunction(scope) + validate.errors = null + + if (Object.defineProperty) { + Object.defineProperty(validate, 'error', { + get: function() { + if (!validate.errors) return '' + return validate.errors.map(function(err) { + return err.field + ' ' + err.message; + }).join('\n') + } + }) + } + + validate.toJSON = function() { + return schema + } + + return validate +} + +module.exports = function(schema, opts) { + if (typeof schema === 'string') schema = JSON.parse(schema) + return compile(schema, {}, schema, true, opts) +} + +module.exports.filter = function(schema, opts) { + var validate = module.exports(schema, xtend(opts, {filter: true})) + return function(sch) { + validate(sch) + return sch + } +} + +},{"./formats":102,"generate-function":97,"generate-object-property":98,"jsonpointer":106,"xtend":112}],104:[function(require,module,exports){ +"use strict" +function isProperty(str) { + return /^[$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc][$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc0-9\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19b0-\u19c0\u19c8\u19c9\u19d0-\u19d9\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1dc0-\u1de6\u1dfc-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f]*$/.test(str) +} +module.exports = isProperty +},{}],105:[function(require,module,exports){ +module.exports = Array.isArray || function (arr) { + return Object.prototype.toString.call(arr) == '[object Array]'; +}; + +},{}],106:[function(require,module,exports){ +var untilde = function(str) { + return str.replace(/~./g, function(m) { + switch (m) { + case "~0": + return "~"; + case "~1": + return "/"; + } + throw new Error("Invalid tilde escape: " + m); + }); +} + +var traverse = function(obj, pointer, value) { + // assert(isArray(pointer)) + var part = untilde(pointer.shift()); + if(!obj.hasOwnProperty(part)) { + return null; + } + if(pointer.length !== 0) { // keep traversin! + return traverse(obj[part], pointer, value); + } + // we're done + if(typeof value === "undefined") { + // just reading + return obj[part]; + } + // set new value, return old value + var old_value = obj[part]; + if(value === null) { + delete obj[part]; + } else { + obj[part] = value; + } + return old_value; +} + +var validate_input = function(obj, pointer) { + if(typeof obj !== "object") { + throw new Error("Invalid input object."); + } + + if(pointer === "") { + return []; + } + + if(!pointer) { + throw new Error("Invalid JSON pointer."); + } + + pointer = pointer.split("/"); + var first = pointer.shift(); + if (first !== "") { + throw new Error("Invalid JSON pointer."); + } + + return pointer; +} + +var get = function(obj, pointer) { + pointer = validate_input(obj, pointer); + if (pointer.length === 0) { + return obj; + } + return traverse(obj, pointer); +} + +var set = function(obj, pointer, value) { + pointer = validate_input(obj, pointer); + if (pointer.length === 0) { + throw new Error("Invalid JSON pointer for set.") + } + return traverse(obj, pointer, value); +} + +exports.get = get +exports.set = set + +},{}],107:[function(require,module,exports){ +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} options + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options){ + options = options || {}; + if ('string' == typeof val) return parse(val); + return options.long + ? long(val) + : short(val); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + str = '' + str; + if (str.length > 10000) return; + var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str); + if (!match) return; + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function short(ms) { + if (ms >= d) return Math.round(ms / d) + 'd'; + if (ms >= h) return Math.round(ms / h) + 'h'; + if (ms >= m) return Math.round(ms / m) + 'm'; + if (ms >= s) return Math.round(ms / s) + 's'; + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function long(ms) { + return plural(ms, d, 'day') + || plural(ms, h, 'hour') + || plural(ms, m, 'minute') + || plural(ms, s, 'second') + || ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, n, name) { + if (ms < n) return; + if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name; + return Math.ceil(ms / n) + ' ' + name + 's'; +} + +},{}],108:[function(require,module,exports){ +/* eslint-disable no-unused-vars */ 'use strict'; +var hasOwnProperty = Object.prototype.hasOwnProperty; +var propIsEnumerable = Object.prototype.propertyIsEnumerable; -function ToObject(val) { - if (val == null) { +function toObject(val) { + if (val === null || val === undefined) { throw new TypeError('Object.assign cannot be called with null or undefined'); } return Object(val); } module.exports = Object.assign || function (target, source) { var from; - var keys; - var to = ToObject(target); + var to = toObject(target); + var symbols; for (var s = 1; s < arguments.length; s++) { - from = arguments[s]; - keys = Object.keys(Object(from)); + from = Object(arguments[s]); - for (var i = 0; i < keys.length; i++) { - to[keys[i]] = from[keys[i]]; + for (var key in from) { + if (hasOwnProperty.call(from, key)) { + to[key] = from[key]; + } } + + if (Object.getOwnPropertySymbols) { + symbols = Object.getOwnPropertySymbols(from); + for (var i = 0; i < symbols.length; i++) { + if (propIsEnumerable.call(from, symbols[i])) { + to[symbols[i]] = from[symbols[i]]; + } + } + } } return to; }; -},{}],132:[function(require,module,exports){ +},{}],109:[function(require,module,exports){ +// shim for using process in browser + +var process = module.exports = {}; +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = setTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + clearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + setTimeout(drainQueue, 0); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],110:[function(require,module,exports){ +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; +} +},{}],111:[function(require,module,exports){ +(function (process,global){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; + + +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + // Allow for deprecating things in the process of starting up. + if (isUndefined(global.process)) { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; + } + + if (process.noDeprecation === true) { + return fn; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + + return deprecated; +}; + + +var debugs = {}; +var debugEnviron; +exports.debuglog = function(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; +}; + + /** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); +} +exports.inspect = inspect; + + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; + +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; + + +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } +} + + +function stylizeNoColor(str, styleType) { + return str; +} + + +function arrayToHash(array) { + var hash = {}; + + array.forEach(function(val, idx) { + hash[val] = true; + }); + + return hash; +} + + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); + + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } + + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } + + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +exports.isBuffer = require('./support/isBuffer'); + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} + + +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; + +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); +} + + +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = require('inherits'); + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; + + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; +}; + +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./support/isBuffer":110,"_process":109,"inherits":101}],112:[function(require,module,exports){ +module.exports = extend + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +function extend() { + var target = {} + + for (var i = 0; i < arguments.length; i++) { + var source = arguments[i] + + for (var key in source) { + if (hasOwnProperty.call(source, key)) { + target[key] = source[key] + } + } + } + + return target +} + +},{}],113:[function(require,module,exports){ +/** + * @fileoverview Common utils for AST. + * @author Gyandeep Singh + * @copyright 2015 Gyandeep Singh. All rights reserved. + * See LICENSE file in root directory for full license. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var esutils = require("esutils"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Checks reference if is non initializer and writable. + * @param {Reference} reference - A reference to check. + * @param {int} index - The index of the reference in the references. + * @param {Reference[]} references - The array that the reference belongs to. + * @returns {boolean} Success/Failure + * @private + */ +function isModifyingReference(reference, index, references) { + var identifier = reference.identifier; + + return (identifier && + reference.init === false && + reference.isWrite() && + // Destructuring assignments can have multiple default value, + // so possibly there are multiple writeable references for the same identifier. + (index === 0 || references[index - 1].identifier !== identifier) + ); +} + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +module.exports = { + + /** + * Determines whether two adjacent tokens are on the same line. + * @param {Object} left - The left token object. + * @param {Object} right - The right token object. + * @returns {boolean} Whether or not the tokens are on the same line. + * @public + */ + isTokenOnSameLine: function(left, right) { + return left.loc.end.line === right.loc.start.line; + }, + + /** + * Checks whether or not a node is `null` or `undefined`. + * @param {ASTNode} node - A node to check. + * @returns {boolean} Whether or not the node is a `null` or `undefined`. + * @public + */ + isNullOrUndefined: function(node) { + return ( + (node.type === "Literal" && node.value === null) || + (node.type === "Identifier" && node.name === "undefined") || + (node.type === "UnaryExpression" && node.operator === "void") + ); + }, + + /** + * Checks whether or not a given node is a string literal. + * @param {ASTNode} node - A node to check. + * @returns {boolean} `true` if the node is a string literal. + */ + isStringLiteral: function(node) { + return ( + (node.type === "Literal" && typeof node.value === "string") || + node.type === "TemplateLiteral" + ); + }, + + /** + * Gets references which are non initializer and writable. + * @param {Reference[]} references - An array of references. + * @returns {Reference[]} An array of only references which are non initializer and writable. + * @public + */ + getModifyingReferences: function(references) { + return references.filter(isModifyingReference); + }, + + /** + * Validate that a string passed in is surrounded by the specified character + * @param {string} val The text to check. + * @param {string} character The character to see if it's surrounded by. + * @returns {boolean} True if the text is surrounded by the character, false if not. + * @private + */ + isSurroundedBy: function(val, character) { + return val[0] === character && val[val.length - 1] === character; + }, + + /** + * Returns whether the provided node is an ESLint directive comment or not + * @param {LineComment|BlockComment} node The node to be checked + * @returns {boolean} `true` if the node is an ESLint directive comment + */ + isDirectiveComment: function(node) { + var comment = node.value.trim(); + return ( + node.type === "Line" && comment.indexOf("eslint-") === 0 || + node.type === "Block" && ( + comment.indexOf("global ") === 0 || + comment.indexOf("eslint ") === 0 || + comment.indexOf("eslint-") === 0 + ) + ); + }, + + /** + * Gets the trailing statement of a given node. + * + * if (code) + * consequent; + * + * When taking this `IfStatement`, returns `consequent;` statement. + * + * @param {ASTNode} A node to get. + * @returns {ASTNode|null} The trailing statement's node. + */ + getTrailingStatement: esutils.ast.trailingStatement, + + /** + * Finds the variable by a given name in a given scope and its upper scopes. + * + * @param {escope.Scope} initScope - A scope to start find. + * @param {string} name - A variable name to find. + * @returns {escope.Variable|null} A found variable or `null`. + */ + getVariableByName: function(initScope, name) { + var scope = initScope; + while (scope) { + var variable = scope.set.get(name); + if (variable) { + return variable; + } + + scope = scope.upper; + } + + return null; + } +}; + +},{"esutils":94}],114:[function(require,module,exports){ +/** + * @fileoverview Config file operations. This file must be usable in the browser, + * so no Node-specific code can be here. + * @author Nicholas C. Zakas + * @copyright 2015 Nicholas C. Zakas. All rights reserved. + * See LICENSE file in root directory for full license. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var debug = require("debug"), + environments = require("../../conf/environments"), + assign = require("object-assign"); + +//------------------------------------------------------------------------------ +// Private +//------------------------------------------------------------------------------ + +debug = debug("eslint:config-ops"); + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +module.exports = { + + /** + * Creates an empty configuration object suitable for merging as a base. + * @returns {Object} A configuration object. + */ + createEmptyConfig: function() { + return { + globals: {}, + env: {}, + rules: {}, + ecmaFeatures: {} + }; + }, + + /** + * Creates an environment config based on the specified environments. + * @param {Object<string,boolean>} env The environment settings. + * @returns {Object} A configuration object with the appropriate rules and globals + * set. + */ + createEnvironmentConfig: function(env) { + + var envConfig = this.createEmptyConfig(); + + if (env) { + + envConfig.env = env; + + Object.keys(env).filter(function(name) { + return env[name]; + }).forEach(function(name) { + var environment = environments[name]; + + if (environment) { + debug("Creating config for environment " + name); + if (environment.globals) { + assign(envConfig.globals, environment.globals); + } + + if (environment.ecmaFeatures) { + assign(envConfig.ecmaFeatures, environment.ecmaFeatures); + } + } + }); + } + + return envConfig; + }, + + /** + * Given a config with environment settings, applies the globals and + * ecmaFeatures to the configuration and returns the result. + * @param {Object} config The configuration information. + * @returns {Object} The updated configuration information. + */ + applyEnvironments: function(config) { + if (config.env && typeof config.env === "object") { + debug("Apply environment settings to config"); + return this.merge(this.createEnvironmentConfig(config.env), config); + } + + return config; + }, + + /** + * Merges two config objects. This will not only add missing keys, but will also modify values to match. + * @param {Object} target config object + * @param {Object} src config object. Overrides in this config object will take priority over base. + * @param {boolean} [combine] Whether to combine arrays or not + * @param {boolean} [isRule] Whether its a rule + * @returns {Object} merged config object. + */ + merge: function deepmerge(target, src, combine, isRule) { + /* + The MIT License (MIT) + + Copyright (c) 2012 Nicholas Fisher + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + // This code is taken from deepmerge repo (https://github.com/KyleAMathews/deepmerge) and modified to meet our needs. + var array = Array.isArray(src) || Array.isArray(target); + var dst = array && [] || {}; + + combine = !!combine; + isRule = !!isRule; + if (array) { + target = target || []; + if (isRule && src.length > 1) { + dst = dst.concat(src); + } else { + dst = dst.concat(target); + } + if (typeof src !== "object" && !Array.isArray(src)) { + src = [src]; + } + Object.keys(src).forEach(function(e, i) { + e = src[i]; + if (typeof dst[i] === "undefined") { + dst[i] = e; + } else if (typeof e === "object") { + if (isRule) { + dst[i] = e; + } else { + dst[i] = deepmerge(target[i], e, combine, isRule); + } + } else { + if (!combine) { + dst[i] = e; + } else { + if (dst.indexOf(e) === -1) { + dst.push(e); + } + } + } + }); + } else { + if (target && typeof target === "object") { + Object.keys(target).forEach(function(key) { + dst[key] = target[key]; + }); + } + Object.keys(src).forEach(function(key) { + if (Array.isArray(src[key]) || Array.isArray(target[key])) { + dst[key] = deepmerge(target[key], src[key], key === "plugins", isRule); + } else if (typeof src[key] !== "object" || !src[key]) { + dst[key] = src[key]; + } else { + if (!target[key]) { + dst[key] = src[key]; + } else { + dst[key] = deepmerge(target[key], src[key], combine, key === "rules"); + } + } + }); + } + + return dst; + } + + +}; + +},{"../../conf/environments":2,"debug":8,"object-assign":108}],115:[function(require,module,exports){ +/** + * @fileoverview Validates configs. + * @author Brandon Mills + * @copyright 2015 Brandon Mills + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var rules = require("../rules"), + environments = require("../../conf/environments"), + schemaValidator = require("is-my-json-valid"); + +var validators = { + rules: Object.create(null) +}; + +//------------------------------------------------------------------------------ +// Private +//------------------------------------------------------------------------------ + +/** + * Gets a complete options schema for a rule. + * @param {string} id The rule's unique name. + * @returns {object} JSON Schema for the rule's options. + */ +function getRuleOptionsSchema(id) { + var rule = rules.get(id), + schema = rule && rule.schema; + + if (!schema) { + return { + "type": "array", + "items": [ + { + "enum": [0, 1, 2] + } + ], + "minItems": 1 + }; + } + + // Given a tuple of schemas, insert warning level at the beginning + if (Array.isArray(schema)) { + return { + "type": "array", + "items": [ + { + "enum": [0, 1, 2] + } + ].concat(schema), + "minItems": 1, + "maxItems": schema.length + 1 + }; + } + + // Given a full schema, leave it alone + return schema; +} + +/** + * Validates a rule's options against its schema. + * @param {string} id The rule's unique name. + * @param {array|number} options The given options for the rule. + * @param {string} source The name of the configuration source. + * @returns {void} + */ +function validateRuleOptions(id, options, source) { + var validateRule = validators.rules[id], + message; + + if (!validateRule) { + validateRule = schemaValidator(getRuleOptionsSchema(id), { verbose: true }); + validators.rules[id] = validateRule; + } + + if (typeof options === "number") { + options = [options]; + } + + validateRule(options); + + if (validateRule.errors) { + message = [ + source, ":\n", + "\tConfiguration for rule \"", id, "\" is invalid:\n" + ]; + validateRule.errors.forEach(function(error) { + if (error.field === "data[\"0\"]") { // better error for severity + message.push( + "\tSeverity should be one of the following: 0 = off, 1 = warning, 2 = error (you passed \"", error.value, "\").\n"); + } else { + message.push( + "\tValue \"", error.value, "\" ", error.message, ".\n" + ); + } + }); + + throw new Error(message.join("")); + } +} + +/** + * Validates an environment object + * @param {object} environment The environment config object to validate. + * @param {string} source The location to report with any errors. + * @returns {void} + */ +function validateEnvironment(environment, source) { + + // not having an environment is ok + if (!environment) { + return; + } + + if (Array.isArray(environment)) { + throw new Error("Environment must not be an array"); + } + + if (typeof environment === "object") { + Object.keys(environment).forEach(function(env) { + if (!environments[env]) { + var message = [ + source, ":\n", + "\tEnvironment key \"", env, "\" is unknown\n" + ]; + throw new Error(message.join("")); + } + }); + } else { + throw new Error("Environment must be an object"); + } +} + +/** + * Validates an entire config object. + * @param {object} config The config object to validate. + * @param {string} source The location to report with any errors. + * @returns {void} + */ +function validate(config, source) { + + if (typeof config.rules === "object") { + Object.keys(config.rules).forEach(function(id) { + validateRuleOptions(id, config.rules[id], source); + }); + } + + validateEnvironment(config.env, source); +} + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +module.exports = { + getRuleOptionsSchema: getRuleOptionsSchema, + validate: validate, + validateRuleOptions: validateRuleOptions +}; + +},{"../../conf/environments":2,"../rules":119,"is-my-json-valid":103}],116:[function(require,module,exports){ +/** * @fileoverview Main ESLint object. * @author Nicholas C. Zakas + * @copyright 2013 Nicholas C. Zakas. All rights reserved. + * See LICENSE file in root directory for full license. */ "use strict"; //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -var estraverse = require("estraverse-fb"), +var estraverse = require("./util/estraverse"), escope = require("escope"), environments = require("../conf/environments"), + blankScriptAST = require("../conf/blank-script.json"), assign = require("object-assign"), rules = require("./rules"), - util = require("./util"), RuleContext = require("./rule-context"), timing = require("./timing"), - createTokenStore = require("./token-store.js"), + SourceCode = require("./util/source-code"), + NodeEventGenerator = require("./util/node-event-generator"), + CommentEventGenerator = require("./util/comment-event-generator"), EventEmitter = require("events").EventEmitter, - escapeRegExp = require("escape-string-regexp"); + ConfigOps = require("./config/config-ops"), + validator = require("./config/config-validator"), + replacements = require("../conf/replacements.json"), + assert = require("assert"); +var DEFAULT_PARSER = require("../conf/eslint.json").parser; + //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -// Have to modify estraverse until TryStatement.handlers is removed -estraverse.VisitorKeys.TryStatement = ["block", "handlers", "finalizer"]; - -// TODO: Remove when estraverse is updated -estraverse.Syntax.ExportNamedDeclaration = "ExportNamedDeclaration"; -estraverse.Syntax.ExportDefaultDeclaration = "ExportDefaultDeclaration"; -estraverse.Syntax.ExportAllDeclaration = "ExportAllDeclaration"; -estraverse.Syntax.ExportSpecifier = "ExportSpecifier"; -estraverse.VisitorKeys.ExportNamedDeclaration = ["declaration", "specifies", "source"]; -estraverse.VisitorKeys.ExportAllDeclaration = ["source"]; -estraverse.VisitorKeys.ExportDefaultDeclaration = ["declaration"]; -estraverse.VisitorKeys.ExportNamedDeclaration = ["declaration", "specifiers", "source"]; -estraverse.VisitorKeys.ExportSpecifier = ["exported", "local"]; /** * Parses a list of "name:boolean_value" or/and "name" options divided by comma or * whitespace. * @param {string} string The string to parse. + * @param {Comment} comment The comment node which has the string. * @returns {Object} Result map object of names and boolean values */ -function parseBooleanConfig(string) { +function parseBooleanConfig(string, comment) { var items = {}; // Collapse whitespace around : to make parsing easier string = string.replace(/\s*:\s*/g, ":"); // Collapse whitespace around , string = string.replace(/\s*,\s*/g, ","); @@ -16889,11 +21602,14 @@ if (pos !== -1) { value = name.substring(pos + 1, name.length); name = name.substring(0, pos); } - items[name] = (value === "true"); + items[name] = { + value: (value === "true"), + comment: comment + }; }); return items; } @@ -16907,18 +21623,18 @@ function parseJsonConfig(string, location, messages) { var items = {}; string = string.replace(/([a-zA-Z0-9\-\/]+):/g, "\"$1\":").replace(/(\]|[0-9])\s+(?=")/, "$1,"); try { items = JSON.parse("{" + string + "}"); - } catch(ex) { + } catch (ex) { messages.push({ fatal: true, severity: 2, message: "Failed to parse JSON from '" + string + "': " + ex.message, line: location.start.line, - column: location.start.column + column: location.start.column + 1 }); } return items; @@ -16942,75 +21658,69 @@ }); return items; } /** - * @param {Scope} scope The scope object to check. - * @param {string} name The name of the variable to look up. - * @returns {Variable} The variable object if found or null if not. - */ -function getVariable(scope, name) { - var variable = null; - scope.variables.some(function(v) { - if (v.name === name) { - variable = v; - return true; - } else { - return false; - } - - }); - return variable; -} - -/** * Ensures that variables representing built-in properties of the Global Object, * and any globals declared by special block comments, are present in the global * scope. * @param {ASTNode} program The top node of the AST. * @param {Scope} globalScope The global scope. * @param {Object} config The existing configuration data. * @returns {void} */ function addDeclaredGlobals(program, globalScope, config) { var declaredGlobals = {}, + exportedGlobals = {}, explicitGlobals = {}, builtin = environments.builtin; assign(declaredGlobals, builtin); - Object.keys(config.env).forEach(function (name) { + Object.keys(config.env).forEach(function(name) { if (config.env[name]) { var environmentGlobals = environments[name] && environments[name].globals; if (environmentGlobals) { assign(declaredGlobals, environmentGlobals); } } }); + assign(exportedGlobals, config.exported); assign(declaredGlobals, config.globals); assign(explicitGlobals, config.astGlobals); Object.keys(declaredGlobals).forEach(function(name) { - var variable = getVariable(globalScope, name); + var variable = globalScope.set.get(name); if (!variable) { variable = new escope.Variable(name, globalScope); variable.eslintExplicitGlobal = false; globalScope.variables.push(variable); + globalScope.set.set(name, variable); } variable.writeable = declaredGlobals[name]; }); Object.keys(explicitGlobals).forEach(function(name) { - var variable = getVariable(globalScope, name); + var variable = globalScope.set.get(name); if (!variable) { variable = new escope.Variable(name, globalScope); variable.eslintExplicitGlobal = true; + variable.eslintExplicitGlobalComment = explicitGlobals[name].comment; globalScope.variables.push(variable); + globalScope.set.set(name, variable); } - variable.writeable = explicitGlobals[name]; + variable.writeable = explicitGlobals[name].value; }); + + // mark all exported variables as such + Object.keys(exportedGlobals).forEach(function(name) { + var variable = globalScope.set.get(name); + if (variable) { + variable.eslintUsed = true; + } + }); } /** * Add data to reporting configuration to disable reporting for list of rules * starting from start location @@ -17076,42 +21786,48 @@ /** * Parses comments in file to extract file-specific config of rules, globals * and environments and merges them with global config; also code blocks * where reporting is disabled or enabled and merges them with reporting config. + * @param {string} filename The file being checked. * @param {ASTNode} ast The top node of the AST. * @param {Object} config The existing configuration data. * @param {Object[]} reportingConfig The existing reporting configuration data. * @param {Object[]} messages The messages queue. - * @returns {void} + * @returns {object} Modified config object */ -function modifyConfigsFromComments(ast, config, reportingConfig, messages) { +function modifyConfigsFromComments(filename, ast, config, reportingConfig, messages) { var commentConfig = { + exported: {}, astGlobals: {}, rules: {}, env: {} }; var commentRules = {}; ast.comments.forEach(function(comment) { var value = comment.value.trim(); - var match = /^(eslint-\w+|eslint-\w+-\w+|eslint|globals?)(\s|$)/.exec(value); + var match = /^(eslint-\w+|eslint-\w+-\w+|eslint|exported|globals?)(\s|$)/.exec(value); if (match) { value = value.substring(match.index + match[1].length); if (comment.type === "Block") { switch (match[1]) { + case "exported": + assign(commentConfig.exported, parseBooleanConfig(value, comment)); + break; + case "globals": case "global": - util.mixin(commentConfig.astGlobals, parseBooleanConfig(value)); + assign(commentConfig.astGlobals, parseBooleanConfig(value, comment)); break; case "eslint-env": - util.mixin(commentConfig.env, parseListConfig(value)); + assign(commentConfig.env, parseListConfig(value)); break; case "eslint-disable": disableReporting(reportingConfig, comment.loc.start, Object.keys(parseListConfig(value))); break; @@ -17122,13 +21838,12 @@ case "eslint": var items = parseJsonConfig(value, comment.loc, messages); Object.keys(items).forEach(function(name) { var ruleValue = items[name]; - if (typeof ruleValue === "number" || (Array.isArray(ruleValue) && typeof ruleValue[0] === "number")) { - commentRules[name] = ruleValue; - } + validator.validateRuleOptions(name, ruleValue, filename + " line " + comment.loc.start.line); + commentRules[name] = ruleValue; }); break; // no default } @@ -17140,20 +21855,19 @@ } } } }); - // apply environment rules before user rules - Object.keys(commentConfig.env).forEach(function (name) { - var environmentRules = environments[name] && environments[name].rules; - if (commentConfig.env[name] && environmentRules) { - util.mixin(commentConfig.rules, environmentRules); + // apply environment configs + Object.keys(commentConfig.env).forEach(function(name) { + if (environments[name]) { + commentConfig = ConfigOps.merge(commentConfig, environments[name]); } }); - util.mixin(commentConfig.rules, commentRules); + assign(commentConfig.rules, commentRules); - util.mergeConfigs(config, commentConfig); + return ConfigOps.merge(config, commentConfig); } /** * Check if message of rule with ruleId should be ignored in location * @param {Object[]} reportingConfig Collection of ignore records @@ -17205,33 +21919,90 @@ } // merge in environment ecmaFeatures if (typeof config.env === "object") { Object.keys(config.env).forEach(function(env) { - if (config.env[env] && environments[env].ecmaFeatures) { + if (config.env[env] && environments[env] && environments[env].ecmaFeatures) { assign(ecmaFeatures, environments[env].ecmaFeatures); } }); } preparedConfig = { rules: copiedRules, - parser: config.parser || "espree", - globals: util.mergeConfigs({}, config.globals), - env: util.mergeConfigs({}, config.env || {}), - settings: util.mergeConfigs({}, config.settings || {}), - ecmaFeatures: util.mergeConfigs(ecmaFeatures, config.ecmaFeatures || {}) + parser: config.parser || DEFAULT_PARSER, + globals: ConfigOps.merge({}, config.globals), + env: ConfigOps.merge({}, config.env || {}), + settings: ConfigOps.merge({}, config.settings || {}), + ecmaFeatures: ConfigOps.merge(ecmaFeatures, config.ecmaFeatures || {}) }; // can't have global return inside of modules if (preparedConfig.ecmaFeatures.modules) { preparedConfig.ecmaFeatures.globalReturn = false; } return preparedConfig; } +/** + * Provide a stub rule with a given message + * @param {string} message The message to be displayed for the rule + * @returns {Function} Stub rule function + */ +function createStubRule(message) { + + /** + * Creates a fake rule object + * @param {object} context context object for each rule + * @returns {object} collection of node to listen on + */ + function createRuleModule(context) { + return { + Program: function(node) { + context.report(node, message); + } + }; + } + + if (message) { + return createRuleModule; + } else { + throw new Error("No message passed to stub rule"); + } +} + +/** + * Provide a rule replacement message + * @param {string} ruleId Name of the rule + * @returns {string} Message detailing rule replacement + */ +function getRuleReplacementMessage(ruleId) { + if (ruleId in replacements.rules) { + var newRules = replacements.rules[ruleId]; + return "Rule \'" + ruleId + "\' was removed and replaced by: " + newRules.join(", "); + } +} + +var eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//g; + +/** + * Checks whether or not there is a comment which has "eslint-env *" in a given text. + * @param {string} text - A source code text to check. + * @returns {object|null} A result of parseListConfig() with "eslint-env *" comment. + */ +function findEslintEnv(text) { + var match, retv; + + eslintEnvPattern.lastIndex = 0; + while ((match = eslintEnvPattern.exec(text))) { + retv = assign(retv || {}, parseListConfig(match[1])); + } + + return retv; +} + //------------------------------------------------------------------------------ // Public Interface //------------------------------------------------------------------------------ /** @@ -17240,23 +22011,18 @@ */ module.exports = (function() { var api = Object.create(new EventEmitter()), messages = [], - currentText = null, - currentTextLines = [], currentConfig = null, - currentTokens = null, currentScopes = null, scopeMap = null, scopeManager = null, currentFilename = null, controller = null, reportingConfig = [], - commentLocsEnter = [], - commentLocsExit = [], - currentAST = null; + sourceCode = null; /** * Parses text into an AST. Moved out here because the try-catch prevents * optimization of functions, so it's best to keep the try-catch as isolated * as possible @@ -17299,66 +22065,28 @@ attachComment: true, ecmaFeatures: config.ecmaFeatures }); } catch (ex) { + // If the message includes a leading line number, strip it: + var message = ex.message.replace(/^line \d+:/i, "").trim(); + messages.push({ fatal: true, severity: 2, - // messages come as "Line X: Unexpected token foo", so strip off leading part - message: ex.message.substring(ex.message.indexOf(":") + 1).trim(), + message: "Parsing error: " + message, line: ex.lineNumber, - column: ex.column + column: ex.column + 1 }); return null; } } /** - * Check collection of comments to prevent double event for comment as - * leading and trailing, then emit event if passing - * @param {ASTNode[]} comments Collection of comment nodes - * @param {Object[]} locs List of locations of previous comment nodes - * @param {string} eventName Event name postfix - * @returns {void} - */ - function emitComments(comments, locs, eventName) { - - if (comments.length) { - comments.forEach(function(node) { - if (locs.indexOf(node.loc) >= 0) { - locs.splice(locs.indexOf(node.loc), 1); - } else { - locs.push(node.loc); - api.emit(node.type + eventName, node); - } - }); - } - } - - /** - * Shortcut to check and emit enter of comment nodes - * @param {ASTNode[]} comments Collection of comment nodes - * @returns {void} - */ - function emitCommentsEnter(comments) { - emitComments(comments, commentLocsEnter, "Comment"); - } - - /** - * Shortcut to check and emit exit of comment nodes - * @param {ASTNode[]} comments Collection of comment nodes - * @returns {void} - */ - function emitCommentsExit(comments) { - emitComments(comments, commentLocsExit, "Comment:exit"); - } - - /** * Get the severity level of a rule (0 - none, 1 - warning, 2 - error) * Returns 0 if the rule config is not valid (an Array or a number) * @param {Array|number} ruleConfig rule configuration * @returns {number} 0, 1, or 2, indicating rule severity */ @@ -17393,107 +22121,143 @@ * @returns {void} */ api.reset = function() { this.removeAllListeners(); messages = []; - currentAST = null; currentConfig = null; - currentText = null; - currentTextLines = []; - currentTokens = null; currentScopes = null; scopeMap = null; scopeManager = null; controller = null; reportingConfig = []; - commentLocsEnter = []; - commentLocsExit = []; + sourceCode = null; }; /** * Verifies the text against the rules specified by the second argument. - * @param {string} text The JavaScript text to verify. + * @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object. * @param {Object} config An object whose keys specify the rules to use. - * @param {string=} filename The optional filename of the file being checked. - * If this is not set, the filename will default to '<input>' in the rule context. - * @param {boolean=} saveState Indicates if the state from the last run should be saved. + * @param {(string|Object)} [filenameOrOptions] The optional filename of the file being checked. + * If this is not set, the filename will default to '<input>' in the rule context. If + * an object, then it has "filename", "saveState", and "allowInlineConfig" properties. + * @param {boolean} [saveState] Indicates if the state from the last run should be saved. * Mostly useful for testing purposes. + * @param {boolean} [filenameOrOptions.allowInlineConfig] Allow/disallow inline comments' ability to change config once it is set. Defaults to true if not supplied. + * Useful if you want to validate JS without comments overriding rules. * @returns {Object[]} The results as an array of messages or null if no messages. */ - api.verify = function(text, config, filename, saveState) { + api.verify = function(textOrSourceCode, config, filenameOrOptions, saveState) { var ast, shebang, ecmaFeatures, - ecmaVersion; + ecmaVersion, + allowInlineConfig, + text = (typeof textOrSourceCode === "string") ? textOrSourceCode : null; - // set the current parsed filename - currentFilename = filename; + // evaluate arguments + if (typeof filenameOrOptions === "object") { + currentFilename = filenameOrOptions.filename; + allowInlineConfig = filenameOrOptions.allowInlineConfig; + saveState = filenameOrOptions.saveState; + } else { + currentFilename = filenameOrOptions; + } if (!saveState) { this.reset(); } - // there's no input, just exit here - if (text.trim().length === 0) { - currentText = text; - return messages; + // search and apply "eslint-env *". + var envInFile = findEslintEnv(text || textOrSourceCode.text); + if (envInFile) { + if (!config || !config.env) { + config = assign({}, config || {}, {env: envInFile}); + } else { + config = assign({}, config); + config.env = assign({}, config.env, envInFile); + } } // process initial config to make it safe to extend config = prepareConfig(config || {}); - ast = parse(text.replace(/^#!([^\r\n]+)/, function(match, captured) { - shebang = captured; - return "//" + captured; - }), config); + // only do this for text + if (text !== null) { + // there's no input, just exit here + if (text.trim().length === 0) { + sourceCode = new SourceCode(text, blankScriptAST); + return messages; + } + + ast = parse(text.replace(/^#!([^\r\n]+)/, function(match, captured) { + shebang = captured; + return "//" + captured; + }), config); + + if (ast) { + sourceCode = new SourceCode(text, ast); + } + + } else { + sourceCode = textOrSourceCode; + ast = sourceCode.ast; + } + // if espree failed to parse the file, there's no sense in setting up rules if (ast) { - currentAST = ast; - // parse global comments and modify config - modifyConfigsFromComments(ast, config, reportingConfig, messages); + if (allowInlineConfig !== false) { + config = modifyConfigsFromComments(currentFilename, ast, config, reportingConfig, messages); + } // enable appropriate rules Object.keys(config.rules).filter(function(key) { return getRuleSeverity(config.rules[key]) > 0; }).forEach(function(key) { - - var ruleCreator = rules.get(key), - severity = getRuleSeverity(config.rules[key]), - options = getRuleOptions(config.rules[key]), + var ruleCreator, + severity, + options, rule; - if (ruleCreator) { - try { - rule = ruleCreator(new RuleContext( - key, api, severity, options, - config.settings, config.ecmaFeatures - )); - - // add all the node types as listeners - Object.keys(rule).forEach(function(nodeType) { - api.on(nodeType, timing.enabled - ? timing.time(key, rule[nodeType]) - : rule[nodeType] - ); - }); - } catch(ex) { - ex.message = "Error while loading rule '" + key + "': " + ex.message; - throw ex; + ruleCreator = rules.get(key); + if (!ruleCreator) { + var replacementMsg = getRuleReplacementMessage(key); + if (replacementMsg) { + ruleCreator = createStubRule(replacementMsg); + } else { + ruleCreator = createStubRule("Definition for rule '" + key + "' was not found"); } + rules.define(key, ruleCreator); + } - } else { - throw new Error("Definition for rule '" + key + "' was not found."); + severity = getRuleSeverity(config.rules[key]); + options = getRuleOptions(config.rules[key]); + + try { + rule = ruleCreator(new RuleContext( + key, api, severity, options, + config.settings, config.ecmaFeatures + )); + + // add all the node types as listeners + Object.keys(rule).forEach(function(nodeType) { + api.on(nodeType, timing.enabled + ? timing.time(key, rule[nodeType]) + : rule[nodeType] + ); + }); + } catch (ex) { + ex.message = "Error while loading rule '" + key + "': " + ex.message; + throw ex; } }); // save config so rules can access as necessary currentConfig = config; - currentText = text; controller = new estraverse.Controller(); ecmaFeatures = currentConfig.ecmaFeatures; ecmaVersion = (ecmaFeatures.blockBindings || ecmaFeatures.classes || ecmaFeatures.modules || ecmaFeatures.defaultParams || @@ -17512,35 +22276,20 @@ /* * Index the scopes by the start range of their block for efficient * lookup in getScope. */ scopeMap = []; - currentScopes.forEach(function (scope, index) { + currentScopes.forEach(function(scope, index) { var range = scope.block.range[0]; // Sometimes two scopes are returned for a given node. This is // handled later in a known way, so just don't overwrite here. if (!scopeMap[range]) { scopeMap[range] = index; } }); - /* - * Split text here into array of lines so - * it's not being done repeatedly - * by individual rules. - */ - currentTextLines = currentText.split(/\r?\n|\u2028|\u2029/g); - - // Freezing so array isn't accidentally changed by a rule. - Object.freeze(currentTextLines); - - currentTokens = createTokenStore(ast.tokens); - Object.keys(currentTokens).forEach(function(method) { - api[method] = currentTokens[method]; - }); - // augment global scope with declared global variables addDeclaredGlobals(ast, currentScopes[0], currentConfig); // remove shebang comments if (shebang && ast.comments.length && ast.comments[0].value === shebang) { @@ -17549,32 +22298,25 @@ if (ast.body.length && ast.body[0].leadingComments && ast.body[0].leadingComments[0].value === shebang) { ast.body[0].leadingComments.splice(0, 1); } } + var eventGenerator = new NodeEventGenerator(api); + eventGenerator = new CommentEventGenerator(eventGenerator, sourceCode); + /* * Each node has a type property. Whenever a particular type of node is found, * an event is fired. This allows any listeners to automatically be informed * that this type of node has been found and react accordingly. */ controller.traverse(ast, { enter: function(node, parent) { - - var comments = api.getComments(node); - - emitCommentsEnter(comments.leading); node.parent = parent; - api.emit(node.type, node); - emitCommentsEnter(comments.trailing); + eventGenerator.enterNode(node); }, leave: function(node) { - - var comments = api.getComments(node); - - emitCommentsExit(comments.trailing); - api.emit(node.type + ":exit", node); - emitCommentsExit(comments.leading); + eventGenerator.leaveNode(node); } }); } @@ -17601,225 +22343,186 @@ * numbers. If location is not provided the node's start location will * be used. * @param {string} message The actual message. * @param {Object} opts Optional template data which produces a formatted message * with symbols being replaced by this object's values. + * @param {Object} fix A fix command description. * @returns {void} */ - api.report = function(ruleId, severity, node, location, message, opts) { + api.report = function(ruleId, severity, node, location, message, opts, fix) { + if (node) { + assert.strictEqual(typeof node, "object", "Node must be an object"); + } if (typeof location === "string") { + assert.ok(node, "Node must be provided when reporting error if location is not provided"); + + fix = opts; opts = message; message = location; location = node.loc.start; } + // else, assume location was provided, so node may be omitted - Object.keys(opts || {}).forEach(function (key) { - var rx = new RegExp("{{" + escapeRegExp(key) + "}}", "g"); - message = message.replace(rx, opts[key]); - }); - if (isDisabledByReportingConfig(reportingConfig, ruleId, location)) { return; } - messages.push({ + if (opts) { + message = message.replace(/\{\{\s*(.+?)\s*\}\}/g, function(fullMatch, term) { + if (term in opts) { + return opts[term]; + } + + // Preserve old behavior: If parameter name not provided, don't replace it. + return fullMatch; + }); + } + + var problem = { ruleId: ruleId, severity: severity, message: message, line: location.line, - column: location.column, - nodeType: node.type, - source: currentTextLines[location.line - 1] || "" - }); - }; + column: location.column + 1, // switch to 1-base instead of 0-base + nodeType: node && node.type, + source: sourceCode.lines[location.line - 1] || "" + }; - /** - * Gets the source code for the given node. - * @param {ASTNode=} node The AST node to get the text for. - * @param {int=} beforeCount The number of characters before the node to retrieve. - * @param {int=} afterCount The number of characters after the node to retrieve. - * @returns {string} The text representing the AST node. - */ - api.getSource = function(node, beforeCount, afterCount) { - if (node) { - return (currentText !== null) ? currentText.slice(Math.max(node.range[0] - (beforeCount || 0), 0), - node.range[1] + (afterCount || 0)) : null; - } else { - return currentText; + // ensure there's range and text properties, otherwise it's not a valid fix + if (fix && Array.isArray(fix.range) && (typeof fix.text === "string")) { + problem.fix = fix; } + messages.push(problem); }; /** - * Gets the entire source text split into an array of lines. - * @returns {Array} The source text as an array of lines. + * Gets the SourceCode object representing the parsed source. + * @returns {SourceCode} The SourceCode object. */ - api.getSourceLines = function() { - return currentTextLines; + api.getSourceCode = function() { + return sourceCode; }; - /** - * Retrieves an array containing all comments in the source code. - * @returns {ASTNode[]} An array of comment nodes. - */ - api.getAllComments = function() { - return currentAST.comments; + // methods that exist on SourceCode object + var externalMethods = { + getSource: "getText", + getSourceLines: "getLines", + getAllComments: "getAllComments", + getNodeByRangeIndex: "getNodeByRangeIndex", + getComments: "getComments", + getJSDocComment: "getJSDocComment", + getFirstToken: "getFirstToken", + getFirstTokens: "getFirstTokens", + getLastToken: "getLastToken", + getLastTokens: "getLastTokens", + getTokenAfter: "getTokenAfter", + getTokenBefore: "getTokenBefore", + getTokenByRangeStart: "getTokenByRangeStart", + getTokens: "getTokens", + getTokensAfter: "getTokensAfter", + getTokensBefore: "getTokensBefore", + getTokensBetween: "getTokensBetween" }; - /** - * Gets all comments for the given node. - * @param {ASTNode} node The AST node to get the comments for. - * @returns {Object} The list of comments indexed by their position. - */ - api.getComments = function(node) { + // copy over methods + Object.keys(externalMethods).forEach(function(methodName) { + var exMethodName = externalMethods[methodName]; - var leadingComments = node.leadingComments || [], - trailingComments = node.trailingComments || []; - - /* - * espree adds a "comments" array on Program nodes rather than - * leadingComments/trailingComments. Comments are only left in the - * Program node comments array if there is no executable code. - */ - if (node.type === "Program") { - if (node.body.length === 0) { - leadingComments = node.comments; + // All functions expected to have less arguments than 5. + api[methodName] = function(a, b, c, d, e) { + if (sourceCode) { + return sourceCode[exMethodName](a, b, c, d, e); } - } - - return { - leading: leadingComments, - trailing: trailingComments + return null; }; - }; + }); /** - * Retrieves the JSDoc comment for a given node. - * @param {ASTNode} node The AST node to get the comment for. - * @returns {ASTNode} The BlockComment node containing the JSDoc for the - * given node or null if not found. - */ - api.getJSDocComment = function(node) { - - var parent = node.parent, - line = node.loc.start.line; - - /** - * Finds a JSDoc comment node in an array of comment nodes. - * @param {ASTNode[]} comments The array of comment nodes to search. - * @returns {ASTNode} The node if found, null if not. - * @private - */ - function findJSDocComment(comments) { - - if (comments) { - for (var i = comments.length - 1; i >= 0; i--) { - if (comments[i].type === "Block" && comments[i].value.charAt(0) === "*") { - - if (line - comments[i].loc.end.line <= 1) { - return comments[i]; - } else { - break; - } - } - } - } - - return null; - } - - switch (node.type) { - case "FunctionDeclaration": - return findJSDocComment(node.leadingComments); - - case "ArrowFunctionExpression": - case "FunctionExpression": - - if (parent.type !== "CallExpression" || parent.callee !== node) { - while (parent && !parent.leadingComments && !/Function/.test(parent.type)) { - parent = parent.parent; - } - - return parent && (parent.type !== "FunctionDeclaration") ? findJSDocComment(parent.leadingComments) : null; - } - - // falls through - - default: - return null; - } - }; - - /** * Gets nodes that are ancestors of current node. * @returns {ASTNode[]} Array of objects representing ancestors. */ api.getAncestors = function() { return controller.parents(); }; /** - * Gets the deepest node containing a range index. - * @param {int} index Range index of the desired node. - * @returns {ASTNode} [description] - */ - api.getNodeByRangeIndex = function(index) { - var result = null; - - estraverse.traverse(controller.root, { - enter: function (node) { - if (node.range[0] <= index && index < node.range[1]) { - result = node; - } else { - this.skip(); - } - }, - leave: function (node) { - if (node === result) { - this.break(); - } - } - }); - - return result; - }; - - /** * Gets the scope for the current node. * @returns {Object} An object representing the current node's scope. */ api.getScope = function() { var parents = controller.parents(), scope = currentScopes[0]; // Don't do this for Program nodes - they have no parents if (parents.length) { - // if current node is function declaration, add it to the list + // if current node introduces a scope, add it to the list var current = controller.current(); - if (["FunctionDeclaration", "FunctionExpression", - "ArrowFunctionExpression"].indexOf(current.type) >= 0) { - parents.push(current); + if (currentConfig.ecmaFeatures.blockBindings) { + if (["BlockStatement", "SwitchStatement", "CatchClause", "FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].indexOf(current.type) >= 0) { + parents.push(current); + } + } else { + if (["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].indexOf(current.type) >= 0) { + parents.push(current); + } } // Ascend the current node's parents for (var i = parents.length - 1; i >= 0; --i) { - scope = scopeManager.acquire(parents[i]); + // Get the innermost scope + scope = scopeManager.acquire(parents[i], true); if (scope) { - return scope; + if (scope.type === "function-expression-name") { + return scope.childScopes[0]; + } else { + return scope; + } } } } return currentScopes[0]; }; /** + * Record that a particular variable has been used in code + * @param {string} name The name of the variable to mark as used + * @returns {boolean} True if the variable was found and marked as used, + * false if not. + */ + api.markVariableAsUsed = function(name) { + var scope = this.getScope(), + specialScope = currentConfig.ecmaFeatures.globalReturn || currentConfig.ecmaFeatures.modules, + variables, + i, + len; + + // Special Node.js scope means we need to start one level deeper + if (scope.type === "global" && specialScope) { + scope = scope.childScopes[0]; + } + + do { + variables = scope.variables; + for (i = 0, len = variables.length; i < len; i++) { + if (variables[i].name === name) { + variables[i].eslintUsed = true; + return true; + } + } + } while ( (scope = scope.upper) ); + + return false; + }; + + /** * Gets the filename for the currently parsed source. * @returns {string} The filename associated with the source being parsed. * Defaults to "<input>" if no filename info is present. */ api.getFilename = function() { @@ -17857,158 +22560,221 @@ */ api.defaults = function() { return require("../conf/eslint.json"); }; + /** + * Gets variables that are declared by a specified node. + * + * The variables are its `defs[].node` or `defs[].parent` is same as the specified node. + * Specifically, below: + * + * - `VariableDeclaration` - variables of its all declarators. + * - `VariableDeclarator` - variables. + * - `FunctionDeclaration`/`FunctionExpression` - its function name and parameters. + * - `ArrowFunctionExpression` - its parameters. + * - `ClassDeclaration`/`ClassExpression` - its class name. + * - `CatchClause` - variables of its exception. + * - `ImportDeclaration` - variables of its all specifiers. + * - `ImportSpecifier`/`ImportDefaultSpecifier`/`ImportNamespaceSpecifier` - a variable. + * - others - always an empty array. + * + * @param {ASTNode} node A node to get. + * @returns {escope.Variable[]} Variables that are declared by the node. + */ + api.getDeclaredVariables = function(node) { + return (scopeManager && scopeManager.getDeclaredVariables(node)) || []; + }; + return api; }()); -},{"../conf/environments":1,"../conf/eslint.json":2,"./rule-context":134,"./rules":135,"./timing":285,"./token-store.js":286,"./util":287,"escape-string-regexp":18,"escope":19,"estraverse-fb":125,"events":4,"object-assign":131}],133:[function(require,module,exports){ +},{"../conf/blank-script.json":1,"../conf/environments":2,"../conf/eslint.json":3,"../conf/replacements.json":4,"./config/config-ops":114,"./config/config-validator":115,"./rule-context":118,"./rules":119,"./timing":309,"./util/comment-event-generator":311,"./util/estraverse":312,"./util/node-event-generator":314,"./util/source-code":316,"assert":5,"escope":76,"events":96,"object-assign":108}],117:[function(require,module,exports){ module.exports = function() { var rules = Object.create(null); + rules["accessor-pairs"] = require("./rules/accessor-pairs"); + rules["array-bracket-spacing"] = require("./rules/array-bracket-spacing"); + rules["arrow-body-style"] = require("./rules/arrow-body-style"); + rules["arrow-parens"] = require("./rules/arrow-parens"); + rules["arrow-spacing"] = require("./rules/arrow-spacing"); rules["block-scoped-var"] = require("./rules/block-scoped-var"); + rules["block-spacing"] = require("./rules/block-spacing"); rules["brace-style"] = require("./rules/brace-style"); + rules["callback-return"] = require("./rules/callback-return"); rules["camelcase"] = require("./rules/camelcase"); rules["comma-dangle"] = require("./rules/comma-dangle"); rules["comma-spacing"] = require("./rules/comma-spacing"); rules["comma-style"] = require("./rules/comma-style"); rules["complexity"] = require("./rules/complexity"); + rules["computed-property-spacing"] = require("./rules/computed-property-spacing"); rules["consistent-return"] = require("./rules/consistent-return"); rules["consistent-this"] = require("./rules/consistent-this"); + rules["constructor-super"] = require("./rules/constructor-super"); rules["curly"] = require("./rules/curly"); rules["default-case"] = require("./rules/default-case"); + rules["dot-location"] = require("./rules/dot-location"); rules["dot-notation"] = require("./rules/dot-notation"); rules["eol-last"] = require("./rules/eol-last"); rules["eqeqeq"] = require("./rules/eqeqeq"); rules["func-names"] = require("./rules/func-names"); rules["func-style"] = require("./rules/func-style"); - rules["generator-star"] = require("./rules/generator-star"); - rules["global-strict"] = require("./rules/global-strict"); + rules["generator-star-spacing"] = require("./rules/generator-star-spacing"); + rules["global-require"] = require("./rules/global-require"); rules["guard-for-in"] = require("./rules/guard-for-in"); rules["handle-callback-err"] = require("./rules/handle-callback-err"); + rules["id-length"] = require("./rules/id-length"); + rules["id-match"] = require("./rules/id-match"); rules["indent"] = require("./rules/indent"); + rules["init-declarations"] = require("./rules/init-declarations"); + rules["jsx-quotes"] = require("./rules/jsx-quotes"); rules["key-spacing"] = require("./rules/key-spacing"); + rules["linebreak-style"] = require("./rules/linebreak-style"); + rules["lines-around-comment"] = require("./rules/lines-around-comment"); rules["max-depth"] = require("./rules/max-depth"); rules["max-len"] = require("./rules/max-len"); rules["max-nested-callbacks"] = require("./rules/max-nested-callbacks"); rules["max-params"] = require("./rules/max-params"); rules["max-statements"] = require("./rules/max-statements"); rules["new-cap"] = require("./rules/new-cap"); rules["new-parens"] = require("./rules/new-parens"); + rules["newline-after-var"] = require("./rules/newline-after-var"); rules["no-alert"] = require("./rules/no-alert"); rules["no-array-constructor"] = require("./rules/no-array-constructor"); + rules["no-arrow-condition"] = require("./rules/no-arrow-condition"); rules["no-bitwise"] = require("./rules/no-bitwise"); rules["no-caller"] = require("./rules/no-caller"); + rules["no-case-declarations"] = require("./rules/no-case-declarations"); rules["no-catch-shadow"] = require("./rules/no-catch-shadow"); - rules["no-comma-dangle"] = require("./rules/no-comma-dangle"); + rules["no-class-assign"] = require("./rules/no-class-assign"); rules["no-cond-assign"] = require("./rules/no-cond-assign"); rules["no-console"] = require("./rules/no-console"); + rules["no-const-assign"] = require("./rules/no-const-assign"); rules["no-constant-condition"] = require("./rules/no-constant-condition"); + rules["no-continue"] = require("./rules/no-continue"); rules["no-control-regex"] = require("./rules/no-control-regex"); rules["no-debugger"] = require("./rules/no-debugger"); rules["no-delete-var"] = require("./rules/no-delete-var"); rules["no-div-regex"] = require("./rules/no-div-regex"); rules["no-dupe-args"] = require("./rules/no-dupe-args"); + rules["no-dupe-class-members"] = require("./rules/no-dupe-class-members"); rules["no-dupe-keys"] = require("./rules/no-dupe-keys"); + rules["no-duplicate-case"] = require("./rules/no-duplicate-case"); rules["no-else-return"] = require("./rules/no-else-return"); - rules["no-empty-class"] = require("./rules/no-empty-class"); + rules["no-empty-character-class"] = require("./rules/no-empty-character-class"); rules["no-empty-label"] = require("./rules/no-empty-label"); + rules["no-empty-pattern"] = require("./rules/no-empty-pattern"); rules["no-empty"] = require("./rules/no-empty"); rules["no-eq-null"] = require("./rules/no-eq-null"); rules["no-eval"] = require("./rules/no-eval"); rules["no-ex-assign"] = require("./rules/no-ex-assign"); rules["no-extend-native"] = require("./rules/no-extend-native"); rules["no-extra-bind"] = require("./rules/no-extra-bind"); rules["no-extra-boolean-cast"] = require("./rules/no-extra-boolean-cast"); rules["no-extra-parens"] = require("./rules/no-extra-parens"); rules["no-extra-semi"] = require("./rules/no-extra-semi"); - rules["no-extra-strict"] = require("./rules/no-extra-strict"); rules["no-fallthrough"] = require("./rules/no-fallthrough"); rules["no-floating-decimal"] = require("./rules/no-floating-decimal"); rules["no-func-assign"] = require("./rules/no-func-assign"); + rules["no-implicit-coercion"] = require("./rules/no-implicit-coercion"); rules["no-implied-eval"] = require("./rules/no-implied-eval"); rules["no-inline-comments"] = require("./rules/no-inline-comments"); rules["no-inner-declarations"] = require("./rules/no-inner-declarations"); rules["no-invalid-regexp"] = require("./rules/no-invalid-regexp"); + rules["no-invalid-this"] = require("./rules/no-invalid-this"); rules["no-irregular-whitespace"] = require("./rules/no-irregular-whitespace"); rules["no-iterator"] = require("./rules/no-iterator"); rules["no-label-var"] = require("./rules/no-label-var"); rules["no-labels"] = require("./rules/no-labels"); rules["no-lone-blocks"] = require("./rules/no-lone-blocks"); rules["no-lonely-if"] = require("./rules/no-lonely-if"); rules["no-loop-func"] = require("./rules/no-loop-func"); + rules["no-magic-numbers"] = require("./rules/no-magic-numbers"); rules["no-mixed-requires"] = require("./rules/no-mixed-requires"); rules["no-mixed-spaces-and-tabs"] = require("./rules/no-mixed-spaces-and-tabs"); rules["no-multi-spaces"] = require("./rules/no-multi-spaces"); rules["no-multi-str"] = require("./rules/no-multi-str"); rules["no-multiple-empty-lines"] = require("./rules/no-multiple-empty-lines"); rules["no-native-reassign"] = require("./rules/no-native-reassign"); + rules["no-negated-condition"] = require("./rules/no-negated-condition"); rules["no-negated-in-lhs"] = require("./rules/no-negated-in-lhs"); rules["no-nested-ternary"] = require("./rules/no-nested-ternary"); rules["no-new-func"] = require("./rules/no-new-func"); rules["no-new-object"] = require("./rules/no-new-object"); rules["no-new-require"] = require("./rules/no-new-require"); rules["no-new-wrappers"] = require("./rules/no-new-wrappers"); rules["no-new"] = require("./rules/no-new"); rules["no-obj-calls"] = require("./rules/no-obj-calls"); rules["no-octal-escape"] = require("./rules/no-octal-escape"); rules["no-octal"] = require("./rules/no-octal"); + rules["no-param-reassign"] = require("./rules/no-param-reassign"); rules["no-path-concat"] = require("./rules/no-path-concat"); rules["no-plusplus"] = require("./rules/no-plusplus"); rules["no-process-env"] = require("./rules/no-process-env"); rules["no-process-exit"] = require("./rules/no-process-exit"); rules["no-proto"] = require("./rules/no-proto"); rules["no-redeclare"] = require("./rules/no-redeclare"); rules["no-regex-spaces"] = require("./rules/no-regex-spaces"); - rules["no-reserved-keys"] = require("./rules/no-reserved-keys"); rules["no-restricted-modules"] = require("./rules/no-restricted-modules"); + rules["no-restricted-syntax"] = require("./rules/no-restricted-syntax"); rules["no-return-assign"] = require("./rules/no-return-assign"); rules["no-script-url"] = require("./rules/no-script-url"); rules["no-self-compare"] = require("./rules/no-self-compare"); rules["no-sequences"] = require("./rules/no-sequences"); rules["no-shadow-restricted-names"] = require("./rules/no-shadow-restricted-names"); rules["no-shadow"] = require("./rules/no-shadow"); - rules["no-space-before-semi"] = require("./rules/no-space-before-semi"); rules["no-spaced-func"] = require("./rules/no-spaced-func"); rules["no-sparse-arrays"] = require("./rules/no-sparse-arrays"); rules["no-sync"] = require("./rules/no-sync"); rules["no-ternary"] = require("./rules/no-ternary"); + rules["no-this-before-super"] = require("./rules/no-this-before-super"); rules["no-throw-literal"] = require("./rules/no-throw-literal"); rules["no-trailing-spaces"] = require("./rules/no-trailing-spaces"); rules["no-undef-init"] = require("./rules/no-undef-init"); rules["no-undef"] = require("./rules/no-undef"); rules["no-undefined"] = require("./rules/no-undefined"); rules["no-underscore-dangle"] = require("./rules/no-underscore-dangle"); + rules["no-unexpected-multiline"] = require("./rules/no-unexpected-multiline"); + rules["no-unneeded-ternary"] = require("./rules/no-unneeded-ternary"); rules["no-unreachable"] = require("./rules/no-unreachable"); rules["no-unused-expressions"] = require("./rules/no-unused-expressions"); rules["no-unused-vars"] = require("./rules/no-unused-vars"); rules["no-use-before-define"] = require("./rules/no-use-before-define"); + rules["no-useless-call"] = require("./rules/no-useless-call"); + rules["no-useless-concat"] = require("./rules/no-useless-concat"); rules["no-var"] = require("./rules/no-var"); rules["no-void"] = require("./rules/no-void"); rules["no-warning-comments"] = require("./rules/no-warning-comments"); rules["no-with"] = require("./rules/no-with"); - rules["no-wrap-func"] = require("./rules/no-wrap-func"); + rules["object-curly-spacing"] = require("./rules/object-curly-spacing"); + rules["object-shorthand"] = require("./rules/object-shorthand"); rules["one-var"] = require("./rules/one-var"); rules["operator-assignment"] = require("./rules/operator-assignment"); + rules["operator-linebreak"] = require("./rules/operator-linebreak"); rules["padded-blocks"] = require("./rules/padded-blocks"); + rules["prefer-arrow-callback"] = require("./rules/prefer-arrow-callback"); + rules["prefer-const"] = require("./rules/prefer-const"); + rules["prefer-reflect"] = require("./rules/prefer-reflect"); + rules["prefer-spread"] = require("./rules/prefer-spread"); + rules["prefer-template"] = require("./rules/prefer-template"); rules["quote-props"] = require("./rules/quote-props"); rules["quotes"] = require("./rules/quotes"); rules["radix"] = require("./rules/radix"); + rules["require-jsdoc"] = require("./rules/require-jsdoc"); + rules["require-yield"] = require("./rules/require-yield"); rules["semi-spacing"] = require("./rules/semi-spacing"); rules["semi"] = require("./rules/semi"); rules["sort-vars"] = require("./rules/sort-vars"); - rules["space-after-function-name"] = require("./rules/space-after-function-name"); rules["space-after-keywords"] = require("./rules/space-after-keywords"); rules["space-before-blocks"] = require("./rules/space-before-blocks"); - rules["space-before-function-parentheses"] = require("./rules/space-before-function-parentheses"); - rules["space-in-brackets"] = require("./rules/space-in-brackets"); + rules["space-before-function-paren"] = require("./rules/space-before-function-paren"); + rules["space-before-keywords"] = require("./rules/space-before-keywords"); rules["space-in-parens"] = require("./rules/space-in-parens"); rules["space-infix-ops"] = require("./rules/space-infix-ops"); rules["space-return-throw-case"] = require("./rules/space-return-throw-case"); rules["space-unary-ops"] = require("./rules/space-unary-ops"); - rules["spaced-line-comment"] = require("./rules/spaced-line-comment"); + rules["spaced-comment"] = require("./rules/spaced-comment"); rules["strict"] = require("./rules/strict"); rules["use-isnan"] = require("./rules/use-isnan"); rules["valid-jsdoc"] = require("./rules/valid-jsdoc"); rules["valid-typeof"] = require("./rules/valid-typeof"); rules["vars-on-top"] = require("./rules/vars-on-top"); @@ -18016,45 +22782,71 @@ rules["wrap-regex"] = require("./rules/wrap-regex"); rules["yoda"] = require("./rules/yoda"); return rules; }; -},{"./rules/block-scoped-var":136,"./rules/brace-style":137,"./rules/camelcase":138,"./rules/comma-dangle":139,"./rules/comma-spacing":140,"./rules/comma-style":141,"./rules/complexity":142,"./rules/consistent-return":143,"./rules/consistent-this":144,"./rules/curly":145,"./rules/default-case":146,"./rules/dot-notation":147,"./rules/eol-last":148,"./rules/eqeqeq":149,"./rules/func-names":150,"./rules/func-style":151,"./rules/generator-star":152,"./rules/global-strict":153,"./rules/guard-for-in":154,"./rules/handle-callback-err":155,"./rules/indent":156,"./rules/key-spacing":157,"./rules/max-depth":158,"./rules/max-len":159,"./rules/max-nested-callbacks":160,"./rules/max-params":161,"./rules/max-statements":162,"./rules/new-cap":163,"./rules/new-parens":164,"./rules/no-alert":165,"./rules/no-array-constructor":166,"./rules/no-bitwise":167,"./rules/no-caller":168,"./rules/no-catch-shadow":169,"./rules/no-comma-dangle":170,"./rules/no-cond-assign":171,"./rules/no-console":172,"./rules/no-constant-condition":173,"./rules/no-control-regex":174,"./rules/no-debugger":175,"./rules/no-delete-var":176,"./rules/no-div-regex":177,"./rules/no-dupe-args":178,"./rules/no-dupe-keys":179,"./rules/no-else-return":180,"./rules/no-empty":183,"./rules/no-empty-class":181,"./rules/no-empty-label":182,"./rules/no-eq-null":184,"./rules/no-eval":185,"./rules/no-ex-assign":186,"./rules/no-extend-native":187,"./rules/no-extra-bind":188,"./rules/no-extra-boolean-cast":189,"./rules/no-extra-parens":190,"./rules/no-extra-semi":191,"./rules/no-extra-strict":192,"./rules/no-fallthrough":193,"./rules/no-floating-decimal":194,"./rules/no-func-assign":195,"./rules/no-implied-eval":196,"./rules/no-inline-comments":197,"./rules/no-inner-declarations":198,"./rules/no-invalid-regexp":199,"./rules/no-irregular-whitespace":200,"./rules/no-iterator":201,"./rules/no-label-var":202,"./rules/no-labels":203,"./rules/no-lone-blocks":204,"./rules/no-lonely-if":205,"./rules/no-loop-func":206,"./rules/no-mixed-requires":207,"./rules/no-mixed-spaces-and-tabs":208,"./rules/no-multi-spaces":209,"./rules/no-multi-str":210,"./rules/no-multiple-empty-lines":211,"./rules/no-native-reassign":212,"./rules/no-negated-in-lhs":213,"./rules/no-nested-ternary":214,"./rules/no-new":219,"./rules/no-new-func":215,"./rules/no-new-object":216,"./rules/no-new-require":217,"./rules/no-new-wrappers":218,"./rules/no-obj-calls":220,"./rules/no-octal":222,"./rules/no-octal-escape":221,"./rules/no-path-concat":223,"./rules/no-plusplus":224,"./rules/no-process-env":225,"./rules/no-process-exit":226,"./rules/no-proto":227,"./rules/no-redeclare":228,"./rules/no-regex-spaces":229,"./rules/no-reserved-keys":230,"./rules/no-restricted-modules":231,"./rules/no-return-assign":232,"./rules/no-script-url":233,"./rules/no-self-compare":234,"./rules/no-sequences":235,"./rules/no-shadow":237,"./rules/no-shadow-restricted-names":236,"./rules/no-space-before-semi":238,"./rules/no-spaced-func":239,"./rules/no-sparse-arrays":240,"./rules/no-sync":241,"./rules/no-ternary":242,"./rules/no-throw-literal":243,"./rules/no-trailing-spaces":244,"./rules/no-undef":246,"./rules/no-undef-init":245,"./rules/no-undefined":247,"./rules/no-underscore-dangle":248,"./rules/no-unreachable":249,"./rules/no-unused-expressions":250,"./rules/no-unused-vars":251,"./rules/no-use-before-define":252,"./rules/no-var":253,"./rules/no-void":254,"./rules/no-warning-comments":255,"./rules/no-with":256,"./rules/no-wrap-func":257,"./rules/one-var":258,"./rules/operator-assignment":259,"./rules/padded-blocks":260,"./rules/quote-props":261,"./rules/quotes":262,"./rules/radix":263,"./rules/semi":265,"./rules/semi-spacing":264,"./rules/sort-vars":266,"./rules/space-after-function-name":267,"./rules/space-after-keywords":268,"./rules/space-before-blocks":269,"./rules/space-before-function-parentheses":270,"./rules/space-in-brackets":271,"./rules/space-in-parens":272,"./rules/space-infix-ops":273,"./rules/space-return-throw-case":274,"./rules/space-unary-ops":275,"./rules/spaced-line-comment":276,"./rules/strict":277,"./rules/use-isnan":278,"./rules/valid-jsdoc":279,"./rules/valid-typeof":280,"./rules/vars-on-top":281,"./rules/wrap-iife":282,"./rules/wrap-regex":283,"./rules/yoda":284}],134:[function(require,module,exports){ +},{"./rules/accessor-pairs":120,"./rules/array-bracket-spacing":121,"./rules/arrow-body-style":122,"./rules/arrow-parens":123,"./rules/arrow-spacing":124,"./rules/block-scoped-var":125,"./rules/block-spacing":126,"./rules/brace-style":127,"./rules/callback-return":128,"./rules/camelcase":129,"./rules/comma-dangle":130,"./rules/comma-spacing":131,"./rules/comma-style":132,"./rules/complexity":133,"./rules/computed-property-spacing":134,"./rules/consistent-return":135,"./rules/consistent-this":136,"./rules/constructor-super":137,"./rules/curly":138,"./rules/default-case":139,"./rules/dot-location":140,"./rules/dot-notation":141,"./rules/eol-last":142,"./rules/eqeqeq":143,"./rules/func-names":144,"./rules/func-style":145,"./rules/generator-star-spacing":146,"./rules/global-require":147,"./rules/guard-for-in":148,"./rules/handle-callback-err":149,"./rules/id-length":150,"./rules/id-match":151,"./rules/indent":152,"./rules/init-declarations":153,"./rules/jsx-quotes":154,"./rules/key-spacing":155,"./rules/linebreak-style":156,"./rules/lines-around-comment":157,"./rules/max-depth":158,"./rules/max-len":159,"./rules/max-nested-callbacks":160,"./rules/max-params":161,"./rules/max-statements":162,"./rules/new-cap":163,"./rules/new-parens":164,"./rules/newline-after-var":165,"./rules/no-alert":166,"./rules/no-array-constructor":167,"./rules/no-arrow-condition":168,"./rules/no-bitwise":169,"./rules/no-caller":170,"./rules/no-case-declarations":171,"./rules/no-catch-shadow":172,"./rules/no-class-assign":173,"./rules/no-cond-assign":174,"./rules/no-console":175,"./rules/no-const-assign":176,"./rules/no-constant-condition":177,"./rules/no-continue":178,"./rules/no-control-regex":179,"./rules/no-debugger":180,"./rules/no-delete-var":181,"./rules/no-div-regex":182,"./rules/no-dupe-args":183,"./rules/no-dupe-class-members":184,"./rules/no-dupe-keys":185,"./rules/no-duplicate-case":186,"./rules/no-else-return":187,"./rules/no-empty":191,"./rules/no-empty-character-class":188,"./rules/no-empty-label":189,"./rules/no-empty-pattern":190,"./rules/no-eq-null":192,"./rules/no-eval":193,"./rules/no-ex-assign":194,"./rules/no-extend-native":195,"./rules/no-extra-bind":196,"./rules/no-extra-boolean-cast":197,"./rules/no-extra-parens":198,"./rules/no-extra-semi":199,"./rules/no-fallthrough":200,"./rules/no-floating-decimal":201,"./rules/no-func-assign":202,"./rules/no-implicit-coercion":203,"./rules/no-implied-eval":204,"./rules/no-inline-comments":205,"./rules/no-inner-declarations":206,"./rules/no-invalid-regexp":207,"./rules/no-invalid-this":208,"./rules/no-irregular-whitespace":209,"./rules/no-iterator":210,"./rules/no-label-var":211,"./rules/no-labels":212,"./rules/no-lone-blocks":213,"./rules/no-lonely-if":214,"./rules/no-loop-func":215,"./rules/no-magic-numbers":216,"./rules/no-mixed-requires":217,"./rules/no-mixed-spaces-and-tabs":218,"./rules/no-multi-spaces":219,"./rules/no-multi-str":220,"./rules/no-multiple-empty-lines":221,"./rules/no-native-reassign":222,"./rules/no-negated-condition":223,"./rules/no-negated-in-lhs":224,"./rules/no-nested-ternary":225,"./rules/no-new":230,"./rules/no-new-func":226,"./rules/no-new-object":227,"./rules/no-new-require":228,"./rules/no-new-wrappers":229,"./rules/no-obj-calls":231,"./rules/no-octal":233,"./rules/no-octal-escape":232,"./rules/no-param-reassign":234,"./rules/no-path-concat":235,"./rules/no-plusplus":236,"./rules/no-process-env":237,"./rules/no-process-exit":238,"./rules/no-proto":239,"./rules/no-redeclare":240,"./rules/no-regex-spaces":241,"./rules/no-restricted-modules":242,"./rules/no-restricted-syntax":243,"./rules/no-return-assign":244,"./rules/no-script-url":245,"./rules/no-self-compare":246,"./rules/no-sequences":247,"./rules/no-shadow":249,"./rules/no-shadow-restricted-names":248,"./rules/no-spaced-func":250,"./rules/no-sparse-arrays":251,"./rules/no-sync":252,"./rules/no-ternary":253,"./rules/no-this-before-super":254,"./rules/no-throw-literal":255,"./rules/no-trailing-spaces":256,"./rules/no-undef":258,"./rules/no-undef-init":257,"./rules/no-undefined":259,"./rules/no-underscore-dangle":260,"./rules/no-unexpected-multiline":261,"./rules/no-unneeded-ternary":262,"./rules/no-unreachable":263,"./rules/no-unused-expressions":264,"./rules/no-unused-vars":265,"./rules/no-use-before-define":266,"./rules/no-useless-call":267,"./rules/no-useless-concat":268,"./rules/no-var":269,"./rules/no-void":270,"./rules/no-warning-comments":271,"./rules/no-with":272,"./rules/object-curly-spacing":273,"./rules/object-shorthand":274,"./rules/one-var":275,"./rules/operator-assignment":276,"./rules/operator-linebreak":277,"./rules/padded-blocks":278,"./rules/prefer-arrow-callback":279,"./rules/prefer-const":280,"./rules/prefer-reflect":281,"./rules/prefer-spread":282,"./rules/prefer-template":283,"./rules/quote-props":284,"./rules/quotes":285,"./rules/radix":286,"./rules/require-jsdoc":287,"./rules/require-yield":288,"./rules/semi":290,"./rules/semi-spacing":289,"./rules/sort-vars":291,"./rules/space-after-keywords":292,"./rules/space-before-blocks":293,"./rules/space-before-function-paren":294,"./rules/space-before-keywords":295,"./rules/space-in-parens":296,"./rules/space-infix-ops":297,"./rules/space-return-throw-case":298,"./rules/space-unary-ops":299,"./rules/spaced-comment":300,"./rules/strict":301,"./rules/use-isnan":302,"./rules/valid-jsdoc":303,"./rules/valid-typeof":304,"./rules/vars-on-top":305,"./rules/wrap-iife":306,"./rules/wrap-regex":307,"./rules/yoda":308}],118:[function(require,module,exports){ /** * @fileoverview RuleContext utility for rules * @author Nicholas C. Zakas + * @copyright 2013 Nicholas C. Zakas. All rights reserved. + * See LICENSE file in root directory for full license. */ "use strict"; //------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var RuleFixer = require("./util/rule-fixer"); + +//------------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------------ var PASSTHROUGHS = [ - "getAllComments", - "getAncestors", - "getComments", - "getFilename", - "getFirstToken", - "getFirstTokens", - "getJSDocComment", - "getLastToken", - "getLastTokens", - "getNodeByRangeIndex", - "getScope", - "getSource", - "getSourceLines", - "getTokenAfter", - "getTokenBefore", - "getTokenByRangeStart", - "getTokens", - "getTokensAfter", - "getTokensBefore", - "getTokensBetween" - ]; + "getAllComments", + "getAncestors", + "getComments", + "getDeclaredVariables", + "getFilename", + "getFirstToken", + "getFirstTokens", + "getJSDocComment", + "getLastToken", + "getLastTokens", + "getNodeByRangeIndex", + "getScope", + "getSource", + "getSourceLines", + "getTokenAfter", + "getTokenBefore", + "getTokenByRangeStart", + "getTokens", + "getTokensAfter", + "getTokensBefore", + "getTokensBetween", + "markVariableAsUsed", + "isMarkedAsUsed" +]; //------------------------------------------------------------------------------ +// Typedefs +//------------------------------------------------------------------------------ + +/** + * An error message description + * @typedef {Object} MessageDescriptor + * @property {string} nodeType The type of node. + * @property {Location} loc The location of the problem. + * @property {string} message The problem message. + * @property {Object} [data] Optional data to use to fill in placeholders in the + * message. + * @property {Function} fix The function to call that creates a fix command. + */ + +//------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ /** * Acts as an abstraction layer between rules and the main eslint object. @@ -18104,30 +22896,62 @@ }; }, this); /** * Passthrough to eslint.report() that automatically assigns the rule ID and severity. - * @param {ASTNode} node The AST node related to the message. + * @param {ASTNode|MessageDescriptor} nodeOrDescriptor The AST node related to the message or a message + * descriptor. * @param {Object=} location The location of the error. * @param {string} message The message to display to the user. * @param {Object} opts Optional template data which produces a formatted message * with symbols being replaced by this object's values. * @returns {void} */ - this.report = function(node, location, message, opts) { - eslint.report(ruleId, severity, node, location, message, opts); + this.report = function(nodeOrDescriptor, location, message, opts) { + + var descriptor, + fix = null; + + // check to see if it's a new style call + if (arguments.length === 1) { + descriptor = nodeOrDescriptor; + + // if there's a fix specified, get it + if (typeof descriptor.fix === "function") { + fix = descriptor.fix(new RuleFixer()); + } + + eslint.report( + ruleId, severity, descriptor.node, + descriptor.loc || descriptor.node.loc.start, + descriptor.message, descriptor.data, fix + ); + + return; + } + + // old style call + eslint.report(ruleId, severity, nodeOrDescriptor, location, message, opts); }; + /** + * Passthrough to eslint.getSourceCode(). + * @returns {SourceCode} The SourceCode object for the code. + */ + this.getSourceCode = function() { + return eslint.getSourceCode(); + }; + } RuleContext.prototype = { constructor: RuleContext }; module.exports = RuleContext; -},{}],135:[function(require,module,exports){ +},{"./util/rule-fixer":315}],119:[function(require,module,exports){ /** * @fileoverview Defines a storage for rules. * @author Nicholas C. Zakas */ @@ -18157,12 +22981,10 @@ */ function define(ruleId, ruleModule) { rules[ruleId] = ruleModule; } -exports.define = define; - /** * Loads and registers all rules from passed rules directory. * @param {String} [rulesDir] Path to rules directory, may be relative. Defaults to `lib/rules`. * @returns {void} */ @@ -18171,262 +22993,939 @@ Object.keys(newRules).forEach(function(ruleId) { define(ruleId, newRules[ruleId]); }); } -exports.load = load; - /** * Registers all given rules of a plugin. * @param {Object} pluginRules A key/value map of rule definitions. * @param {String} pluginName The name of the plugin without prefix (`eslint-plugin-`). * @returns {void} */ -exports.import = function (pluginRules, pluginName) { - Object.keys(pluginRules).forEach(function (ruleId) { +function importPlugin(pluginRules, pluginName) { + Object.keys(pluginRules).forEach(function(ruleId) { var qualifiedRuleId = pluginName + "/" + ruleId, rule = pluginRules[ruleId]; define(qualifiedRuleId, rule); }); -}; +} /** * Access rule handler by id (file name). * @param {String} ruleId Rule id (file name). * @returns {Function} Rule handler. */ -exports.get = function(ruleId) { - return rules[ruleId]; -}; +function get(ruleId) { + if (typeof rules[ruleId] === "string") { + return require(rules[ruleId]); + } else { + return rules[ruleId]; + } +} /** * Reset rules storage. * Should be used only in tests. * @returns {void} */ -exports.testClear = function() { +function testClear() { rules = Object.create(null); +} + +module.exports = { + define: define, + load: load, + import: importPlugin, + get: get, + testClear: testClear }; //------------------------------------------------------------------------------ // Initialization //------------------------------------------------------------------------------ // loads built-in rules load(); -},{"./load-rules":133}],136:[function(require,module,exports){ +},{"./load-rules":117}],120:[function(require,module,exports){ /** - * @fileoverview Rule to check for "block scoped" variables by binding context - * @author Matt DuVall <http://www.mattduvall.com> + * @fileoverview Rule to flag wrapping non-iife in parens + * @author Gyandeep Singh + * @copyright 2015 Gyandeep Singh. All rights reserved. */ + "use strict"; //------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Checks whether or not a given node is an `Identifier` node which was named a given name. + * @param {ASTNode} node - A node to check. + * @param {string} name - An expected name of the node. + * @returns {boolean} `true` if the node is an `Identifier` node which was named as expected. + */ +function isIdentifier(node, name) { + return node.type === "Identifier" && node.name === name; +} + +/** + * Checks whether or not a given node is an argument of a specified method call. + * @param {ASTNode} node - A node to check. + * @param {number} index - An expected index of the node in arguments. + * @param {string} object - An expected name of the object of the method. + * @param {string} property - An expected name of the method. + * @returns {boolean} `true` if the node is an argument of the specified method call. + */ +function isArgumentOfMethodCall(node, index, object, property) { + var parent = node.parent; + return ( + parent.type === "CallExpression" && + parent.callee.type === "MemberExpression" && + parent.callee.computed === false && + isIdentifier(parent.callee.object, object) && + isIdentifier(parent.callee.property, property) && + parent.arguments[index] === node + ); +} + +/** + * Checks whether or not a given node is a property descriptor. + * @param {ASTNode} node - A node to check. + * @returns {boolean} `true` if the node is a property descriptor. + */ +function isPropertyDescriptor(node) { + // Object.defineProperty(obj, "foo", {set: ...}) + if (isArgumentOfMethodCall(node, 2, "Object", "defineProperty") || + isArgumentOfMethodCall(node, 2, "Reflect", "defineProperty") + ) { + return true; + } + + // Object.defineProperties(obj, {foo: {set: ...}}) + // Object.create(proto, {foo: {set: ...}}) + node = node.parent.parent; + return node.type === "ObjectExpression" && ( + isArgumentOfMethodCall(node, 1, "Object", "create") || + isArgumentOfMethodCall(node, 1, "Object", "defineProperties") + ); +} + +//------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var config = context.options[0] || {}; + var checkGetWithoutSet = config.getWithoutSet === true; + var checkSetWithoutGet = config.setWithoutGet !== false; - var scopeStack = []; + /** + * Checks a object expression to see if it has setter and getter both present or none. + * @param {ASTNode} node The node to check. + * @returns {void} + * @private + */ + function checkLonelySetGet(node) { + var isSetPresent = false; + var isGetPresent = false; + var isDescriptor = isPropertyDescriptor(node); + for (var i = 0, end = node.properties.length; i < end; i++) { + var property = node.properties[i]; + + var propToCheck = ""; + if (property.kind === "init") { + if (isDescriptor && !property.computed) { + propToCheck = property.key.name; + } + } else { + propToCheck = property.kind; + } + + switch (propToCheck) { + case "set": + isSetPresent = true; + break; + + case "get": + isGetPresent = true; + break; + + default: + // Do nothing + } + + if (isSetPresent && isGetPresent) { + break; + } + } + + if (checkSetWithoutGet && isSetPresent && !isGetPresent) { + context.report(node, "Getter is not present"); + } else if (checkGetWithoutSet && isGetPresent && !isSetPresent) { + context.report(node, "Setter is not present"); + } + } + + return { + "ObjectExpression": function(node) { + if (checkSetWithoutGet || checkGetWithoutSet) { + checkLonelySetGet(node); + } + } + }; + +}; + +module.exports.schema = [ + { + "type": "object", + "properties": { + "getWithoutSet": { + "type": "boolean" + }, + "setWithoutGet": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{}],121:[function(require,module,exports){ +/** + * @fileoverview Disallows or enforces spaces inside of array brackets. + * @author Jamund Ferguson + * @copyright 2015 Jamund Ferguson. All rights reserved. + * @copyright 2014 Brandyn Bennett. All rights reserved. + * @copyright 2014 Michael Ficarra. No rights reserved. + * @copyright 2014 Vignesh Anand. All rights reserved. + */ +"use strict"; + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var spaced = context.options[0] === "always", + sourceCode = context.getSourceCode(); + + /** + * Determines whether an option is set, relative to the spacing option. + * If spaced is "always", then check whether option is set to false. + * If spaced is "never", then check whether option is set to true. + * @param {Object} option - The option to exclude. + * @returns {boolean} Whether or not the property is excluded. + */ + function isOptionSet(option) { + return context.options[1] ? context.options[1][option] === !spaced : false; + } + + var options = { + spaced: spaced, + singleElementException: isOptionSet("singleValue"), + objectsInArraysException: isOptionSet("objectsInArrays"), + arraysInArraysException: isOptionSet("arraysInArrays") + }; + //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- /** - * Determines whether an identifier is in declaration position or is a non-declaration reference. - * @param {ASTNode} id The identifier. - * @param {ASTNode} parent The identifier's parent AST node. - * @returns {Boolean} true when the identifier is in declaration position. + * Reports that there shouldn't be a space after the first token + * @param {ASTNode} node - The node to report in the event of an error. + * @param {Token} token - The token to use for the report. + * @returns {void} + */ + function reportNoBeginningSpace(node, token) { + context.report({ + node: node, + loc: token.loc.start, + message: "There should be no space after '" + token.value + "'", + fix: function(fixer) { + var nextToken = context.getSourceCode().getTokenAfter(token); + return fixer.removeRange([token.range[1], nextToken.range[0]]); + } + }); + } + + /** + * Reports that there shouldn't be a space before the last token + * @param {ASTNode} node - The node to report in the event of an error. + * @param {Token} token - The token to use for the report. + * @returns {void} + */ + function reportNoEndingSpace(node, token) { + context.report({ + node: node, + loc: token.loc.start, + message: "There should be no space before '" + token.value + "'", + fix: function(fixer) { + var previousToken = context.getSourceCode().getTokenBefore(token); + return fixer.removeRange([previousToken.range[1], token.range[0]]); + } + }); + } + + /** + * Reports that there should be a space after the first token + * @param {ASTNode} node - The node to report in the event of an error. + * @param {Token} token - The token to use for the report. + * @returns {void} + */ + function reportRequiredBeginningSpace(node, token) { + context.report({ + node: node, + loc: token.loc.start, + message: "A space is required after '" + token.value + "'", + fix: function(fixer) { + return fixer.insertTextAfter(token, " "); + } + }); + } + + /** + * Reports that there should be a space before the last token + * @param {ASTNode} node - The node to report in the event of an error. + * @param {Token} token - The token to use for the report. + * @returns {void} + */ + function reportRequiredEndingSpace(node, token) { + context.report({ + node: node, + loc: token.loc.start, + message: "A space is required before '" + token.value + "'", + fix: function(fixer) { + return fixer.insertTextBefore(token, " "); + } + }); + } + + /** + * Determines if a node is an object type + * @param {ASTNode} node - The node to check. + * @returns {boolean} Whether or not the node is an object type. + */ + function isObjectType(node) { + return node && (node.type === "ObjectExpression" || node.type === "ObjectPattern"); + } + + /** + * Determines if a node is an array type + * @param {ASTNode} node - The node to check. + * @returns {boolean} Whether or not the node is an array type. + */ + function isArrayType(node) { + return node && (node.type === "ArrayExpression" || node.type === "ArrayPattern"); + } + + /** + * Validates the spacing around array brackets + * @param {ASTNode} node - The node we're checking for spacing + * @returns {void} */ - function isDeclaration(id, parent) { - switch (parent.type) { - case "FunctionDeclaration": - case "FunctionExpression": - return parent.params.indexOf(id) > -1 || id === parent.id; + function validateArraySpacing(node) { + if (options.spaced && node.elements.length === 0) { + return; + } - case "VariableDeclarator": - return id === parent.id; + var first = context.getFirstToken(node), + second = context.getFirstToken(node, 1), + penultimate = context.getLastToken(node, 1), + last = context.getLastToken(node), + firstElement = node.elements[0], + lastElement = node.elements[node.elements.length - 1]; - case "CatchClause": - return id === parent.param; + var openingBracketMustBeSpaced = + options.objectsInArraysException && isObjectType(firstElement) || + options.arraysInArraysException && isArrayType(firstElement) || + options.singleElementException && node.elements.length === 1 + ? !options.spaced : options.spaced; - default: - return false; + var closingBracketMustBeSpaced = + options.objectsInArraysException && isObjectType(lastElement) || + options.arraysInArraysException && isArrayType(lastElement) || + options.singleElementException && node.elements.length === 1 + ? !options.spaced : options.spaced; + + if (astUtils.isTokenOnSameLine(first, second)) { + if (openingBracketMustBeSpaced && !sourceCode.isSpaceBetweenTokens(first, second)) { + reportRequiredBeginningSpace(node, first); + } + if (!openingBracketMustBeSpaced && sourceCode.isSpaceBetweenTokens(first, second)) { + reportNoBeginningSpace(node, first); + } } + + if (first !== penultimate && astUtils.isTokenOnSameLine(penultimate, last)) { + if (closingBracketMustBeSpaced && !sourceCode.isSpaceBetweenTokens(penultimate, last)) { + reportRequiredEndingSpace(node, last); + } + if (!closingBracketMustBeSpaced && sourceCode.isSpaceBetweenTokens(penultimate, last)) { + reportNoEndingSpace(node, last); + } + } } + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + return { + ArrayPattern: validateArraySpacing, + ArrayExpression: validateArraySpacing + }; + +}; + +module.exports.schema = [ + { + "enum": ["always", "never"] + }, + { + "type": "object", + "properties": { + "singleValue": { + "type": "boolean" + }, + "objectsInArrays": { + "type": "boolean" + }, + "arraysInArrays": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{"../ast-utils":113}],122:[function(require,module,exports){ +/** + * @fileoverview Rule to require braces in arrow function body. + * @author Alberto Rodríguez + * @copyright 2015 Alberto Rodríguez. All rights reserved. + * See LICENSE file in root directory for full license. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var always = context.options[0] === "always"; + var asNeeded = !context.options[0] || context.options[0] === "as-needed"; + /** - * Determines whether an identifier is in property position. - * @param {ASTNode} id The identifier. - * @param {ASTNode} parent The identifier's parent AST node. - * @returns {Boolean} true when the identifier is in property position. + * Determines whether a arrow function body needs braces + * @param {ASTNode} node The arrow function node. + * @returns {void} */ - function isProperty(id, parent) { - switch (parent.type) { - case "MemberExpression": - return id === parent.property && !parent.computed; + function validate(node) { + var arrowBody = node.body; + if (arrowBody.type === "BlockStatement") { + var blockBody = arrowBody.body; - case "Property": - return id === parent.key; + if (blockBody.length > 1) { + return; + } - default: - return false; + if (blockBody.length === 0) { + var hasComments = context.getComments(arrowBody).trailing.length > 0; + if (hasComments) { + return; + } + + context.report({ + node: node, + loc: arrowBody.loc.start, + message: "Unexpected empty block in arrow body." + }); + } else { + if (asNeeded && blockBody[0].type === "ReturnStatement") { + context.report({ + node: node, + loc: arrowBody.loc.start, + message: "Unexpected block statement surrounding arrow body." + }); + } + } + } else { + if (always) { + context.report({ + node: node, + loc: arrowBody.loc.start, + message: "Expected block statement surrounding arrow body." + }); + } } } + return { + "ArrowFunctionExpression": validate + }; +}; + +module.exports.schema = [ + { + "enum": ["always", "as-needed"] + } +]; + +},{}],123:[function(require,module,exports){ +/** + * @fileoverview Rule to require parens in arrow function arguments. + * @author Jxck + * @copyright 2015 Jxck. All rights reserved. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var message = "Expected parentheses around arrow function argument."; + var asNeededMessage = "Unexpected parentheses around single function argument"; + var asNeeded = context.options[0] === "as-needed"; + /** - * Pushes a new scope object on the scope stack. + * Determines whether a arrow function argument end with `)` + * @param {ASTNode} node The arrow function node. * @returns {void} */ - function pushScope() { - scopeStack.push([]); + function parens(node) { + var token = context.getFirstToken(node); + + // as-needed: x => x + if (asNeeded && node.params.length === 1 && node.params[0].type === "Identifier") { + if (token.type === "Punctuator" && token.value === "(") { + context.report(node, asNeededMessage); + } + return; + } + + if (token.type === "Identifier") { + var after = context.getTokenAfter(token); + + // (x) => x + if (after.value !== ")") { + context.report(node, message); + } + } } + return { + "ArrowFunctionExpression": parens + }; +}; + +module.exports.schema = [ + { + "enum": ["always", "as-needed"] + } +]; + +},{}],124:[function(require,module,exports){ +/** + * @fileoverview Rule to require parens in arrow function arguments. + * @author Jxck + * @copyright 2015 Jxck. All rights reserved. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + // merge rules with default + var rule = { before: true, after: true }; + var option = context.options[0] || {}; + rule.before = option.before !== false; + rule.after = option.after !== false; + /** - * Removes the topmost scope object from the scope stack. - * @returns {void} + * Get tokens of arrow(`=>`) and before/after arrow. + * @param {ASTNode} node The arrow function node. + * @returns {Object} Tokens of arrow and before/after arrow. */ - function popScope() { - scopeStack.pop(); + function getTokens(node) { + var t = context.getFirstToken(node); + var before; + while (t.type !== "Punctuator" || t.value !== "=>") { + before = t; + t = context.getTokenAfter(t); + } + var after = context.getTokenAfter(t); + return { before: before, arrow: t, after: after }; } /** - * Declares the given names in the topmost scope object. - * @param {[String]} names A list of names to declare. + * Count spaces before/after arrow(`=>`) token. + * @param {Object} tokens Tokens before/after arrow. + * @returns {Object} count of space before/after arrow. + */ + function countSpaces(tokens) { + var before = tokens.arrow.range[0] - tokens.before.range[1]; + var after = tokens.after.range[0] - tokens.arrow.range[1]; + return { before: before, after: after }; + } + + /** + * Determines whether space(s) before after arrow(`=>`) is satisfy rule. + * if before/after value is `true`, there should be space(s). + * if before/after value is `false`, there should be no space. + * @param {ASTNode} node The arrow function node. * @returns {void} */ - function declare(names) { - [].push.apply(scopeStack[scopeStack.length - 1], names); + function spaces(node) { + var tokens = getTokens(node); + var countSpace = countSpaces(tokens); + + if (rule.before) { + // should be space(s) before arrow + if (countSpace.before === 0) { + context.report({ + node: tokens.before, + message: "Missing space before =>", + fix: function(fixer) { + return fixer.insertTextBefore(tokens.arrow, " "); + } + }); + } + } else { + // should be no space before arrow + if (countSpace.before > 0) { + context.report({ + node: tokens.before, + message: "Unexpected space before =>", + fix: function(fixer) { + return fixer.removeRange([tokens.before.range[1], tokens.arrow.range[0]]); + } + }); + } + } + + if (rule.after) { + // should be space(s) after arrow + if (countSpace.after === 0) { + context.report({ + node: tokens.after, + message: "Missing space after =>", + fix: function(fixer) { + return fixer.insertTextAfter(tokens.arrow, " "); + } + }); + } + } else { + // should be no space after arrow + if (countSpace.after > 0) { + context.report({ + node: tokens.after, + message: "Unexpected space after =>", + fix: function(fixer) { + return fixer.removeRange([tokens.arrow.range[1], tokens.after.range[0]]); + } + }); + } + } } - //-------------------------------------------------------------------------- - // Public API - //-------------------------------------------------------------------------- + return { + "ArrowFunctionExpression": spaces + }; +}; - function functionHandler(node) { - pushScope(); - declare(node.params.map(function(id) { - return id.name; - })); - declare(node.id ? [node.id.name] : []); - declare(node.rest ? [node.rest.name] : []); - declare(["arguments"]); +module.exports.schema = [ + { + "type": "object", + "properties": { + "before": { + "type": "boolean" + }, + "after": { + "type": "boolean" + } + }, + "additionalProperties": false } +]; - function variableDeclarationHandler(node) { - node.declarations.forEach(function(declaration) { +},{}],125:[function(require,module,exports){ +/** + * @fileoverview Rule to check for "block scoped" variables by binding context + * @author Matt DuVall <http://www.mattduvall.com> + * @copyright 2015 Toru Nagashima. All rights reserved. + * @copyright 2015 Mathieu M-Gosselin. All rights reserved. + */ +"use strict"; - switch (declaration.id.type) { - case "Identifier": - declare([declaration.id.name]); - break; +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ - case "ObjectPattern": - declare(declaration.id.properties.map(function(property) { - return property.key.name; - })); - break; +/** + * Collects unresolved references from the global scope, then creates a map to references from its name. + * @param {RuleContext} context - The current context. + * @returns {object} A map object. Its key is the variable names. Its value is the references of each variable. + */ +function collectUnresolvedReferences(context) { + var unresolved = Object.create(null); + var references = context.getScope().through; - case "ArrayPattern": - declare(declaration.id.elements.map(function(element) { - return element.name; - })); - break; + for (var i = 0; i < references.length; ++i) { + var reference = references[i]; + var name = reference.identifier.name; - // no default - } + if (name in unresolved === false) { + unresolved[name] = []; + } + unresolved[name].push(reference); + } - }); + return unresolved; +} +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var unresolvedReferences = Object.create(null); + var stack = []; + + /** + * Makes a block scope. + * @param {ASTNode} node - A node of a scope. + * @returns {void} + */ + function enterScope(node) { + stack.push(node.range); } - return { - "Program": function() { - var scope = context.getScope(); - scopeStack = [scope.variables.map(function(v) { - return v.name; - })]; + /** + * Pops the last block scope. + * @returns {void} + */ + function exitScope() { + stack.pop(); + } - // global return creates another scope - if (context.ecmaFeatures.globalReturn) { - scope = scope.childScopes[0]; - scopeStack.push(scope.variables.map(function(v) { - return v.name; - })); + /** + * Reports a given reference. + * @param {escope.Reference} reference - A reference to report. + * @returns {void} + */ + function report(reference) { + var identifier = reference.identifier; + context.report( + identifier, + "\"{{name}}\" used outside of binding context.", + {name: identifier.name}); + } + + /** + * Finds and reports references which are outside of valid scopes. + * @param {ASTNode} node - A node to get variables. + * @returns {void} + */ + function checkForVariables(node) { + if (node.kind !== "var") { + return; + } + + var isGlobal = context.getScope().type === "global"; + + // Defines a predicate to check whether or not a given reference is outside of valid scope. + var scopeRange = stack[stack.length - 1]; + + /** + * Check if a reference is out of scope + * @param {ASTNode} reference node to examine + * @returns {boolean} True is its outside the scope + * @private + */ + function isOutsideOfScope(reference) { + var idRange = reference.identifier.range; + return idRange[0] < scopeRange[0] || idRange[1] > scopeRange[1]; + } + + // Gets declared variables, and checks its references. + var variables = context.getDeclaredVariables(node); + for (var i = 0; i < variables.length; ++i) { + var variable = variables[i]; + var references = variable.references; + + // Global variables are not resolved. + // In this case, use unresolved references. + if (isGlobal && variable.name in unresolvedReferences) { + references = unresolvedReferences[variable.name]; } - }, - "BlockStatement": function(node) { - var statements = node.body; - pushScope(); - statements.forEach(function(stmt) { - if (stmt.type === "VariableDeclaration") { - variableDeclarationHandler(stmt); - } else if (stmt.type === "FunctionDeclaration") { - declare([stmt.id.name]); - } - }); - }, + // Reports. + references.filter(isOutsideOfScope).forEach(report); + } + } - "VariableDeclaration": function (node) { - variableDeclarationHandler(node); + return { + "Program": function(node) { + unresolvedReferences = collectUnresolvedReferences(context); + stack = [node.range]; }, - "BlockStatement:exit": popScope, + // Manages scopes. + "BlockStatement": enterScope, + "BlockStatement:exit": exitScope, + "ForStatement": enterScope, + "ForStatement:exit": exitScope, + "ForInStatement": enterScope, + "ForInStatement:exit": exitScope, + "ForOfStatement": enterScope, + "ForOfStatement:exit": exitScope, + "SwitchStatement": enterScope, + "SwitchStatement:exit": exitScope, + "CatchClause": enterScope, + "CatchClause:exit": exitScope, - "CatchClause": function(node) { - pushScope(); - declare([node.param.name]); - }, - "CatchClause:exit": popScope, + // Finds and reports references which are outside of valid scope. + "VariableDeclaration": checkForVariables + }; - "FunctionDeclaration": functionHandler, - "FunctionDeclaration:exit": popScope, +}; - "FunctionExpression": functionHandler, - "FunctionExpression:exit": popScope, +module.exports.schema = []; - "ArrowFunctionExpression": functionHandler, - "ArrowFunctionExpression:exit": popScope, +},{}],126:[function(require,module,exports){ +/** + * @fileoverview A rule to disallow or enforce spaces inside of single line blocks. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + */ - "ForStatement": function() { - pushScope(); - }, - "ForStatement:exit": popScope, +"use strict"; - "ForInStatement": function() { - pushScope(); - }, - "ForInStatement:exit": popScope, +var util = require("../ast-utils"); - "ForOfStatement": function() { - pushScope(); - }, - "ForOfStatement:exit": popScope, +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ - "Identifier": function(node) { - var ancestor = context.getAncestors().pop(); - if (isDeclaration(node, ancestor) || isProperty(node, ancestor) || ancestor.type === "LabeledStatement") { - return; +module.exports = function(context) { + var always = (context.options[0] !== "never"), + message = always ? "Requires a space" : "Unexpected space(s)", + sourceCode = context.getSourceCode(); + + /** + * Gets the open brace token from a given node. + * @param {ASTNode} node - A BlockStatement/SwitchStatement node to get. + * @returns {Token} The token of the open brace. + */ + function getOpenBrace(node) { + if (node.type === "SwitchStatement") { + if (node.cases.length > 0) { + return context.getTokenBefore(node.cases[0]); } + return context.getLastToken(node, 1); + } + return context.getFirstToken(node); + } - for (var i = 0, l = scopeStack.length; i < l; i++) { - if (scopeStack[i].indexOf(node.name) > -1) { - return; + /** + * Checks whether or not: + * - given tokens are on same line. + * - there is/isn't a space between given tokens. + * @param {Token} left - A token to check. + * @param {Token} right - The token which is next to `left`. + * @returns {boolean} + * When the option is `"always"`, `true` if there are one or more spaces between given tokens. + * When the option is `"never"`, `true` if there are not any spaces between given tokens. + * If given tokens are not on same line, it's always `true`. + */ + function isValid(left, right) { + return ( + !util.isTokenOnSameLine(left, right) || + sourceCode.isSpaceBetweenTokens(left, right) === always + ); + } + + /** + * Reports invalid spacing style inside braces. + * @param {ASTNode} node - A BlockStatement/SwitchStatement node to get. + * @returns {void} + */ + function checkSpacingInsideBraces(node) { + // Gets braces and the first/last token of content. + var openBrace = getOpenBrace(node); + var closeBrace = context.getLastToken(node); + var firstToken = sourceCode.getTokenOrCommentAfter(openBrace); + var lastToken = sourceCode.getTokenOrCommentBefore(closeBrace); + + // Skip if the node is invalid or empty. + if (openBrace.type !== "Punctuator" || + openBrace.value !== "{" || + closeBrace.type !== "Punctuator" || + closeBrace.value !== "}" || + firstToken === closeBrace + ) { + return; + } + + // Skip line comments for option never + if (!always && firstToken.type === "Line") { + return; + } + + // Check. + if (!isValid(openBrace, firstToken)) { + context.report({ + node: node, + loc: openBrace.loc.start, + message: message + " after \"{\".", + fix: function(fixer) { + if (always) { + return fixer.insertTextBefore(firstToken, " "); + } + + return fixer.removeRange([openBrace.range[1], firstToken.range[0]]); } - } + }); + } + if (!isValid(lastToken, closeBrace)) { + context.report({ + node: node, + loc: closeBrace.loc.start, + message: message + " before \"}\".", + fix: function(fixer) { + if (always) { + return fixer.insertTextAfter(lastToken, " "); + } - context.report(node, "\"" + node.name + "\" used outside of binding context."); + return fixer.removeRange([lastToken.range[1], closeBrace.range[0]]); + } + }); } - }; + } + return { + BlockStatement: checkSpacingInsideBraces, + SwitchStatement: checkSpacingInsideBraces + }; }; -},{}],137:[function(require,module,exports){ +module.exports.schema = [ + {enum: ["always", "never"]} +]; + +},{"../ast-utils":113}],127:[function(require,module,exports){ /** * @fileoverview Rule to flag block statements that do not use the one true brace style * @author Ian Christian Myers */ @@ -18439,14 +23938,15 @@ module.exports = function(context) { var style = context.options[0] || "1tbs"; var params = context.options[1] || {}; var OPEN_MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.", + OPEN_MESSAGE_ALLMAN = "Opening curly brace appears on the same line as controlling statement.", BODY_MESSAGE = "Statement inside of curly braces should be on next line.", CLOSE_MESSAGE = "Closing curly brace does not appear on the same line as the subsequent block.", CLOSE_MESSAGE_SINGLE = "Closing curly brace should be on the same line as opening curly brace or on the line after the previous block.", - CLOSE_MESSAGE_STROUSTRUP = "Closing curly brace appears on the same line as the subsequent block."; + CLOSE_MESSAGE_STROUSTRUP_ALLMAN = "Closing curly brace appears on the same line as the subsequent block."; //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- @@ -18458,10 +23958,19 @@ */ function isBlock(node) { return node && node.type === "BlockStatement"; } + /** + * Check if the token is an punctuator with a value of curly brace + * @param {object} token - Token to check + * @returns {boolean} true if its a curly punctuator + * @private + */ + function isCurlyPunctuator(token) { + return token.value === "{" || token.value === "}"; + } /** * Binds a list of properties to a function that verifies that the opening * curly brace is on the same line as its controlling statement of a given * node. @@ -18473,32 +23982,34 @@ var blockProperties = arguments; return function(node) { [].forEach.call(blockProperties, function(blockProp) { var block = node[blockProp], previousToken, curlyToken, curlyTokenEnd, curlyTokensOnSameLine; - block = node[blockProp]; - if (isBlock(block)) { + if (!isBlock(block)) { + return; + } - previousToken = context.getTokenBefore(block); - curlyToken = context.getFirstToken(block); - curlyTokenEnd = context.getLastToken(block); - curlyTokensOnSameLine = curlyToken.loc.start.line === curlyTokenEnd.loc.start.line; + previousToken = context.getTokenBefore(block); + curlyToken = context.getFirstToken(block); + curlyTokenEnd = context.getLastToken(block); + curlyTokensOnSameLine = curlyToken.loc.start.line === curlyTokenEnd.loc.start.line; - if (previousToken.loc.start.line !== curlyToken.loc.start.line) { - context.report(node, OPEN_MESSAGE); - } else if (block.body.length && params.allowSingleLine) { + if (style !== "allman" && previousToken.loc.start.line !== curlyToken.loc.start.line) { + context.report(node, OPEN_MESSAGE); + } else if (style === "allman" && previousToken.loc.start.line === curlyToken.loc.start.line && !params.allowSingleLine) { + context.report(node, OPEN_MESSAGE_ALLMAN); + } - if (curlyToken.loc.start.line === block.body[0].loc.start.line && !curlyTokensOnSameLine) { - context.report(block.body[0], BODY_MESSAGE); - } else if (curlyTokenEnd.loc.start.line === block.body[block.body.length - 1].loc.start.line && !curlyTokensOnSameLine) { - context.report(block.body[block.body.length - 1], CLOSE_MESSAGE_SINGLE); - } + if (!block.body.length || curlyTokensOnSameLine && params.allowSingleLine) { + return; + } - } else if (block.body.length && curlyToken.loc.start.line === block.body[0].loc.start.line) { - context.report(block.body[0], BODY_MESSAGE); - } + if (curlyToken.loc.start.line === block.body[0].loc.start.line) { + context.report(block.body[0], BODY_MESSAGE); + } else if (curlyTokenEnd.loc.start.line === block.body[block.body.length - 1].loc.start.line) { + context.report(block.body[block.body.length - 1], CLOSE_MESSAGE_SINGLE); } }); }; } @@ -18522,17 +24033,15 @@ if (alternateIsBlock || alternateIsIfBlock) { tokens = context.getTokensBefore(node.alternate, 2); if (style === "1tbs") { - if (tokens[0].loc.start.line !== tokens[1].loc.start.line) { + if (tokens[0].loc.start.line !== tokens[1].loc.start.line && isCurlyPunctuator(tokens[0]) ) { context.report(node.alternate, CLOSE_MESSAGE); } - } else if (style === "stroustrup") { - if (tokens[0].loc.start.line === tokens[1].loc.start.line) { - context.report(node.alternate, CLOSE_MESSAGE_STROUSTRUP); - } + } else if (tokens[0].loc.start.line === tokens[1].loc.start.line) { + context.report(node.alternate, CLOSE_MESSAGE_STROUSTRUP_ALLMAN); } } } } @@ -18552,14 +24061,12 @@ tokens = context.getTokensBefore(node.finalizer, 2); if (style === "1tbs") { if (tokens[0].loc.start.line !== tokens[1].loc.start.line) { context.report(node.finalizer, CLOSE_MESSAGE); } - } else if (style === "stroustrup") { - if (tokens[0].loc.start.line === tokens[1].loc.start.line) { - context.report(node.finalizer, CLOSE_MESSAGE_STROUSTRUP); - } + } else if (tokens[0].loc.start.line === tokens[1].loc.start.line) { + context.report(node.finalizer, CLOSE_MESSAGE_STROUSTRUP_ALLMAN); } } } /** @@ -18577,13 +24084,13 @@ if (isBlock(node.body)) { if (style === "1tbs") { if (previousToken.loc.start.line !== firstToken.loc.start.line) { context.report(node, CLOSE_MESSAGE); } - } else if (style === "stroustrup") { + } else { if (previousToken.loc.start.line === firstToken.loc.start.line) { - context.report(node, CLOSE_MESSAGE_STROUSTRUP); + context.report(node, CLOSE_MESSAGE_STROUSTRUP_ALLMAN); } } } } @@ -18595,19 +24102,19 @@ */ function checkSwitchStatement(node) { var tokens; if (node.cases && node.cases.length) { tokens = context.getTokensBefore(node.cases[0], 2); - if (tokens[0].loc.start.line !== tokens[1].loc.start.line) { - context.report(node, OPEN_MESSAGE); - } } else { tokens = context.getLastTokens(node, 3); - if (tokens[0].loc.start.line !== tokens[1].loc.start.line) { - context.report(node, OPEN_MESSAGE); - } } + + if (style !== "allman" && tokens[0].loc.start.line !== tokens[1].loc.start.line) { + context.report(node, OPEN_MESSAGE); + } else if (style === "allman" && tokens[0].loc.start.line === tokens[1].loc.start.line) { + context.report(node, OPEN_MESSAGE_ALLMAN); + } } //-------------------------------------------------------------------------- // Public API //-------------------------------------------------------------------------- @@ -18628,14 +24135,174 @@ "SwitchStatement": checkSwitchStatement }; }; -},{}],138:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["1tbs", "stroustrup", "allman"] + }, + { + "type": "object", + "properties": { + "allowSingleLine": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{}],128:[function(require,module,exports){ /** + * @fileoverview Enforce return after a callback. + * @author Jamund Ferguson + * @copyright 2015 Jamund Ferguson. All rights reserved. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + var callbacks = context.options[0] || ["callback", "cb", "next"]; + + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + + /** + * Find the closest parent matching a list of types. + * @param {ASTNode} node The node whose parents we are searching + * @param {Array} types The node types to match + * @returns {ASTNode} The matched node or undefined. + */ + function findClosestParentOfType(node, types) { + if (!node.parent) { + return null; + } + if (types.indexOf(node.parent.type) === -1) { + return findClosestParentOfType(node.parent, types); + } + return node.parent; + } + + /** + * Check to see if a CallExpression is in our callback list. + * @param {ASTNode} node The node to check against our callback names list. + * @returns {Boolean} Whether or not this function matches our callback name. + */ + function isCallback(node) { + return node.callee.type === "Identifier" && callbacks.indexOf(node.callee.name) > -1; + } + + /** + * Determines whether or not the callback is part of a callback expression. + * @param {ASTNode} node The callback node + * @param {ASTNode} parentNode The expression node + * @returns {boolean} Whether or not this is part of a callback expression + */ + function isCallbackExpression(node, parentNode) { + + // ensure the parent node exists and is an expression + if (!parentNode || parentNode.type !== "ExpressionStatement") { + return false; + } + + // cb() + if (parentNode.expression === node) { + return true; + } + + // special case for cb && cb() and similar + if (parentNode.expression.type === "BinaryExpression" || parentNode.expression.type === "LogicalExpression") { + if (parentNode.expression.right === node) { + return true; + } + } + } + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + return { + "CallExpression": function(node) { + + // if we"re not a callback we can return + if (!isCallback(node)) { + return; + } + + // find the closest block, return or loop + var closestBlock = findClosestParentOfType(node, ["BlockStatement", "ReturnStatement", "ArrowFunctionExpression"]) || {}, + lastItem, parentType; + + // if our parent is a return we know we're ok + if (closestBlock.type === "ReturnStatement" ) { + return; + } + + // arrow functions don't always have blocks and implicitly return + if (closestBlock.type === "ArrowFunctionExpression") { + return; + } + + // block statements are part of functions and most if statements + if (closestBlock.type === "BlockStatement") { + + // find the last item in the block + lastItem = closestBlock.body[closestBlock.body.length - 1]; + + // if the callback is the last thing in a block that might be ok + if (isCallbackExpression(node, lastItem)) { + + parentType = closestBlock.parent.type; + + // but only if the block is part of a function + if (parentType === "FunctionExpression" || + parentType === "FunctionDeclaration" || + parentType === "ArrowFunctionExpression" + ) { + return; + } + + } + + // ending a block with a return is also ok + if (lastItem.type === "ReturnStatement") { + + // but only if the callback is immediately before + if (isCallbackExpression(node, closestBlock.body[closestBlock.body.length - 2])) { + return; + } + } + + } + + // as long as you're the child of a function at this point you should be asked to return + if (findClosestParentOfType(node, ["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"])) { + context.report(node, "Expected return with your callback function."); + } + + } + + }; +}; + +module.exports.schema = [{ + type: "array", + items: { type: "string" } +}]; + +},{}],129:[function(require,module,exports){ +/** * @fileoverview Rule to flag non-camelcased identifiers * @author Nicholas C. Zakas + * @copyright 2015 Dieter Oberkofler. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ @@ -18668,10 +24335,17 @@ */ function report(node) { context.report(node, "Identifier '{{name}}' is not in camel case.", { name: node.name }); } + var options = context.options[0] || {}, + properties = options.properties || ""; + + if (properties !== "always" && properties !== "never") { + properties = "always"; + } + return { "Identifier": function(node) { // Leading and trailing underscores are commonly used to flag private/protected identifiers, strip them @@ -18679,10 +24353,15 @@ effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent; // MemberExpressions get special rules if (node.parent.type === "MemberExpression") { + // "never" check properties + if (properties === "never") { + return; + } + // Always report underscored object names if (node.parent.object.type === "Identifier" && node.parent.object.name === node.name && isUnderscored(name)) { report(node); @@ -18694,120 +24373,286 @@ effectiveParent.left.type === "MemberExpression" && effectiveParent.left.property.name === node.name)) { report(node); } + // Properties have their own rules + } else if (node.parent.type === "Property") { + + // "never" check properties + if (properties === "never") { + return; + } + + if (isUnderscored(name) && effectiveParent.type !== "CallExpression") { + report(node); + } + // Report anything that is underscored that isn't a CallExpression } else if (isUnderscored(name) && effectiveParent.type !== "CallExpression") { report(node); } } + }; }; -},{}],139:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "properties": { + "enum": ["always", "never"] + } + }, + "additionalProperties": false + } +]; + +},{}],130:[function(require,module,exports){ /** * @fileoverview Rule to forbid or enforce dangling commas. * @author Ian Christian Myers + * @copyright 2015 Toru Nagashima * @copyright 2015 Mathias Schreck * @copyright 2013 Ian Christian Myers + * See LICENSE file in root directory for full license. */ "use strict"; //------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Gets the last element of a given array. + * + * @param {*[]} xs - An array to get. + * @returns {*} The last element, or undefined. + */ +function getLast(xs) { + if (xs.length === 0) { + return null; + } + return xs[xs.length - 1]; +} + +/** + * Checks whether or not a trailing comma is allowed in a given node. + * `ArrayPattern` which has `RestElement` disallows it. + * + * @param {ASTNode} node - A node to check. + * @param {ASTNode} lastItem - The node of the last element in the given node. + * @returns {boolean} `true` if a trailing comma is allowed. + */ +function isTrailingCommaAllowed(node, lastItem) { + switch (node.type) { + case "ArrayPattern": + // TODO(t-nagashima): Remove SpreadElement after https://github.com/eslint/espree/issues/194 was fixed. + return ( + lastItem.type !== "RestElement" && + lastItem.type !== "SpreadElement" + ); + + // TODO(t-nagashima): Remove this case after https://github.com/eslint/espree/issues/195 was fixed. + case "ArrayExpression": + return ( + node.parent.type !== "ForOfStatement" || + node.parent.left !== node || + lastItem.type !== "SpreadElement" + ); + + default: + return true; + } +} + +//------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = function (context) { - var forbidDanglingComma = context.options[0] !== "always"; +module.exports = function(context) { + var mode = context.options[0]; + var UNEXPECTED_MESSAGE = "Unexpected trailing comma."; + var MISSING_MESSAGE = "Missing trailing comma."; /** - * Checks the given node for trailing comma and reports violations. - * @param {ASTNode} node The node of an ObjectExpression or ArrayExpression + * Checks whether or not a given node is multiline. + * This rule handles a given node as multiline when the closing parenthesis + * and the last element are not on the same line. + * + * @param {ASTNode} node - A ndoe to check. + * @returns {boolean} `true` if the node is multiline. + */ + function isMultiline(node) { + var lastItem = getLast(node.properties || node.elements || node.specifiers); + if (!lastItem) { + return false; + } + + var sourceCode = context.getSourceCode(), + penultimateToken = sourceCode.getLastToken(lastItem), + lastToken = sourceCode.getLastToken(node); + + if (lastToken.value === ",") { + penultimateToken = lastToken; + lastToken = sourceCode.getTokenAfter(lastToken); + } + + return lastToken.loc.end.line !== penultimateToken.loc.end.line; + } + + /** + * Reports a trailing comma if it exists. + * + * @param {ASTNode} node - A node to check. Its type is one of + * ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern, + * ImportDeclaration, and ExportNamedDeclaration. * @returns {void} */ - function checkForTrailingComma(node) { - var items = node.properties || node.elements, - length = items.length, - lastItem, - penultimateToken; + function forbidTrailingComma(node) { + var lastItem = getLast(node.properties || node.elements || node.specifiers); + if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) { + return; + } - if (length) { - lastItem = items[length - 1]; - if (lastItem) { - penultimateToken = context.getLastToken(node, 1); + var sourceCode = context.getSourceCode(), + trailingToken; - if (forbidDanglingComma) { - if (penultimateToken.value === ",") { - context.report(lastItem, penultimateToken.loc.start, "Unexpected trailing comma."); - } - } else { - if (penultimateToken.value !== ",") { - context.report(lastItem, lastItem.loc.end, "Missing trailing comma."); - } - } - } + // last item can be surrounded by parentheses for object and array literals + if (node.type === "ObjectExpression" || node.type === "ArrayExpression") { + trailingToken = sourceCode.getTokenBefore(sourceCode.getLastToken(node)); + } else { + trailingToken = sourceCode.getTokenAfter(lastItem); } + + if (trailingToken.value === ",") { + context.report( + lastItem, + trailingToken.loc.start, + UNEXPECTED_MESSAGE); + } } + /** + * Reports the last element of a given node if it does not have a trailing + * comma. + * + * If a given node is `ArrayPattern` which has `RestElement`, the trailing + * comma is disallowed, so report if it exists. + * + * @param {ASTNode} node - A node to check. Its type is one of + * ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern, + * ImportDeclaration, and ExportNamedDeclaration. + * @returns {void} + */ + function forceTrailingComma(node) { + var lastItem = getLast(node.properties || node.elements || node.specifiers); + if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) { + return; + } + if (!isTrailingCommaAllowed(node, lastItem)) { + forbidTrailingComma(node); + return; + } + + var sourceCode = context.getSourceCode(), + trailingToken; + + // last item can be surrounded by parentheses for object and array literals + if (node.type === "ObjectExpression" || node.type === "ArrayExpression") { + trailingToken = sourceCode.getTokenBefore(sourceCode.getLastToken(node)); + } else { + trailingToken = sourceCode.getTokenAfter(lastItem); + } + + if (trailingToken.value !== ",") { + context.report( + lastItem, + lastItem.loc.end, + MISSING_MESSAGE); + } + } + + /** + * If a given node is multiline, reports the last element of a given node + * when it does not have a trailing comma. + * Otherwise, reports a trailing comma if it exists. + * + * @param {ASTNode} node - A node to check. Its type is one of + * ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern, + * ImportDeclaration, and ExportNamedDeclaration. + * @returns {void} + */ + function forceTrailingCommaIfMultiline(node) { + if (isMultiline(node)) { + forceTrailingComma(node); + } else { + forbidTrailingComma(node); + } + } + + // Chooses a checking function. + var checkForTrailingComma; + if (mode === "always") { + checkForTrailingComma = forceTrailingComma; + } else if (mode === "always-multiline") { + checkForTrailingComma = forceTrailingCommaIfMultiline; + } else { + checkForTrailingComma = forbidTrailingComma; + } + return { "ObjectExpression": checkForTrailingComma, - "ArrayExpression": checkForTrailingComma + "ObjectPattern": checkForTrailingComma, + "ArrayExpression": checkForTrailingComma, + "ArrayPattern": checkForTrailingComma, + "ImportDeclaration": checkForTrailingComma, + "ExportNamedDeclaration": checkForTrailingComma }; }; -},{}],140:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["always", "always-multiline", "never"] + } +]; + +},{}],131:[function(require,module,exports){ /** * @fileoverview Comma spacing - validates spacing before and after comma * @author Vignesh Anand aka vegetableman. * @copyright 2014 Vignesh Anand. All rights reserved. */ "use strict"; +var astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var sourceCode = context.getSourceCode(); + var tokensAndComments = sourceCode.tokensAndComments; + var options = { before: context.options[0] ? !!context.options[0].before : false, after: context.options[0] ? !!context.options[0].after : true }; //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- - // the index of the last comment that was checked - var lastCommentIndex = 0; + // list of comma tokens to ignore for the check of leading whitespace + var commaTokensToIgnore = []; /** - * Determines whether two adjacent tokens have whitespace between them. - * @param {Object} left - The left token object. - * @param {Object} right - The right token object. - * @returns {boolean} Whether or not there is space between the tokens. - */ - function isSpaced(left, right) { - var punctuationLength = context.getTokensBetween(left, right).length; // the length of any parenthesis - return (left.range[1] + punctuationLength) < right.range[0]; - } - - /** - * Checks whether two tokens are on the same line. - * @param {ASTNode} left The leftmost token. - * @param {ASTNode} right The rightmost token. - * @returns {boolean} True if the tokens are on the same line, false if not. - * @private - */ - function isSameLine(left, right) { - return left.loc.end.line === right.loc.start.line; - } - - /** * Determines if a given token is a comma operator. * @param {ASTNode} token The token to check. * @returns {boolean} True if the token is a comma, false if not. * @private */ @@ -18817,17 +24662,43 @@ /** * Reports a spacing error with an appropriate message. * @param {ASTNode} node The binary expression node to report. * @param {string} dir Is the error "before" or "after" the comma? + * @param {ASTNode} otherNode The node at the left or right of `node` * @returns {void} * @private */ - function report(node, dir) { - context.report(node, options[dir] ? - "A space is required " + dir + " ','." : - "There should be no space " + dir + " ','."); + function report(node, dir, otherNode) { + context.report({ + node: node, + fix: function(fixer) { + if (options[dir]) { + if (dir === "before") { + return fixer.insertTextBefore(node, " "); + } else { + return fixer.insertTextAfter(node, " "); + } + } else { + var start, end; + var newText = ""; + + if (dir === "before") { + start = otherNode.range[1]; + end = node.range[0]; + } else { + start = node.range[1]; + end = otherNode.range[0]; + } + + return fixer.replaceTextRange([start, end], newText); + } + }, + message: options[dir] ? + "A space is required " + dir + " ','." : + "There should be no space " + dir + " ','." + }); } /** * Validates the spacing around a comma token. * @param {Object} tokens - The tokens to be validated. @@ -18837,122 +24708,134 @@ * @param {Token|ASTNode} reportItem The item to use when reporting an error. * @returns {void} * @private */ function validateCommaItemSpacing(tokens, reportItem) { - if (tokens.left && isSameLine(tokens.left, tokens.comma) && - (options.before !== isSpaced(tokens.left, tokens.comma)) + if (tokens.left && astUtils.isTokenOnSameLine(tokens.left, tokens.comma) && + (options.before !== sourceCode.isSpaceBetweenTokens(tokens.left, tokens.comma)) ) { - report(reportItem, "before"); + report(reportItem, "before", tokens.left); } - if (tokens.right && isSameLine(tokens.comma, tokens.right) && - (options.after !== isSpaced(tokens.comma, tokens.right)) + + if (tokens.right && !options.after && tokens.right.type === "Line") { + return false; + } + + if (tokens.right && astUtils.isTokenOnSameLine(tokens.comma, tokens.right) && + (options.after !== sourceCode.isSpaceBetweenTokens(tokens.comma, tokens.right)) ) { - report(reportItem, "after"); + report(reportItem, "after", tokens.right); } } /** - * Determines if a given source index is in a comment or not by checking - * the index against the comment range. Since the check goes straight - * through the file, once an index is passed a certain comment, we can - * go to the next comment to check that. - * @param {int} index The source index to check. - * @param {ASTNode[]} comments An array of comment nodes. - * @returns {boolean} True if the index is within a comment, false if not. - * @private + * Adds null elements of the given ArrayExpression or ArrayPattern node to the ignore list. + * @param {ASTNode} node An ArrayExpression or ArrayPattern node. + * @returns {void} */ - function isIndexInComment(index, comments) { + function addNullElementsToIgnoreList(node) { + var previousToken = context.getFirstToken(node); - var comment; + node.elements.forEach(function(element) { + var token; - while (lastCommentIndex < comments.length) { + if (element === null) { + token = context.getTokenAfter(previousToken); - comment = comments[lastCommentIndex]; - - if (comment.range[0] <= index && index < comment.range[1]) { - return true; - } else if (index > comment.range[1]) { - lastCommentIndex++; + if (isComma(token)) { + commaTokensToIgnore.push(token); + } } else { - break; + token = context.getTokenAfter(element); } - } - - return false; + previousToken = token; + }); } //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- return { - "Program": function() { + "Program:exit": function() { - var source = context.getSource(), - allComments = context.getAllComments(), - pattern = /,/g, - commaToken, - previousToken, + var previousToken, nextToken; - while (pattern.test(source)) { + tokensAndComments.forEach(function(token, i) { - // do not flag anything inside of comments - if (!isIndexInComment(pattern.lastIndex, allComments)) { - commaToken = context.getTokenByRangeStart(pattern.lastIndex - 1); + if (!isComma(token)) { + return; + } - if (commaToken && commaToken.type !== "JSXText") { - previousToken = context.getTokenBefore(commaToken); - nextToken = context.getTokenAfter(commaToken); - validateCommaItemSpacing({ - comma: commaToken, - left: isComma(previousToken) ? null : previousToken, - right: isComma(nextToken) ? null : nextToken - }, commaToken); - } + if (token && token.type === "JSXText") { + return; } - } - } + + previousToken = tokensAndComments[i - 1]; + nextToken = tokensAndComments[i + 1]; + + validateCommaItemSpacing({ + comma: token, + left: isComma(previousToken) || commaTokensToIgnore.indexOf(token) > -1 ? null : previousToken, + right: isComma(nextToken) ? null : nextToken + }, token); + }); + }, + "ArrayExpression": addNullElementsToIgnoreList, + "ArrayPattern": addNullElementsToIgnoreList + }; }; -},{}],141:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "before": { + "type": "boolean" + }, + "after": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{"../ast-utils":113}],132:[function(require,module,exports){ /** * @fileoverview Comma style - enforces comma styles of two types: last and first * @author Vignesh Anand aka vegetableman * @copyright 2014 Vignesh Anand. All rights reserved. + * @copyright 2015 Evan Simmons. All rights reserved. */ "use strict"; +var astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var style = context.options[0] || "last"; + var style = context.options[0] || "last", + exceptions = {}; + if (context.options.length === 2 && context.options[1].hasOwnProperty("exceptions")) { + exceptions = context.options[1].exceptions; + } + //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- /** - * Checks whether two tokens are on the same line. - * @param {ASTNode} left The leftmost token. - * @param {ASTNode} right The rightmost token. - * @returns {boolean} True if the tokens are on the same line, false if not. - * @private - */ - function isSameLine(left, right) { - return left.loc.end.line === right.loc.start.line; - } - - /** * Determines if a given token is a comma operator. * @param {ASTNode} token The token to check. * @returns {boolean} True if the token is a comma, false if not. * @private */ @@ -18970,29 +24853,29 @@ * @private */ function validateCommaItemSpacing(previousItemToken, commaToken, currentItemToken, reportItem) { // if single line - if (isSameLine(commaToken, currentItemToken) && - isSameLine(previousItemToken, commaToken)) { + if (astUtils.isTokenOnSameLine(commaToken, currentItemToken) && + astUtils.isTokenOnSameLine(previousItemToken, commaToken)) { return; - } else if (!isSameLine(commaToken, currentItemToken) && - !isSameLine(previousItemToken, commaToken)) { + } else if (!astUtils.isTokenOnSameLine(commaToken, currentItemToken) && + !astUtils.isTokenOnSameLine(previousItemToken, commaToken)) { // lone comma context.report(reportItem, { line: commaToken.loc.end.line, column: commaToken.loc.start.column }, "Bad line breaking before and after ','."); - } else if (style === "first" && !isSameLine(commaToken, currentItemToken)) { + } else if (style === "first" && !astUtils.isTokenOnSameLine(commaToken, currentItemToken)) { context.report(reportItem, "',' should be placed first."); - } else if (style === "last" && isSameLine(commaToken, currentItemToken)) { + } else if (style === "last" && astUtils.isTokenOnSameLine(commaToken, currentItemToken)) { context.report(reportItem, { line: commaToken.loc.end.line, column: commaToken.loc.end.column }, "',' should be placed last."); @@ -19068,25 +24951,50 @@ //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- - return { - "VariableDeclaration": function(node) { + var nodes = {}; + + if (!exceptions.VariableDeclaration) { + nodes.VariableDeclaration = function(node) { validateComma(node, "declarations"); - }, - "ObjectExpression": function(node) { + }; + } + if (!exceptions.ObjectExpression) { + nodes.ObjectExpression = function(node) { validateComma(node, "properties"); - }, - "ArrayExpression": function(node) { + }; + } + if (!exceptions.ArrayExpression) { + nodes.ArrayExpression = function(node) { validateComma(node, "elements"); - } - }; + }; + } + return nodes; }; -},{}],142:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["first", "last"] + }, + { + "type": "object", + "properties": { + "exceptions": { + "type": "object", + "additionalProperties": { + "type": "boolean" + } + } + }, + "additionalProperties": false + } +]; + +},{"../ast-utils":113}],133:[function(require,module,exports){ /** * @fileoverview Counts the cyclomatic complexity of each function of the script. See http://en.wikipedia.org/wiki/Cyclomatic_complexity. * Counts the number of if, conditional, for, whilte, try, switch/case, * @author Patrick Brosset */ @@ -19106,39 +25014,70 @@ //-------------------------------------------------------------------------- // Using a stack to store complexity (handling nested functions) var fns = []; - // When parsing a new function, store it in our function stack + /** + * When parsing a new function, store it in our function stack + * @returns {void} + * @private + */ function startFunction() { fns.push(1); } + /** + * Evaluate the node at the end of function + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function endFunction(node) { - var complexity = fns.pop(), name = "anonymous"; + var complexity = fns.pop(), + name = "anonymous"; if (node.id) { name = node.id.name; + } else if (node.parent.type === "MethodDefinition" || node.parent.type === "Property") { + name = node.parent.key.name; } + if (complexity > THRESHOLD) { context.report(node, "Function '{{name}}' has a complexity of {{complexity}}.", { name: name, complexity: complexity }); } } + /** + * Increase the complexity of the function in context + * @returns {void} + * @private + */ function increaseComplexity() { if (fns.length) { fns[fns.length - 1] ++; } } + /** + * Increase the switch complexity in context + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function increaseSwitchComplexity(node) { // Avoiding `default` if (node.test) { increaseComplexity(node); } } + /** + * Increase the logical path complexity in context + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function increaseLogicalComplexity(node) { // Avoiding && if (node.operator === "||") { increaseComplexity(node); } @@ -19168,12 +25107,173 @@ "DoWhileStatement": increaseComplexity }; }; -},{}],143:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "integer" + } +]; + +},{}],134:[function(require,module,exports){ /** + * @fileoverview Disallows or enforces spaces inside computed properties. + * @author Jamund Ferguson + * @copyright 2015 Jamund Ferguson. All rights reserved. + */ +"use strict"; + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var sourceCode = context.getSourceCode(); + var propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never" + + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + + /** + * Reports that there shouldn't be a space after the first token + * @param {ASTNode} node - The node to report in the event of an error. + * @param {Token} token - The token to use for the report. + * @param {Token} tokenAfter - The token after `token`. + * @returns {void} + */ + function reportNoBeginningSpace(node, token, tokenAfter) { + context.report({ + node: node, + loc: token.loc.start, + message: "There should be no space after '" + token.value + "'", + fix: function(fixer) { + return fixer.removeRange([token.range[1], tokenAfter.range[0]]); + } + }); + } + + /** + * Reports that there shouldn't be a space before the last token + * @param {ASTNode} node - The node to report in the event of an error. + * @param {Token} token - The token to use for the report. + * @param {Token} tokenBefore - The token before `token`. + * @returns {void} + */ + function reportNoEndingSpace(node, token, tokenBefore) { + context.report({ + node: node, + loc: token.loc.start, + message: "There should be no space before '" + token.value + "'", + fix: function(fixer) { + return fixer.removeRange([tokenBefore.range[1], token.range[0]]); + } + }); + } + + /** + * Reports that there should be a space after the first token + * @param {ASTNode} node - The node to report in the event of an error. + * @param {Token} token - The token to use for the report. + * @returns {void} + */ + function reportRequiredBeginningSpace(node, token) { + context.report({ + node: node, + loc: token.loc.start, + message: "A space is required after '" + token.value + "'", + fix: function(fixer) { + return fixer.insertTextAfter(token, " "); + } + }); + } + + /** + * Reports that there should be a space before the last token + * @param {ASTNode} node - The node to report in the event of an error. + * @param {Token} token - The token to use for the report. + * @returns {void} + */ + function reportRequiredEndingSpace(node, token) { + context.report({ + node: node, + loc: token.loc.start, + message: "A space is required before '" + token.value + "'", + fix: function(fixer) { + return fixer.insertTextBefore(token, " "); + } + }); + } + + /** + * Returns a function that checks the spacing of a node on the property name + * that was passed in. + * @param {String} propertyName The property on the node to check for spacing + * @returns {Function} A function that will check spacing on a node + */ + function checkSpacing(propertyName) { + return function(node) { + if (!node.computed) { + return; + } + + var property = node[propertyName]; + + var before = context.getTokenBefore(property), + first = context.getFirstToken(property), + last = context.getLastToken(property), + after = context.getTokenAfter(property); + + if (astUtils.isTokenOnSameLine(before, first)) { + if (propertyNameMustBeSpaced) { + if (!sourceCode.isSpaceBetweenTokens(before, first) && astUtils.isTokenOnSameLine(before, first)) { + reportRequiredBeginningSpace(node, before); + } + } else { + if (sourceCode.isSpaceBetweenTokens(before, first)) { + reportNoBeginningSpace(node, before, first); + } + } + } + + if (astUtils.isTokenOnSameLine(last, after)) { + if (propertyNameMustBeSpaced) { + if (!sourceCode.isSpaceBetweenTokens(last, after) && astUtils.isTokenOnSameLine(last, after)) { + reportRequiredEndingSpace(node, after); + } + } else { + if (sourceCode.isSpaceBetweenTokens(last, after)) { + reportNoEndingSpace(node, after, last); + } + } + } + }; + } + + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + return { + Property: checkSpacing("key"), + MemberExpression: checkSpacing("property") + }; + +}; + +module.exports.schema = [ + { + "enum": ["always", "never"] + } +]; + +},{"../ast-utils":113}],135:[function(require,module,exports){ +/** * @fileoverview Rule to flag consistent return values * @author Nicholas C. Zakas */ "use strict"; @@ -19243,15 +25343,18 @@ } }; }; -},{}],144:[function(require,module,exports){ +module.exports.schema = []; + +},{}],136:[function(require,module,exports){ /** * @fileoverview Rule to enforce consistent naming of "this" context variables * @author Raphael Pigulla * @copyright 2015 Timothy Jones. All rights reserved. + * @copyright 2015 David Aurelio. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition @@ -19298,80 +25401,205 @@ * is assigned to the correct value. * @returns {void} */ function ensureWasAssigned() { var scope = context.getScope(); + var variable = scope.set.get(alias); + if (!variable) { + return; + } - scope.variables.some(function (variable) { - var lookup; + if (variable.defs.some(function(def) { + return def.node.type === "VariableDeclarator" && + def.node.init !== null; + })) { + return; + } - if (variable.name === alias) { - if (variable.defs.some(function (def) { - return def.node.type === "VariableDeclarator" && - def.node.init !== null; - })) { - return true; - } + var lookup = (variable.references.length === 0 && scope.type === "global") ? scope : variable; - lookup = scope.type === "global" ? scope : variable; + // The alias has been declared and not assigned: check it was + // assigned later in the same scope. + if (!lookup.references.some(function(reference) { + var write = reference.writeExpr; - // The alias has been declared and not assigned: check it was - // assigned later in the same scope. - if (!lookup.references.some(function (reference) { - var write = reference.writeExpr; - - if (reference.from === scope && - write && write.type === "ThisExpression" && - write.parent.operator === "=") { - return true; - } - })) { - variable.defs.map(function (def) { - return def.node; - }).forEach(reportBadAssignment); - } - + if (reference.from === scope && + write && write.type === "ThisExpression" && + write.parent.operator === "=") { return true; } - }); + })) { + variable.defs.map(function(def) { + return def.node; + }).forEach(reportBadAssignment); + } } return { "Program:exit": ensureWasAssigned, "FunctionExpression:exit": ensureWasAssigned, "FunctionDeclaration:exit": ensureWasAssigned, - "VariableDeclarator": function (node) { - if (node.init !== null) { - checkAssignment(node, node.id.name, node.init); + "VariableDeclarator": function(node) { + var id = node.id; + var isDestructuring = + id.type === "ArrayPattern" || id.type === "ObjectPattern"; + + if (node.init !== null && !isDestructuring) { + checkAssignment(node, id.name, node.init); } }, - "AssignmentExpression": function (node) { + "AssignmentExpression": function(node) { if (node.left.type === "Identifier") { checkAssignment(node, node.left.name, node.right); } } }; }; -},{}],145:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "string" + } +]; + +},{}],137:[function(require,module,exports){ /** + * @fileoverview A rule to verify `super()` callings in constructor. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + /** + * Searches a class node from ancestors of a node. + * @param {Node} node - A node to get. + * @returns {ClassDeclaration|ClassExpression|null} the found class node or `null`. + */ + function getClassInAncestor(node) { + while (node) { + if (node.type === "ClassDeclaration" || node.type === "ClassExpression") { + return node; + } + node = node.parent; + } + /* istanbul ignore next */ + return null; + } + + /** + * Checks whether or not a node is the null literal. + * @param {Node} node - A node to check. + * @returns {boolean} whether or not a node is the null literal. + */ + function isNullLiteral(node) { + return node && node.type === "Literal" && node.value === null; + } + + /** + * Checks whether or not the current traversal context is on constructors. + * @param {{scope: Scope}} item - A checking context to check. + * @returns {boolean} whether or not the current traversal context is on constructors. + */ + function isOnConstructor(item) { + return item && item.scope === context.getScope().variableScope.upper.variableScope; + } + + // A stack for checking context. + var stack = []; + + return { + /** + * Start checking. + * @param {MethodDefinition} node - A target node. + * @returns {void} + */ + "MethodDefinition": function(node) { + if (node.kind !== "constructor") { + return; + } + stack.push({ + superCallings: [], + scope: context.getScope().variableScope + }); + }, + + /** + * Checks the result, then reports invalid/missing `super()`. + * @param {MethodDefinition} node - A target node. + * @returns {void} + */ + "MethodDefinition:exit": function(node) { + if (node.kind !== "constructor") { + return; + } + var result = stack.pop(); + + var classNode = getClassInAncestor(node); + /* istanbul ignore if */ + if (!classNode) { + return; + } + + if (classNode.superClass === null || isNullLiteral(classNode.superClass)) { + result.superCallings.forEach(function(superCalling) { + context.report(superCalling, "unexpected `super()`."); + }); + } else if (result.superCallings.length === 0) { + context.report(node.key, "this constructor requires `super()`."); + } + }, + + /** + * Checks the result of checking, then reports invalid/missing `super()`. + * @param {MethodDefinition} node - A target node. + * @returns {void} + */ + "CallExpression": function(node) { + var item = stack[stack.length - 1]; + if (isOnConstructor(item) && node.callee.type === "Super") { + item.superCallings.push(node); + } + } + }; +}; + +module.exports.schema = []; + +},{}],138:[function(require,module,exports){ +/** * @fileoverview Rule to flag statements without curly braces * @author Nicholas C. Zakas + * @copyright 2015 Ivan Nikulin. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { var multiOnly = (context.options[0] === "multi"); var multiLine = (context.options[0] === "multi-line"); + var multiOrNest = (context.options[0] === "multi-or-nest"); + var consistent = (context.options[1] === "consistent"); //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- @@ -19386,83 +25614,258 @@ last = context.getLastToken(node); return before.loc.start.line === last.loc.end.line; } /** - * Checks the body of a node to see if it's a block statement. Depending on - * the rule options, reports the appropriate problems. + * Determines if a given node is a one-liner. + * @param {ASTNode} node The node to check. + * @returns {boolean} True if the node is a one-liner. + * @private + */ + function isOneLiner(node) { + var first = context.getFirstToken(node), + last = context.getLastToken(node); + + return first.loc.start.line === last.loc.end.line; + } + + /** + * Gets the `else` keyword token of a given `IfStatement` node. + * @param {ASTNode} node - A `IfStatement` node to get. + * @returns {Token} The `else` keyword token. + */ + function getElseKeyword(node) { + var sourceCode = context.getSourceCode(); + var token = sourceCode.getTokenAfter(node.consequent); + + while (token.type !== "Keyword" || token.value !== "else") { + token = sourceCode.getTokenAfter(token); + } + + return token; + } + + /** + * Checks a given IfStatement node requires braces of the consequent chunk. + * This returns `true` when below: + * + * 1. The given node has the `alternate` node. + * 2. There is a `IfStatement` which doesn't have `alternate` node in the + * trailing statement chain of the `consequent` node. + * + * @param {ASTNode} node - A IfStatement node to check. + * @returns {boolean} `true` if the node requires braces of the consequent chunk. + */ + function requiresBraceOfConsequent(node) { + if (node.alternate && node.consequent.type === "BlockStatement") { + if (node.consequent.body.length >= 2) { + return true; + } + + node = node.consequent.body[0]; + while (node) { + if (node.type === "IfStatement" && !node.alternate) { + return true; + } + node = astUtils.getTrailingStatement(node); + } + } + + return false; + } + + /** + * Reports "Expected { after ..." error + * @param {ASTNode} node The node to report. + * @param {string} name The name to report. + * @param {string} suffix Additional string to add to the end of a report. + * @returns {void} + * @private + */ + function reportExpectedBraceError(node, name, suffix) { + context.report({ + node: node, + loc: (name !== "else" ? node : getElseKeyword(node)).loc.start, + message: "Expected { after '{{name}}'{{suffix}}.", + data: { + name: name, + suffix: (suffix ? " " + suffix : "") + } + }); + } + + /** + * Reports "Unnecessary { after ..." error + * @param {ASTNode} node The node to report. + * @param {string} name The name to report. + * @param {string} suffix Additional string to add to the end of a report. + * @returns {void} + * @private + */ + function reportUnnecessaryBraceError(node, name, suffix) { + context.report({ + node: node, + loc: (name !== "else" ? node : getElseKeyword(node)).loc.start, + message: "Unnecessary { after '{{name}}'{{suffix}}.", + data: { + name: name, + suffix: (suffix ? " " + suffix : "") + } + }); + } + + /** + * Prepares to check the body of a node to see if it's a block statement. * @param {ASTNode} node The node to report if there's a problem. * @param {ASTNode} body The body node to check for blocks. * @param {string} name The name to report if there's a problem. * @param {string} suffix Additional string to add to the end of a report. - * @returns {void} + * @returns {object} a prepared check object, with "actual", "expected", "check" properties. + * "actual" will be `true` or `false` whether the body is already a block statement. + * "expected" will be `true` or `false` if the body should be a block statement or not, or + * `null` if it doesn't matter, depending on the rule options. It can be modified to change + * the final behavior of "check". + * "check" will be a function reporting appropriate problems depending on the other + * properties. */ - function checkBody(node, body, name, suffix) { + function prepareCheck(node, body, name, suffix) { var hasBlock = (body.type === "BlockStatement"); + var expected = null; - if (multiOnly) { + if (node.type === "IfStatement" && node.consequent === body && requiresBraceOfConsequent(node)) { + expected = true; + } else if (multiOnly) { if (hasBlock && body.body.length === 1) { - context.report(node, "Unnecessary { after '{{name}}'{{suffix}}.", - { - name: name, - suffix: (suffix ? " " + suffix : "") - } - ); + expected = false; } } else if (multiLine) { - if (!hasBlock && !isCollapsedOneLiner(body)) { - context.report(node, "Expected { after '{{name}}'{{suffix}}.", - { - name: name, - suffix: (suffix ? " " + suffix : "") - } - ); + if (!isCollapsedOneLiner(body)) { + expected = true; } + } else if (multiOrNest) { + if (hasBlock && body.body.length === 1 && isOneLiner(body.body[0])) { + expected = false; + } else if (!isOneLiner(body)) { + expected = true; + } } else { - if (!hasBlock) { - context.report(node, "Expected { after '{{name}}'{{suffix}}.", - { - name: name, - suffix: (suffix ? " " + suffix : "") + expected = true; + } + + return { + actual: hasBlock, + expected: expected, + check: function() { + if (this.expected !== null && this.expected !== this.actual) { + if (this.expected) { + reportExpectedBraceError(node, name, suffix); + } else { + reportUnnecessaryBraceError(node, name, suffix); } - ); + } } + }; + } + + /** + * Prepares to check the bodies of a "if", "else if" and "else" chain. + * @param {ASTNode} node The first IfStatement node of the chain. + * @returns {object[]} prepared checks for each body of the chain. See `prepareCheck` for more + * information. + */ + function prepareIfChecks(node) { + var preparedChecks = []; + do { + preparedChecks.push(prepareCheck(node, node.consequent, "if", "condition")); + if (node.alternate && node.alternate.type !== "IfStatement") { + preparedChecks.push(prepareCheck(node, node.alternate, "else")); + break; + } + node = node.alternate; + } while (node); + + if (consistent) { + // If any node should have or already have braces, make sure they all have braces. + // If all nodes shouldn't have braces, make sure they don't. + var expected = preparedChecks.some(function(preparedCheck) { + if (preparedCheck.expected !== null) { + return preparedCheck.expected; + } + return preparedCheck.actual; + }); + + preparedChecks.forEach(function(preparedCheck) { + preparedCheck.expected = expected; + }); } + + return preparedChecks; } //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- return { - "IfStatement": function(node) { - - checkBody(node, node.consequent, "if", "condition"); - - if (node.alternate && node.alternate.type !== "IfStatement") { - checkBody(node, node.alternate, "else"); + if (node.parent.type !== "IfStatement") { + prepareIfChecks(node).forEach(function(preparedCheck) { + preparedCheck.check(); + }); } - }, "WhileStatement": function(node) { - checkBody(node, node.body, "while", "condition"); + prepareCheck(node, node.body, "while", "condition").check(); }, - "DoWhileStatement": function (node) { - checkBody(node, node.body, "do"); + "DoWhileStatement": function(node) { + prepareCheck(node, node.body, "do").check(); }, "ForStatement": function(node) { - checkBody(node, node.body, "for", "condition"); + prepareCheck(node, node.body, "for", "condition").check(); } }; }; -},{}],146:[function(require,module,exports){ +module.exports.schema = { + "anyOf": [ + { + "type": "array", + "items": [ + { + "enum": [0, 1, 2] + }, + { + "enum": ["all"] + } + ], + "minItems": 1, + "maxItems": 2 + }, + { + "type": "array", + "items": [ + { + "enum": [0, 1, 2] + }, + { + "enum": ["multi", "multi-line", "multi-or-nest"] + }, + { + "enum": ["consistent"] + } + ], + "minItems": 1, + "maxItems": 3 + } + ] +}; + +},{"../ast-utils":113}],139:[function(require,module,exports){ /** * @fileoverview require default case in switch statements * @author Aliaksei Shytkin */ "use strict"; @@ -19524,87 +25927,87 @@ } } }; }; -},{}],147:[function(require,module,exports){ +module.exports.schema = []; + +},{}],140:[function(require,module,exports){ /** + * @fileoverview Validates newlines before and after dots + * @author Greg Cochard + * @copyright 2015 Greg Cochard + */ + +"use strict"; + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + var config = context.options[0], + // default to onObject if no preference is passed + onObject = config === "object" || !config; + + /** + * Reports if the dot between object and property is on the correct loccation. + * @param {ASTNode} obj The object owning the property. + * @param {ASTNode} prop The property of the object. + * @param {ASTNode} node The corresponding node of the token. + * @returns {void} + */ + function checkDotLocation(obj, prop, node) { + var dot = context.getTokenBefore(prop); + + if (dot.type === "Punctuator" && dot.value === ".") { + if (onObject) { + if (!astUtils.isTokenOnSameLine(obj, dot)) { + context.report(node, dot.loc.start, "Expected dot to be on same line as object."); + } + } else if (!astUtils.isTokenOnSameLine(dot, prop)) { + context.report(node, dot.loc.start, "Expected dot to be on same line as property."); + } + } + } + + /** + * Checks the spacing of the dot within a member expression. + * @param {ASTNode} node The node to check. + * @returns {void} + */ + function checkNode(node) { + checkDotLocation(node.object, node.property, node); + } + + return { + "MemberExpression": checkNode + }; +}; + +module.exports.schema = [ + { + "enum": ["object", "property"] + } +]; + +},{"../ast-utils":113}],141:[function(require,module,exports){ +/** * @fileoverview Rule to warn about using dot notation instead of square bracket notation when possible. * @author Josh Perez */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ var validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/; -var keywords = [ - "this", - "function", - "if", - "return", - "var", - "else", - "for", - "new", - "arguments", - "in", - "typeof", - "while", - "case", - "break", - "try", - "catch", - "delete", - "throw", - "switch", - "continue", - "default", - "instanceof", - "do", - "void", - "finally", - "with", - "debugger", - "eval", - "implements", - "interface", - "package", - "private", - "protected", - "public", - "static", - "yield", - "let", - "class", - "enum", - "export", - "extends", - "import", - "super", - "true", - "false", - "null", - "abstract", - "boolean", - "byte", - "char", - "const", - "double", - "final", - "float", - "goto", - "int", - "long", - "native", - "short", - "synchronized", - "throws", - "transient", - "volatile" -]; +var keywords = require("../util/keywords"); module.exports = function(context) { var options = context.options[0] || {}; var allowKeywords = options.allowKeywords === void 0 || !!options.allowKeywords; @@ -19634,11 +26037,26 @@ } } }; }; -},{}],148:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "allowKeywords": { + "type": "boolean" + }, + "allowPattern": { + "type": "string" + } + }, + "additionalProperties": false + } +]; + +},{"../util/keywords":313}],142:[function(require,module,exports){ /** * @fileoverview Require file to end with single newline. * @author Nodeca Team <https://github.com/nodeca> */ "use strict"; @@ -19655,41 +26073,64 @@ return { "Program": function checkBadEOF(node) { // Get the whole source code, not for node only. - var src = context.getSource(), location = {column: 1}; - + var src = context.getSource(), + location = {column: 1}, + linebreakStyle = context.options[0] || "unix", + linebreak = linebreakStyle === "unix" ? "\n" : "\r\n"; if (src.length === 0) { return; } if (src[src.length - 1] !== "\n") { // file is not newline-terminated location.line = src.split(/\n/g).length; - context.report(node, location, "Newline required at end of file but not found."); + context.report({ + node: node, + loc: location, + message: "Newline required at end of file but not found.", + fix: function(fixer) { + return fixer.insertTextAfterRange([0, src.length], linebreak); + } + }); } } }; }; -},{}],149:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["unix", "windows"] + } +]; + +},{}],143:[function(require,module,exports){ /** * @fileoverview Rule to flag statements that use != and == instead of !== and === * @author Nicholas C. Zakas + * @copyright 2013 Nicholas C. Zakas. All rights reserved. + * See LICENSE file in root directory for full license. */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var sourceCode = context.getSourceCode(), + replacements = { + "==": "===", + "!=": "!==" + }; + /** * Checks if an expression is a typeof expression * @param {ASTNode} node The node to check * @returns {boolean} if the node is a typeof expression */ @@ -19746,29 +26187,40 @@ if (node.operator !== "==" && node.operator !== "!=") { return; } if (context.options[0] === "smart" && (isTypeOfBinary(node) || - areLiteralsAndSameType(node)) || isNullCheck(node)) { + areLiteralsAndSameType(node) || isNullCheck(node))) { return; } if (context.options[0] === "allow-null" && isNullCheck(node)) { return; } - context.report( - node, getOperatorLocation(node), - "Expected '{{op}}=' and instead saw '{{op}}'.", - {op: node.operator} - ); + context.report({ + node: node, + loc: getOperatorLocation(node), + message: "Expected '{{op}}=' and instead saw '{{op}}'.", + data: { op: node.operator }, + fix: function(fixer) { + return fixer.replaceText(sourceCode.getTokenAfter(node.left), replacements[node.operator]); + } + }); + } }; }; -},{}],150:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["smart", "allow-null"] + } +]; + +},{}],144:[function(require,module,exports){ /** * @fileoverview Rule to warn when a function expression does not have a name. * @author Kyle T. Nunery * @copyright 2015 Brandon Mills. All rights reserved. * @copyright 2014 Kyle T. Nunery. All rights reserved. @@ -19782,35 +26234,40 @@ module.exports = function(context) { /** * Determines whether the current FunctionExpression node is a get, set, or - * shorthand method in an object literal. + * shorthand method in an object literal or a class. * @returns {boolean} True if the node is a get, set, or shorthand method. */ - function isObjectMethod() { + function isObjectOrClassMethod() { var parent = context.getAncestors().pop(); - return (parent.type === "Property" && ( - parent.method || - parent.kind === "get" || - parent.kind === "set" + + return (parent.type === "MethodDefinition" || ( + parent.type === "Property" && ( + parent.method || + parent.kind === "get" || + parent.kind === "set" + ) )); } return { "FunctionExpression": function(node) { var name = node.id && node.id.name; - if (!name && !isObjectMethod()) { + if (!name && !isObjectOrClassMethod()) { context.report(node, "Missing function expression name."); } } }; }; -},{}],151:[function(require,module,exports){ +module.exports.schema = []; + +},{}],145:[function(require,module,exports){ /** * @fileoverview Rule to enforce a particular function style * @author Nicholas C. Zakas * @copyright 2013 Nicholas C. Zakas. All rights reserved. */ @@ -19821,44 +26278,86 @@ //------------------------------------------------------------------------------ module.exports = function(context) { var style = context.options[0], - enforceDeclarations = (style === "declaration"); + allowArrowFunctions = context.options[1] && context.options[1].allowArrowFunctions === true, + enforceDeclarations = (style === "declaration"), + stack = []; - return { + var nodesToCheck = { + "Program": function() { + stack = []; + }, "FunctionDeclaration": function(node) { + stack.push(false); + if (!enforceDeclarations) { context.report(node, "Expected a function expression."); } }, + "FunctionDeclaration:exit": function() { + stack.pop(); + }, - "FunctionExpression": function() { - var parent = context.getAncestors().pop(); + "FunctionExpression": function(node) { + stack.push(false); - if (enforceDeclarations && parent.type === "VariableDeclarator") { - context.report(parent, "Expected a function declaration."); + if (enforceDeclarations && node.parent.type === "VariableDeclarator") { + context.report(node.parent, "Expected a function declaration."); } }, + "FunctionExpression:exit": function() { + stack.pop(); + }, - "ArrowFunctionExpression": function() { - var parent = context.getAncestors().pop(); - - if (enforceDeclarations && parent.type === "VariableDeclarator") { - context.report(parent, "Expected a function declaration."); + "ThisExpression": function() { + if (stack.length > 0) { + stack[stack.length - 1] = true; } } - }; + if (!allowArrowFunctions) { + nodesToCheck.ArrowFunctionExpression = function() { + stack.push(false); + }; + + nodesToCheck["ArrowFunctionExpression:exit"] = function(node) { + var hasThisExpr = stack.pop(); + + if (enforceDeclarations && !hasThisExpr && node.parent.type === "VariableDeclarator") { + context.report(node.parent, "Expected a function declaration."); + } + }; + } + + return nodesToCheck; + }; -},{}],152:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["declaration", "expression"] + }, + { + "type": "object", + "properties": { + "allowArrowFunctions": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{}],146:[function(require,module,exports){ /** - * @fileoverview Rule to check for the position of the * in your generator functions + * @fileoverview Rule to check the spacing around the * in generator functions. * @author Jamund Ferguson + * @copyright 2015 Brandon Mills. All rights reserved. * @copyright 2014 Jamund Ferguson. All rights reserved. */ "use strict"; @@ -19866,113 +26365,148 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var position = context.options[0] || "end"; + var mode = (function(option) { + if (!option || typeof option === "string") { + return { + before: { before: true, after: false }, + after: { before: false, after: true }, + both: { before: true, after: true }, + neither: { before: false, after: false } + }[option || "before"]; + } + return option; + }(context.options[0])); /** - * Check the position of the star compared to the expected position. - * @param {ASTNode} node - the entire function node + * Checks the spacing between two tokens before or after the star token. + * @param {string} side Either "before" or "after". + * @param {Token} leftToken `function` keyword token if side is "before", or + * star token if side is "after". + * @param {Token} rightToken Star token if side is "before", or identifier + * token if side is "after". * @returns {void} */ - function checkStarPosition(node) { - var starToken; + function checkSpacing(side, leftToken, rightToken) { + if (!!(rightToken.range[0] - leftToken.range[1]) !== mode[side]) { + var after = leftToken.value === "*"; + var spaceRequired = mode[side]; + var node = after ? leftToken : rightToken; + var type = spaceRequired ? "Missing" : "Unexpected"; + var message = type + " space " + side + " *."; + context.report({ + node: node, + message: message, + fix: function(fixer) { + if (spaceRequired) { + if (after) { + return fixer.insertTextAfter(node, " "); + } + return fixer.insertTextBefore(node, " "); + } + return fixer.removeRange([leftToken.range[1], rightToken.range[0]]); + } + }); + } + } + /** + * Enforces the spacing around the star if node is a generator function. + * @param {ASTNode} node A function expression or declaration node. + * @returns {void} + */ + function checkFunction(node) { + var prevToken, starToken, nextToken; + if (!node.generator) { return; } - // Blocked, pending decision to fix or work around in eslint/espree#36 - if (context.getAncestors().pop().method) { - return; + if (node.parent.method || node.parent.type === "MethodDefinition") { + starToken = context.getTokenBefore(node, 1); + } else { + starToken = context.getFirstToken(node, 1); } - starToken = context.getFirstToken(node, 1); - - // check for function *name() {} - if (position === "end") { - - // * starts where the next identifier begins - if (starToken.range[1] !== context.getTokenAfter(starToken).range[0]) { - context.report(node, "Expected a space before *."); - } + // Only check before when preceded by `function` keyword + prevToken = context.getTokenBefore(starToken); + if (prevToken.value === "function" || prevToken.value === "static") { + checkSpacing("before", prevToken, starToken); } - // check for function* name() {} - if (position === "start") { - - // * begins where the previous identifier ends - if (starToken.range[0] !== context.getTokenBefore(starToken).range[1]) { - context.report(node, "Expected no space before *."); - } + // Only check after when followed by an identifier + nextToken = context.getTokenAfter(starToken); + if (nextToken.type === "Identifier") { + checkSpacing("after", starToken, nextToken); } - - // check for function * name() {} - if (position === "middle") { - - // must be a space before and afer the * - if (starToken.range[0] <= context.getTokenBefore(starToken).range[1] || - starToken.range[1] >= context.getTokenAfter(starToken).range[0]) { - context.report(node, "Expected spaces around *."); - } - } } return { - "FunctionDeclaration": checkStarPosition, - "FunctionExpression": checkStarPosition + "FunctionDeclaration": checkFunction, + "FunctionExpression": checkFunction }; }; -},{}],153:[function(require,module,exports){ +module.exports.schema = [ + { + "oneOf": [ + { + "enum": ["before", "after", "both", "neither"] + }, + { + "type": "object", + "properties": { + "before": {"type": "boolean"}, + "after": {"type": "boolean"} + }, + "additionalProperties": false + } + ] + } +]; + +},{}],147:[function(require,module,exports){ /** - * @fileoverview Rule to flag or require global strict mode. - * @author Nicholas C. Zakas + * @fileoverview Rule for disallowing require() outside of the top-level module context + * @author Jamund Ferguson + * @copyright 2015 Jamund Ferguson. All rights reserved. */ + "use strict"; -//------------------------------------------------------------------------------ -// Rule Definition -//------------------------------------------------------------------------------ +var ACCEPTABLE_PARENTS = [ + "AssignmentExpression", + "VariableDeclarator", + "MemberExpression", + "ExpressionStatement", + "CallExpression", + "ConditionalExpression", + "Program", + "VariableDeclaration" +]; module.exports = function(context) { - - var mode = context.options[0]; - - if (mode === "always") { - - return { - "Program": function(node) { - if (node.body.length > 0) { - var statement = node.body[0]; - - if (!(statement.type === "ExpressionStatement" && statement.expression.value === "use strict")) { - context.report(node, "Use the global form of \"use strict\"."); - } + return { + "CallExpression": function(node) { + if (node.callee.name === "require") { + var isGoodRequire = context.getAncestors().every(function(parent) { + return ACCEPTABLE_PARENTS.indexOf(parent.type) > -1; + }); + if (!isGoodRequire) { + context.report(node, "Unexpected require()."); } } - }; - - } else { // mode = "never" - - return { - "ExpressionStatement": function(node) { - var parent = context.getAncestors().pop(); - - if (node.expression.value === "use strict" && parent.type === "Program") { - context.report(node, "Use the function form of \"use strict\"."); - } - } - }; - - } - + } + }; }; -},{}],154:[function(require,module,exports){ +module.exports.schema = []; + +},{}],148:[function(require,module,exports){ /** * @fileoverview Rule to flag for-in loops without if statements inside * @author Nicholas C. Zakas */ @@ -20000,14 +26534,17 @@ } }; }; -},{}],155:[function(require,module,exports){ +module.exports.schema = []; + +},{}],149:[function(require,module,exports){ /** * @fileoverview Ensure handling of errors when we know they exist. * @author Jamund Ferguson + * @copyright 2015 Mathias Schreck. * @copyright 2014 Jamund Ferguson. All rights reserved. */ "use strict"; @@ -20016,12 +26553,10 @@ //------------------------------------------------------------------------------ module.exports = function(context) { var errorArgument = context.options[0] || "err"; - var callbacks = []; - var scopes = 0; /** * Checks if the given argument should be interpreted as a regexp pattern. * @param {string} stringToCheck The string which should be checked. * @returns {boolean} Whether or not the string should be interpreted as a pattern. @@ -20043,555 +26578,1195 @@ } return name === errorArgument; } /** - * Check the arguments to see if we need to start tracking the error object. - * @param {ASTNode} node The AST node to check. - * @returns {void} + * Get the parameters of a given function scope. + * @param {object} scope The function scope. + * @returns {array} All parameters of the given scope. */ - function startFunction(node) { - - // keep track of nested scopes - scopes++; - - // check if the first argument matches our argument name - var firstArg = node.params && node.params[0]; - if (firstArg && matchesConfiguredErrorName(firstArg.name)) { - callbacks.push({handled: false, depth: scopes, errorVariableName: firstArg.name}); - } + function getParameters(scope) { + return scope.variables.filter(function(variable) { + return variable.defs[0] && variable.defs[0].type === "Parameter"; + }); } /** - * At the end of a function check to see if the error was handled. + * Check to see if we're handling the error object properly. * @param {ASTNode} node The AST node to check. * @returns {void} */ - function endFunction(node) { + function checkForError(node) { + var scope = context.getScope(), + parameters = getParameters(scope), + firstParameter = parameters[0]; - var callback = callbacks[callbacks.length - 1] || {}; + if (firstParameter && matchesConfiguredErrorName(firstParameter.name)) { + if (firstParameter.references.length === 0) { + context.report(node, "Expected error to be handled."); + } + } + } - // check if a callback is ending, if so pop it off the stack - if (callback.depth === scopes) { - callbacks.pop(); + return { + "FunctionDeclaration": checkForError, + "FunctionExpression": checkForError, + "ArrowFunctionExpression": checkForError + }; - // check if there were no handled errors since the last callback - if (!callback.handled) { - context.report(node, "Expected error to be handled."); +}; + +module.exports.schema = [ + { + "type": "string" + } +]; + +},{}],150:[function(require,module,exports){ +/** + * @fileoverview Rule that warns when identifier names are shorter or longer + * than the values provided in configuration. + * @author Burak Yigit Kaya aka BYK + * @copyright 2015 Burak Yigit Kaya. All rights reserved. + * @copyright 2015 Mathieu M-Gosselin. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var options = context.options[0] || {}; + var minLength = typeof options.min !== "undefined" ? options.min : 2; + var maxLength = typeof options.max !== "undefined" ? options.max : Infinity; + var properties = options.properties !== "never"; + var exceptions = (options.exceptions ? options.exceptions : []) + .reduce(function(obj, item) { + obj[item] = true; + + return obj; + }, {}); + + var SUPPORTED_EXPRESSIONS = { + "MemberExpression": properties && function(parent) { + return !parent.computed && ( + // regular property assignment + parent.parent.left === parent || ( + // or the last identifier in an ObjectPattern destructuring + parent.parent.type === "Property" && parent.parent.value === parent && + parent.parent.parent.type === "ObjectPattern" && parent.parent.parent.parent.left === parent.parent.parent + ) + ); + }, + "AssignmentPattern": function(parent, node) { + return parent.left === node; + }, + "VariableDeclarator": function(parent, node) { + return parent.id === node; + }, + "Property": properties && function(parent, node) { + return parent.key === node; + }, + "ImportDefaultSpecifier": true, + "RestElement": true, + "FunctionExpression": true, + "ArrowFunctionExpression": true, + "ClassDeclaration": true, + "FunctionDeclaration": true, + "MethodDefinition": true, + "CatchClause": true + }; + + return { + Identifier: function(node) { + var name = node.name; + var parent = node.parent; + + var isShort = name.length < minLength; + var isLong = name.length > maxLength; + if (!(isShort || isLong) || exceptions[name]) { + return; // Nothing to report } + + var isValidExpression = SUPPORTED_EXPRESSIONS[parent.type]; + + if (isValidExpression && (isValidExpression === true || isValidExpression(parent, node))) { + context.report( + node, + isShort ? + "Identifier name '{{name}}' is too short. (< {{min}})" : + "Identifier name '{{name}}' is too long. (> {{max}})", + { name: name, min: minLength, max: maxLength } + ); + } } + }; +}; - // less nested functions - scopes--; +module.exports.schema = [ + { + "type": "object", + "properties": { + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "exceptions": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "properties": { + "enum": ["always", "never"] + } + }, + "additionalProperties": false + } +]; +},{}],151:[function(require,module,exports){ +/** + * @fileoverview Rule to flag non-matching identifiers + * @author Matthieu Larcher + * @copyright 2015 Matthieu Larcher. All rights reserved. + * See LICENSE in root directory for full license. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + + var pattern = context.options[0] || "^.+$", + regexp = new RegExp(pattern); + + var options = context.options[1] || {}, + properties = options.properties; + + // cast to boolean and default to false + properties = !!properties; + + + /** + * Checks if a string matches the provided pattern + * @param {String} name The string to check. + * @returns {boolean} if the string is a match + * @private + */ + function isInvalid(name) { + return !regexp.test(name); } /** - * Check to see if we're handling the error object properly. - * @param {ASTNode} node The AST node to check. + * Verifies if we should report an error or not based on the effective + * parent node and the identifier name. + * @param {ASTNode} effectiveParent The effective parent node of the node to be reported + * @param {String} name The identifier name of the identifier node + * @returns {boolean} whether an error should be reported or not + */ + function shouldReport(effectiveParent, name) { + return effectiveParent.type !== "CallExpression" + && effectiveParent.type !== "NewExpression" && + isInvalid(name); + } + + /** + * Reports an AST node as a rule violation. + * @param {ASTNode} node The node to report. * @returns {void} + * @private */ - function checkForError(node) { - if (callbacks.length > 0) { - var callback = callbacks[callbacks.length - 1] || {}; + function report(node) { + context.report(node, "Identifier '{{name}}' does not match the pattern '{{pattern}}'.", { + name: node.name, + pattern: pattern + }); + } - // make sure the node's name matches our error argument name - var isAboutError = node.name === callback.errorVariableName; + return { - // we don't consider these use cases as "handling" the error - var doNotCount = ["FunctionDeclaration", "ArrowFunctionExpression", "FunctionExpression", "CatchClause"]; + "Identifier": function(node) { + var name = node.name, + effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent; - // make sure this identifier isn't used as part of one of them - var isHandled = doNotCount.indexOf(node.parent.type) === -1; + // MemberExpressions get special rules + if (node.parent.type === "MemberExpression") { + // return early if properties is false + if (!properties) { + return; + } - if (isAboutError && isHandled) { - // record that this callback handled its error - callback.handled = true; + // Always check object names + if (node.parent.object.type === "Identifier" && + node.parent.object.name === node.name) { + if (isInvalid(name)) { + report(node); + } + + // Report AssignmentExpressions only if they are the left side of the assignment + } else if (effectiveParent.type === "AssignmentExpression" && + (effectiveParent.right.type !== "MemberExpression" || + effectiveParent.left.type === "MemberExpression" && + effectiveParent.left.property.name === node.name)) { + if (isInvalid(name)) { + report(node); + } + } + + // Properties have their own rules + } else if (node.parent.type === "Property") { + // return early if properties is false + if (!properties) { + return; + } + + if (shouldReport(effectiveParent, name)) { + report(node); + } + + // Report anything that is a match and not a CallExpression + } else if (shouldReport(effectiveParent, name)) { + report(node); } } - } - return { - "FunctionDeclaration": startFunction, - "FunctionExpression": startFunction, - "ArrowFunctionExpression": startFunction, - "Identifier": checkForError, - "FunctionDeclaration:exit": endFunction, - "FunctionExpression:exit": endFunction, - "ArrowFunctionExpression:exit": endFunction }; }; -},{}],156:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "properties": { + "type": "boolean" + } + } + } +]; + +},{}],152:[function(require,module,exports){ /** * @fileoverview This option sets a specific tab width for your code - * This rule has been ported and modified from JSCS. - * @author Dmitriy Shekhovtsov - * @copyright 2015 Dmitriy Shekhovtsov. All rights reserved. - * @copyright 2013 Dulin Marat and other contributors. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -/*eslint no-use-before-define:[2, "nofunc"]*/ + + * This rule has been ported and modified from nodeca. + * @author Vitaly Puzrin + * @author Gyandeep Singh + * @copyright 2015 Vitaly Puzrin. All rights reserved. + * @copyright 2015 Gyandeep Singh. All rights reserved. + Copyright (C) 2014 by Vitaly Puzrin + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ +var util = require("util"); +var assign = require("object-assign"); -module.exports = function (context) { - // indentation defaults: 4 spaces - var indentChar = " "; - var indentSize = 4; - var options = {indentSwitchCase: false}; +module.exports = function(context) { - var lines = null; - var indentStack = [0]; - var linesToCheck = null; - var breakIndents = null; + var MESSAGE = "Expected indentation of {{needed}} {{type}} {{characters}} but found {{gotten}}."; + var DEFAULT_VARIABLE_INDENT = 1; + var indentType = "space"; + var indentSize = 4; + var options = { + SwitchCase: 0, + VariableDeclarator: { + var: DEFAULT_VARIABLE_INDENT, + let: DEFAULT_VARIABLE_INDENT, + const: DEFAULT_VARIABLE_INDENT + } + }; + if (context.options.length) { if (context.options[0] === "tab") { - indentChar = "\t"; indentSize = 1; - } else if (typeof context.options[0] === "number") { + indentType = "tab"; + } else /* istanbul ignore else : this will be caught by options validation */ if (typeof context.options[0] === "number") { indentSize = context.options[0]; + indentType = "space"; } if (context.options[1]) { var opts = context.options[1]; - options.indentSwitchCase = opts.indentSwitchCase === true; + options.SwitchCase = opts.SwitchCase || 0; + var variableDeclaratorRules = opts.VariableDeclarator; + if (typeof variableDeclaratorRules === "number") { + options.VariableDeclarator = { + var: variableDeclaratorRules, + let: variableDeclaratorRules, + const: variableDeclaratorRules + }; + } else if (typeof variableDeclaratorRules === "object") { + assign(options.VariableDeclarator, variableDeclaratorRules); + } } } - var blockParents = [ - "IfStatement", - "WhileStatement", - "DoWhileStatement", - "ForStatement", - "ForInStatement", - "ForOfStatement", - "FunctionDeclaration", - "FunctionExpression", - "ArrowExpression", - "CatchClause", - "WithStatement" - ]; - - var indentableNodes = { - BlockStatement: "body", - Program: "body", - ObjectExpression: "properties", - ArrayExpression: "elements", - SwitchStatement: "cases" + var indentPattern = { + normal: indentType === "space" ? /^ +/ : /^\t+/, + excludeCommas: indentType === "space" ? /^[ ,]+/ : /^[\t,]+/ }; - if (options.indentSwitchCase) { - indentableNodes.SwitchCase = "consequent"; - } + var caseIndentStore = {}; - //-------------------------------------------------------------------------- - // Helpers - //-------------------------------------------------------------------------- - /** - * Mark line to be checked - * @param {Number} line - line number + * Reports a given indent violation and properly pluralizes the message + * @param {ASTNode} node Node violating the indent rule + * @param {int} needed Expected indentation character count + * @param {int} gotten Indentation character count in the actual node/code + * @param {Object=} loc Error line and column location + * @param {boolean} isLastNodeCheck Is the error for last node check * @returns {void} */ - function markCheckLine(line) { - linesToCheck[line].check = true; - } + function report(node, needed, gotten, loc, isLastNodeCheck) { + var msgContext = { + needed: needed, + type: indentType, + characters: needed === 1 ? "character" : "characters", + gotten: gotten + }; + var indentChar = indentType === "space" ? " " : "\t"; - /** - * Mark line with targeted node to be checked - * @param {ASTNode} checkNode - targeted node - * @returns {void} - */ - function markCheck(checkNode) { - markCheckLine(checkNode.loc.start.line - 1); - } + /** + * Responsible for fixing the indentation issue fix + * @returns {Function} function to be executed by the fixer + * @private + */ + function getFixerFunction() { + var rangeToFix = []; - /** - * Sets pushing indent of current node - * @param {ASTNode} node - targeted node - * @param {Number} indents - indents count to push - * @returns {void} - */ - function markPush(node, indents) { - linesToCheck[node.loc.start.line - 1].push.push(indents); + if (needed > gotten) { + var spaces = "" + new Array(needed - gotten + 1).join(indentChar); // replace with repeat in future + + if (isLastNodeCheck === true) { + rangeToFix = [ + node.range[1] - 1, + node.range[1] - 1 + ]; + } else { + rangeToFix = [ + node.range[0], + node.range[0] + ]; + } + + return function(fixer) { + return fixer.insertTextBeforeRange(rangeToFix, spaces); + }; + } else { + if (isLastNodeCheck === true) { + rangeToFix = [ + node.range[1] - (gotten - needed) - 1, + node.range[1] - 1 + ]; + } else { + rangeToFix = [ + node.range[0] - (gotten - needed), + node.range[0] + ]; + } + + return function(fixer) { + return fixer.removeRange(rangeToFix); + }; + } + } + + if (loc) { + context.report({ + node: node, + loc: loc, + message: MESSAGE, + data: msgContext, + fix: getFixerFunction() + }); + } else { + context.report({ + node: node, + message: MESSAGE, + data: msgContext, + fix: getFixerFunction() + }); + } } /** - * Marks line as outdent, end of block statement for example - * @param {ASTNode} node - targeted node - * @param {Number} outdents - count of outedents in targeted line - * @returns {void} + * Get node indent + * @param {ASTNode|Token} node Node to examine + * @param {boolean} [byLastLine=false] get indent of node's last line + * @param {boolean} [excludeCommas=false] skip comma on start of line + * @returns {int} Indent */ - function markPop(node, outdents) { - linesToCheck[node.loc.end.line - 1].pop.push(outdents); + function getNodeIndent(node, byLastLine, excludeCommas) { + var token = byLastLine ? context.getLastToken(node) : context.getFirstToken(node); + var src = context.getSource(token, token.loc.start.column); + var regExp = excludeCommas ? indentPattern.excludeCommas : indentPattern.normal; + var indent = regExp.exec(src); + + return indent ? indent[0].length : 0; } /** - * Set alt push for current node - * @param {ASTNode} node - targeted node - * @returns {void} + * Checks node is the first in its own start line. By default it looks by start line. + * @param {ASTNode} node The node to check + * @param {boolean} [byEndLocation=false] Lookup based on start position or end + * @returns {boolean} true if its the first in the its start line */ - function markPushAlt(node) { - linesToCheck[node.loc.start.line - 1].pushAltLine.push(node.loc.end.line - 1); + function isNodeFirstInLine(node, byEndLocation) { + var firstToken = byEndLocation === true ? context.getLastToken(node, 1) : context.getTokenBefore(node), + startLine = byEndLocation === true ? node.loc.end.line : node.loc.start.line, + endLine = firstToken ? firstToken.loc.end.line : -1; + + return startLine !== endLine; } /** - * Marks end of node block to be checked - * and marks targeted node as indent pushing - * @param {ASTNode} pushNode - targeted node - * @param {Number} indents - indent count to push + * Check indent for nodes list + * @param {ASTNode[]} nodes list of node objects + * @param {int} indent needed indent + * @param {boolean} [excludeCommas=false] skip comma on start of line * @returns {void} */ - function markPushAndEndCheck(pushNode, indents) { - markPush(pushNode, indents); - markCheckLine(pushNode.loc.end.line - 1); + function checkNodesIndent(nodes, indent, excludeCommas) { + nodes.forEach(function(node) { + var nodeIndent = getNodeIndent(node, false, excludeCommas); + if ( + node.type !== "ArrayExpression" && node.type !== "ObjectExpression" && + nodeIndent !== indent && isNodeFirstInLine(node) + ) { + report(node, indent, nodeIndent); + } + }); } /** - * Mark node as switch case statement - * and set push\pop indentation changes - * @param {ASTNode} caseNode - targeted node - * @param {ASTNode[]} children - consequent child nodes of case node + * Check last node line indent this detects, that block closed correctly + * @param {ASTNode} node Node to examine + * @param {int} lastLineIndent needed indent * @returns {void} */ - function markCase(caseNode, children) { - var outdentNode = getCaseOutdent(children); + function checkLastNodeLineIndent(node, lastLineIndent) { + var lastToken = context.getLastToken(node); + var endIndent = getNodeIndent(lastToken, true); - if (outdentNode) { - // If a case statement has a `break` as a direct child and it is the - // first one encountered, use it as the example for all future case indentation - if (breakIndents === null) { - breakIndents = (caseNode.loc.start.column === outdentNode.loc.start.column) ? 1 : 0; - } - markPop(outdentNode, breakIndents); - } else { - markPop(caseNode, 0); + if (endIndent !== lastLineIndent && isNodeFirstInLine(node, true)) { + report( + node, + lastLineIndent, + endIndent, + { line: lastToken.loc.start.line, column: lastToken.loc.start.column }, + true + ); } } /** - * Mark child nodes to be checked later of targeted node, - * only if child node not in same line as targeted one - * (if child and parent nodes wrote in single line) - * @param {ASTNode} node - targeted node + * Check first node line indent is correct + * @param {ASTNode} node Node to examine + * @param {int} firstLineIndent needed indent * @returns {void} */ - function markChildren(node) { - getChildren(node).forEach(function(childNode) { - if (childNode.loc.start.line !== node.loc.start.line || node.type === "Program") { - markCheck(childNode); - } - }); + function checkFirstNodeLineIndent(node, firstLineIndent) { + var startIndent = getNodeIndent(node, false); + if (startIndent !== firstLineIndent && isNodeFirstInLine(node)) { + report( + node, + firstLineIndent, + startIndent, + { line: node.loc.start.line, column: node.loc.start.column } + ); + } } /** - * Mark child block as scope pushing and mark to check - * @param {ASTNode} node - target node - * @param {String} property - target node property containing child - * @returns {void} + * Returns the VariableDeclarator based on the current node + * if not present then return null + * @param {ASTNode} node node to examine + * @returns {ASTNode|void} if found then node otherwise null */ - function markAlternateBlockStatement(node, property) { - var child = node[property]; - if (child && child.type === "BlockStatement") { - markCheck(child); + function getVariableDeclaratorNode(node) { + var parent = node.parent; + + while (parent.type !== "VariableDeclarator" && parent.type !== "Program") { + parent = parent.parent; } + + return parent.type === "VariableDeclarator" ? parent : null; } /** - * Checks whether node is multiline or single line - * @param {ASTNode} node - target node - * @returns {boolean} - is multiline node + * Check to see if the node is part of the multi-line variable declaration. + * Also if its on the same line as the varNode + * @param {ASTNode} node node to check + * @param {ASTNode} varNode variable declaration node to check against + * @returns {boolean} True if all the above condition satisfy */ - function isMultiline(node) { - return node.loc.start.line !== node.loc.end.line; + function isNodeInVarOnTop(node, varNode) { + return varNode && + varNode.parent.loc.start.line === node.loc.start.line && + varNode.parent.declarations.length > 1; } /** - * Get switch case statement outdent node if any - * @param {ASTNode[]} caseChildren - case statement childs - * @returns {ASTNode} - outdent node + * Check to see if the argument before the callee node is multi-line and + * there should only be 1 argument before the callee node + * @param {ASTNode} node node to check + * @returns {boolean} True if arguments are multi-line */ - function getCaseOutdent(caseChildren) { - var outdentNode; - caseChildren.some(function(node) { - if (node.type === "BreakStatement") { - outdentNode = node; - return true; - } - }); + function isArgBeforeCalleeNodeMultiline(node) { + var parent = node.parent; - return outdentNode; + if (parent.arguments.length >= 2 && parent.arguments[1] === node) { + return parent.arguments[0].loc.end.line > parent.arguments[0].loc.start.line; + } + + return false; } /** - * Returns block containing node - * @param {ASTNode} node - targeted node - * @returns {ASTNode} - block node + * Check indent for function block content + * @param {ASTNode} node node to examine + * @returns {void} */ - function getBlockNodeToMark(node) { - var parent = node.parent; + function checkIndentInFunctionBlock(node) { - // The parent of an else is the entire if/else block. To avoid over indenting - // in the case of a non-block if with a block else, mark push where the else starts, - // not where the if starts! - if (parent.type === "IfStatement" && parent.alternate === node) { - return node; + // Search first caller in chain. + // Ex.: + // + // Models <- Identifier + // .User + // .find() + // .exec(function() { + // // function body + // }); + // + // Looks for 'Models' + var calleeNode = node.parent; // FunctionExpression + var indent; + + if (calleeNode.parent && + (calleeNode.parent.type === "Property" || + calleeNode.parent.type === "ArrayExpression")) { + // If function is part of array or object, comma can be put at left + indent = getNodeIndent(calleeNode, false, true); + } else { + // If function is standalone, simple calculate indent + indent = getNodeIndent(calleeNode); } - // The end line to check of a do while statement needs to be the location of the - // closing curly brace, not the while statement, to avoid marking the last line of - // a multiline while as a line to check. - if (parent.type === "DoWhileStatement") { - return node; + if (calleeNode.parent.type === "CallExpression") { + var calleeParent = calleeNode.parent; + + if (calleeNode.type !== "FunctionExpression" && calleeNode.type !== "ArrowFunctionExpression") { + if (calleeParent && calleeParent.loc.start.line < node.loc.start.line) { + indent = getNodeIndent(calleeParent); + } + } else { + if (isArgBeforeCalleeNodeMultiline(calleeNode) && + calleeParent.callee.loc.start.line === calleeParent.callee.loc.end.line && + !isNodeFirstInLine(calleeNode)) { + indent = getNodeIndent(calleeParent); + } + } } - // Detect bare blocks: a block whose parent doesn"t expect blocks in its syntax specifically. - if (blockParents.indexOf(parent.type) === -1) { - return node; + // function body indent should be indent + indent size + indent += indentSize; + + // check if the node is inside a variable + var parentVarNode = getVariableDeclaratorNode(node); + if (parentVarNode && isNodeInVarOnTop(node, parentVarNode)) { + indent += indentSize * options.VariableDeclarator[parentVarNode.parent.kind]; } - return parent; + if (node.body.length > 0) { + checkNodesIndent(node.body, indent); + } + + checkLastNodeLineIndent(node, indent - indentSize); } + /** - * Get node's children - * @param {ASTNode} node - current node - * @returns {ASTNode[]} - children + * Checks if the given node starts and ends on the same line + * @param {ASTNode} node The node to check + * @returns {boolean} Whether or not the block starts and ends on the same line. */ - function getChildren(node) { - var childrenProperty = indentableNodes[node.type]; - return node[childrenProperty]; + function isSingleLineNode(node) { + var lastToken = context.getLastToken(node), + startLine = node.loc.start.line, + endLine = lastToken.loc.end.line; + + return startLine === endLine; } /** - * Gets indentation in line `i` - * @param {Number} i - number of line to get indentation - * @returns {Number} - count of indentation symbols + * Check to see if the first element inside an array is an object and on the same line as the node + * If the node is not an array then it will return false. + * @param {ASTNode} node node to check + * @returns {boolean} success/failure */ - function getIndentationFromLine(i) { - var rNotIndentChar = new RegExp("[^" + indentChar + "]"); - var firstContent = lines[i].search(rNotIndentChar); - if (firstContent === -1) { - firstContent = lines[i].length; + function isFirstArrayElementOnSameLine(node) { + if (node.type === "ArrayExpression" && node.elements[0]) { + return node.elements[0].loc.start.line === node.loc.start.line && node.elements[0].type === "ObjectExpression"; + } else { + return false; } - return firstContent; } /** - * Compares expected and actual indentation - * and reports any violations - * @param {ASTNode} node - node used only for reporting + * Check indent for array block content or object block content + * @param {ASTNode} node node to examine * @returns {void} */ - function checkIndentations(node) { - linesToCheck.forEach(function(line, i) { - var actualIndentation = getIndentationFromLine(i); - var expectedIndentation = getExpectedIndentation(line, actualIndentation); + function checkIndentInArrayOrObjectBlock(node) { + // Skip inline + if (isSingleLineNode(node)) { + return; + } - if (line.check) { + var elements = (node.type === "ArrayExpression") ? node.elements : node.properties; - if (actualIndentation !== expectedIndentation) { - context.report(node, - {line: i + 1, column: expectedIndentation}, - "Expected indentation of " + expectedIndentation + " characters."); - // correct the indentation so that future lines - // can be validated appropriately - actualIndentation = expectedIndentation; + // filter out empty elements example would be [ , 2] so remove first element as espree considers it as null + elements = elements.filter(function(elem) { + return elem !== null; + }); + + // Skip if first element is in same line with this node + if (elements.length > 0 && elements[0].loc.start.line === node.loc.start.line) { + return; + } + + var nodeIndent; + var elementsIndent; + var parentVarNode = getVariableDeclaratorNode(node); + + // TODO - come up with a better strategy in future + if (isNodeFirstInLine(node)) { + var parent = node.parent; + var effectiveParent = parent; + + if (parent.type === "MemberExpression") { + if (isNodeFirstInLine(parent)) { + effectiveParent = parent.parent.parent; + } else { + effectiveParent = parent.parent; } } + nodeIndent = getNodeIndent(effectiveParent); + if (parentVarNode && parentVarNode.loc.start.line !== node.loc.start.line) { + if (parent.type !== "VariableDeclarator" || parentVarNode === parentVarNode.parent.declarations[0]) { + nodeIndent = nodeIndent + (indentSize * options.VariableDeclarator[parentVarNode.parent.kind]); + } else if (parent.loc.start.line !== node.loc.start.line && parentVarNode === parentVarNode.parent.declarations[0]) { + nodeIndent = nodeIndent + indentSize; + } + } else if (!parentVarNode && !isFirstArrayElementOnSameLine(parent) && effectiveParent.type !== "MemberExpression" && effectiveParent.type !== "ExpressionStatement" && effectiveParent.type !== "AssignmentExpression" && effectiveParent.type !== "Property") { + nodeIndent = nodeIndent + indentSize; + } - if (line.push.length) { - pushExpectedIndentations(line, actualIndentation); + elementsIndent = nodeIndent + indentSize; + + checkFirstNodeLineIndent(node, nodeIndent); + } else { + nodeIndent = getNodeIndent(node); + elementsIndent = nodeIndent + indentSize; + } + + // check if the node is a multiple variable declaration, if yes then make sure indentation takes into account + // variable indentation concept + if (isNodeInVarOnTop(node, parentVarNode)) { + elementsIndent += indentSize * options.VariableDeclarator[parentVarNode.parent.kind]; + } + + // Comma can be placed before property name + checkNodesIndent(elements, elementsIndent, true); + + if (elements.length > 0) { + // Skip last block line check if last item in same line + if (elements[elements.length - 1].loc.end.line === node.loc.end.line) { + return; } - }); + } + + checkLastNodeLineIndent(node, elementsIndent - indentSize); } /** - * Counts expected indentation for given line number - * @param {Number} line - line number - * @param {Number} actual - actual indentation - * @returns {number} - expected indentation + * Check if the node or node body is a BlockStatement or not + * @param {ASTNode} node node to test + * @returns {boolean} True if it or its body is a block statement */ - function getExpectedIndentation(line, actual) { - var outdent = indentSize * Math.max.apply(null, line.pop); + function isNodeBodyBlock(node) { + return node.type === "BlockStatement" || (node.body && node.body.type === "BlockStatement") || + (node.consequent && node.consequent.type === "BlockStatement"); + } - var idx = indentStack.length - 1; - var expected = indentStack[idx]; + /** + * Check indentation for blocks + * @param {ASTNode} node node to check + * @returns {void} + */ + function blockIndentationCheck(node) { + // Skip inline blocks + if (isSingleLineNode(node)) { + return; + } - if (!Array.isArray(expected)) { - expected = [expected]; + if (node.parent && ( + node.parent.type === "FunctionExpression" || + node.parent.type === "FunctionDeclaration" || + node.parent.type === "ArrowFunctionExpression" + )) { + checkIndentInFunctionBlock(node); + return; } - expected = expected.map(function(value) { - if (line.pop.length) { - value -= outdent; - } + var indent; + var nodesToCheck = []; - return value; - }).reduce(function(previous, current) { - // when the expected is an array, resolve the value - // back into a Number by checking both values are the actual indentation - return actual === current ? current : previous; - }); + // For this statements we should check indent from statement begin + // (not from block begin) + var statementsWithProperties = [ + "IfStatement", "WhileStatement", "ForStatement", "ForInStatement", "ForOfStatement", "DoWhileStatement" + ]; - indentStack[idx] = expected; + if (node.parent && statementsWithProperties.indexOf(node.parent.type) !== -1 && isNodeBodyBlock(node)) { + indent = getNodeIndent(node.parent); + } else { + indent = getNodeIndent(node); + } - line.pop.forEach(function() { - indentStack.pop(); - }); + if (node.type === "IfStatement" && node.consequent.type !== "BlockStatement") { + nodesToCheck = [node.consequent]; + } else if (util.isArray(node.body)) { + nodesToCheck = node.body; + } else { + nodesToCheck = [node.body]; + } - return expected; + if (nodesToCheck.length > 0) { + checkNodesIndent(nodesToCheck, indent + indentSize); + } + + if (node.type === "BlockStatement") { + checkLastNodeLineIndent(node, indent); + } } /** - * Store in stack expected indentations - * @param {Number} line - current line - * @param {Number} actualIndentation - actual indentation at current line + * Filter out the elements which are on the same line of each other or the node. + * basically have only 1 elements from each line except the variable declaration line. + * @param {ASTNode} node Variable declaration node + * @returns {ASTNode[]} Filtered elements + */ + function filterOutSameLineVars(node) { + return node.declarations.reduce(function(finalCollection, elem) { + var lastElem = finalCollection[finalCollection.length - 1]; + + if ((elem.loc.start.line !== node.loc.start.line && !lastElem) || + (lastElem && lastElem.loc.start.line !== elem.loc.start.line)) { + finalCollection.push(elem); + } + + return finalCollection; + }, []); + } + + /** + * Check indentation for variable declarations + * @param {ASTNode} node node to examine * @returns {void} */ - function pushExpectedIndentations(line, actualIndentation) { - var indents = Math.max.apply(null, line.push); - var expected = actualIndentation + (indentSize * indents); + function checkIndentInVariableDeclarations(node) { + var elements = filterOutSameLineVars(node); + var nodeIndent = getNodeIndent(node); + var lastElement = elements[elements.length - 1]; - // when a line has alternate indentations, push an array of possible values - // on the stack, to be resolved when checked against an actual indentation - if (line.pushAltLine.length) { - expected = [expected]; - line.pushAltLine.forEach(function(altLine) { - expected.push(getIndentationFromLine(altLine) + (indentSize * indents)); - }); + var elementsIndent = nodeIndent + indentSize * options.VariableDeclarator[node.kind]; + + // Comma can be placed before declaration + checkNodesIndent(elements, elementsIndent, true); + + // Only check the last line if there is any token after the last item + if (context.getLastToken(node).loc.end.line <= lastElement.loc.end.line) { + return; } - line.push.forEach(function() { - indentStack.push(expected); - }); + var tokenBeforeLastElement = context.getTokenBefore(lastElement); + + if (tokenBeforeLastElement.value === ",") { + // Special case for comma-first syntax where the semicolon is indented + checkLastNodeLineIndent(node, getNodeIndent(tokenBeforeLastElement)); + } else { + checkLastNodeLineIndent(node, elementsIndent - indentSize); + } } - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + /** + * Check and decide whether to check for indentation for blockless nodes + * Scenarios are for or while statements without braces around them + * @param {ASTNode} node node to examine + * @returns {void} + */ + function blockLessNodes(node) { + if (node.body.type !== "BlockStatement") { + blockIndentationCheck(node); + } + } - return { - "Program": function (node) { - lines = context.getSourceLines(); - linesToCheck = lines.map(function () { - return { - push: [], - pushAltLine: [], - pop: [], - check: false - }; - }); + /** + * Returns the expected indentation for the case statement + * @param {ASTNode} node node to examine + * @param {int} [switchIndent] indent for switch statement + * @returns {int} indent size + */ + function expectedCaseIndent(node, switchIndent) { + var switchNode = (node.type === "SwitchStatement") ? node : node.parent; + var caseIndent; - if (!isMultiline(node)) { - return; + if (caseIndentStore[switchNode.loc.start.line]) { + return caseIndentStore[switchNode.loc.start.line]; + } else { + if (typeof switchIndent === "undefined") { + switchIndent = getNodeIndent(switchNode); } - markChildren(node); - }, - "Program:exit": function (node) { - checkIndentations(node); - }, + if (switchNode.cases.length > 0 && options.SwitchCase === 0) { + caseIndent = switchIndent; + } else { + caseIndent = switchIndent + (indentSize * options.SwitchCase); + } - "BlockStatement": function (node) { - if (!isMultiline(node)) { - return; + caseIndentStore[switchNode.loc.start.line] = caseIndent; + return caseIndent; + } + } + + return { + "Program": function(node) { + if (node.body.length > 0) { + // Root nodes should have no indent + checkNodesIndent(node.body, getNodeIndent(node)); } + }, - markChildren(node); - markPop(node, 1); + "BlockStatement": blockIndentationCheck, - markPushAndEndCheck(getBlockNodeToMark(node), 1); + "WhileStatement": blockLessNodes, + + "ForStatement": blockLessNodes, + + "ForInStatement": blockLessNodes, + + "ForOfStatement": blockLessNodes, + + "DoWhileStatement": blockLessNodes, + + "IfStatement": function(node) { + if (node.consequent.type !== "BlockStatement" && node.consequent.loc.start.line > node.loc.start.line) { + blockIndentationCheck(node); + } }, - "IfStatement": function (node) { - markAlternateBlockStatement(node, "alternate"); + "VariableDeclaration": function(node) { + if (node.declarations[node.declarations.length - 1].loc.start.line > node.declarations[0].loc.start.line) { + checkIndentInVariableDeclarations(node); + } }, - "TryStatement": function (node) { - markAlternateBlockStatement(node, "handler"); - markAlternateBlockStatement(node, "finalizer"); + "ObjectExpression": function(node) { + checkIndentInArrayOrObjectBlock(node); }, - "SwitchStatement": function (node) { - if (!isMultiline(node)) { - return; - } + "ArrayExpression": function(node) { + checkIndentInArrayOrObjectBlock(node); + }, - var indents = 1; - var children = getChildren(node); + "SwitchStatement": function(node) { + // Switch is not a 'BlockStatement' + var switchIndent = getNodeIndent(node); + var caseIndent = expectedCaseIndent(node, switchIndent); + checkNodesIndent(node.cases, caseIndent); - if (node.loc.start.column === children[0].loc.start.column) { - indents = 0; - } - markChildren(node); - markPop(node, indents); - markPushAndEndCheck(node, indents); + checkLastNodeLineIndent(node, switchIndent); }, - "SwitchCase": function (node) { - if (!options.indentSwitchCase) { + "SwitchCase": function(node) { + // Skip inline cases + if (isSingleLineNode(node)) { return; } + var caseIndent = expectedCaseIndent(node); + checkNodesIndent(node.consequent, caseIndent + indentSize); + } + }; - if (!isMultiline(node)) { - return; +}; + +module.exports.schema = [ + { + "oneOf": [ + { + "enum": ["tab"] + }, + { + "type": "integer" } + ] + }, + { + "type": "object", + "properties": { + "SwitchCase": { + "type": "integer" + }, + "VariableDeclarator": { + "type": ["integer", "object"], + "properties": { + "var": { + "type": "integer" + }, + "let": { + "type": "integer" + }, + "const": { + "type": "integer" + } + } + } + }, + "additionalProperties": false + } +]; - var children = getChildren(node); +},{"object-assign":108,"util":111}],153:[function(require,module,exports){ +/** + * @fileoverview A rule to control the style of variable initializations. + * @author Colin Ihrig + * @copyright 2015 Colin Ihrig. All rights reserved. + */ - if (children.length === 1 && children[0].type === "BlockStatement") { - return; - } +"use strict"; - markPush(node, 1); - markCheck(node); - markChildren(node); +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ - markCase(node, children); - }, +/** + * Checks whether or not a given node is a for loop. + * @param {ASTNode} block - A node to check. + * @returns {boolean} `true` when the node is a for loop. + */ +function isForLoop(block) { + return block.type === "ForInStatement" || + block.type === "ForOfStatement" || + block.type === "ForStatement"; +} - // indentations inside of function expressions can be offset from - // either the start of the function or the end of the function, therefore - // mark all starting lines of functions as potential indentations - "FunctionDeclaration": function (node) { - markPushAlt(node); - }, - "FunctionExpression": function (node) { - markPushAlt(node); +/** + * Checks whether or not a given declarator node has its initializer. + * @param {ASTNode} node - A declarator node to check. + * @returns {boolean} `true` when the node has its initializer. + */ +function isInitialized(node) { + var declaration = node.parent; + var block = declaration.parent; + + if (isForLoop(block)) { + if (block.type === "ForStatement") { + return block.init === declaration; } + return block.left === declaration; + } + return Boolean(node.init); +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + var MODE_ALWAYS = "always", + MODE_NEVER = "never"; + + var mode = context.options[0] || MODE_ALWAYS; + var params = context.options[1] || {}; + //-------------------------------------------------------------------------- + // Public API + //-------------------------------------------------------------------------- + + return { + "VariableDeclaration:exit": function(node) { + + var kind = node.kind, + declarations = node.declarations; + + for (var i = 0; i < declarations.length; ++i) { + var declaration = declarations[i], + id = declaration.id, + initialized = isInitialized(declaration), + isIgnoredForLoop = params.ignoreForLoopInit && isForLoop(node.parent); + if (id.type !== "Identifier") { + continue; + } + + if (mode === MODE_ALWAYS && !initialized) { + context.report(declaration, "Variable '" + id.name + "' should be initialized on declaration."); + } else if (mode === MODE_NEVER && kind !== "const" && initialized && !isIgnoredForLoop) { + context.report(declaration, "Variable '" + id.name + "' should not be initialized on declaration."); + } + } + } }; +}; +module.exports.schema = { + "anyOf": [ + { + "type": "array", + "items": [ + { + "enum": [0, 1, 2] + }, + { + "enum": ["always"] + } + ], + "minItems": 1, + "maxItems": 2 + }, + { + "type": "array", + "items": [ + { + "enum": [0, 1, 2] + }, + { + "enum": ["never"] + }, + { + "type": "object", + "properties": { + "ignoreForLoopInit": { + "type": "boolean" + } + }, + "additionalProperties": false + } + ], + "minItems": 1, + "maxItems": 3 + } + ] }; -},{}],157:[function(require,module,exports){ +},{}],154:[function(require,module,exports){ /** + * @fileoverview A rule to ensure consistent quotes used in jsx syntax. + * @author Mathias Schreck <https://github.com/lo1tuma> + * @copyright 2015 Mathias Schreck + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------ + +var QUOTE_SETTINGS = { + "prefer-double": { + quote: "\"", + description: "singlequote" + }, + "prefer-single": { + quote: "'", + description: "doublequote" + } +}; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var quoteOption = context.options[0] || "prefer-double", + setting = QUOTE_SETTINGS[quoteOption]; + + /** + * Checks if the given string literal node uses the expected quotes + * @param {ASTNode} node - A string literal node. + * @returns {boolean} Whether or not the string literal used the expected quotes. + * @public + */ + function usesExpectedQuotes(node) { + return node.value.indexOf(setting.quote) !== -1 || astUtils.isSurroundedBy(node.raw, setting.quote); + } + + return { + "JSXAttribute": function(node) { + var attributeValue = node.value; + + if (attributeValue && astUtils.isStringLiteral(attributeValue) && !usesExpectedQuotes(attributeValue)) { + context.report(attributeValue, "Unexpected usage of {{description}}.", setting); + } + } + }; +}; + +module.exports.schema = [ + { + "enum": [ "prefer-single", "prefer-double" ] + } +]; + +},{"../ast-utils":113}],155:[function(require,module,exports){ +/** * @fileoverview Rule to specify spacing of object literal keys and values * @author Brandon Mills * @copyright 2014 Brandon Mills. All rights reserved. */ "use strict"; @@ -20609,29 +27784,10 @@ function containsLineTerminator(str) { return /[\n\r\u2028\u2029]/.test(str); } /** - * Gets an object literal property's key as the identifier name or string value. - * @param {ASTNode} property Property node whose key to retrieve. - * @returns {string} The property's key. - */ -function getKey(property) { - return property.key.name || property.key.value; -} - -/** - * Gets the number of characters in a key, including quotes around string keys. - * @param {ASTNode} property Property of on object literal. - * @returns {int} Width of the key, including string quotes where present. - */ -function getKeyWidth(property) { - var key = property.key; - return (key.type === "Identifier" ? key.name : key.raw).length; -} - -/** * Gets the last element of an array. * @param {Array} arr An array. * @returns {any} Last element of arr. */ function last(arr) { @@ -20643,11 +27799,11 @@ * @param {ASTNode} lastMember The last Property known to be in the group. * @param {ASTNode} candidate The next Property that might be in the group. * @returns {boolean} True if the candidate property is part of the group. */ function continuesPropertyGroup(lastMember, candidate) { - var groupEndLine = lastMember.loc.end.line, + var groupEndLine = lastMember.loc.start.line, candidateStartLine = candidate.loc.start.line, comments, i; if (candidateStartLine - groupEndLine <= 1) { return true; @@ -20671,17 +27827,26 @@ } return false; } +/** + * Checks whether a node is contained on a single line. + * @param {ASTNode} node AST Node being evaluated. + * @returns {boolean} True if the node is a single line. + */ +function isSingleLine(node) { + return (node.loc.end.line === node.loc.start.line); +} + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ var messages = { - key: "{{error}} space after key \"{{key}}\".", - value: "{{error}} space before value for key \"{{key}}\"." + key: "{{error}} space after {{computed}}key \"{{key}}\".", + value: "{{error}} space before value for {{computed}}key \"{{key}}\"." }; module.exports = function(context) { /** @@ -20693,32 +27858,47 @@ * } */ var options = context.options[0] || {}, align = options.align, + mode = options.mode || "strict", beforeColon = +!!options.beforeColon, // Defaults to false afterColon = +!(options.afterColon === false); // Defaults to true /** - * Gets the whitespace around the colon in an object literal property. - * @param {ASTNode} property Property node from an object literal. - * @returns {Object} Whitespace before and after the property's colon. + * Starting from the given a node (a property.key node here) looks forward + * until it finds the last token before a colon punctuator and returns it. + * @param {ASTNode} node The node to start looking from. + * @returns {ASTNode} The last token before a colon punctuator. */ - function getPropertyWhitespace(property) { - var whitespace = /^(\s*):(\s*)/.exec(context.getSource().slice( - property.key.range[1], property.value.range[0] - )); + function getLastTokenBeforeColon(node) { + var prevNode; - if (whitespace) { - return { - beforeColon: whitespace[1], - afterColon: whitespace[2] - }; + while (node && (node.type !== "Punctuator" || node.value !== ":")) { + prevNode = node; + node = context.getTokenAfter(node); } + + return prevNode; } /** + * Gets an object literal property's key as the identifier name or string value. + * @param {ASTNode} property Property node whose key to retrieve. + * @returns {string} The property's key. + */ + function getKey(property) { + var key = property.key; + + if (property.computed) { + return context.getSource().slice(key.range[0], key.range[1]); + } + + return property.key.name || property.key.value; + } + + /** * Reports an appropriately-formatted error if spacing is incorrect on one * side of the colon. * @param {ASTNode} property Key-value pair in an object literal. * @param {string} side Side being verified - either "key" or "value". * @param {string} whitespace Actual whitespace string. @@ -20729,24 +27909,89 @@ var diff = whitespace.length - expected, key = property.key, firstTokenAfterColon = context.getTokenAfter(key, 1), location = side === "key" ? key.loc.start : firstTokenAfterColon.loc.start; - if (diff && !(expected && containsLineTerminator(whitespace))) { + if ((diff && mode === "strict" || diff < 0 && mode === "minimum") && + !(expected && containsLineTerminator(whitespace)) + ) { context.report(property[side], location, messages[side], { error: diff > 0 ? "Extra" : "Missing", + computed: property.computed ? "computed " : "", key: getKey(property) }); } } /** + * Gets the number of characters in a key, including quotes around string + * keys and braces around computed property keys. + * @param {ASTNode} property Property of on object literal. + * @returns {int} Width of the key. + */ + function getKeyWidth(property) { + var startToken, endToken; + + // Ignore shorthand methods and properties, as they have no colon + if (property.method || property.shorthand) { + return 0; + } + + startToken = context.getFirstToken(property); + endToken = getLastTokenBeforeColon(property.key); + + return endToken.range[1] - startToken.range[0]; + } + + /** + * Gets the whitespace around the colon in an object literal property. + * @param {ASTNode} property Property node from an object literal. + * @returns {Object} Whitespace before and after the property's colon. + */ + function getPropertyWhitespace(property) { + var whitespace = /(\s*):(\s*)/.exec(context.getSource().slice( + property.key.range[1], property.value.range[0] + )); + + if (whitespace) { + return { + beforeColon: whitespace[1], + afterColon: whitespace[2] + }; + } + } + + /** + * Creates groups of properties. + * @param {ASTNode} node ObjectExpression node being evaluated. + * @returns {Array.<ASTNode[]>} Groups of property AST node lists. + */ + function createGroups(node) { + if (node.properties.length === 1) { + return [node.properties]; + } + + return node.properties.reduce(function(groups, property) { + var currentGroup = last(groups), + prev = last(currentGroup); + + if (!prev || continuesPropertyGroup(prev, property)) { + currentGroup.push(property); + } else { + groups.push([property]); + } + + return groups; + }, [[]]); + } + + /** * Verifies correct vertical alignment of a group of properties. * @param {ASTNode[]} properties List of Property AST nodes. * @returns {void} */ - function verifyAlignment(properties) { + function verifyGroupAlignment(properties) { var length = properties.length, widths = properties.map(getKeyWidth), // Width of keys, including quotes targetWidth = Math.max.apply(null, widths), i, property, whitespace, width; @@ -20771,48 +28016,506 @@ report(property, "value", whitespace.afterColon, afterColon); } } } + /** + * Verifies vertical alignment, taking into account groups of properties. + * @param {ASTNode} node ObjectExpression node being evaluated. + * @returns {void} + */ + function verifyAlignment(node) { + createGroups(node).forEach(function(group) { + verifyGroupAlignment(group); + }); + } + + /** + * Verifies spacing of property conforms to specified options. + * @param {ASTNode} node Property node being evaluated. + * @returns {void} + */ + function verifySpacing(node) { + var whitespace = getPropertyWhitespace(node); + if (whitespace) { // Object literal getters/setters lack colons + report(node, "key", whitespace.beforeColon, beforeColon); + report(node, "value", whitespace.afterColon, afterColon); + } + } + + /** + * Verifies spacing of each property in a list. + * @param {ASTNode[]} properties List of Property AST nodes. + * @returns {void} + */ + function verifyListSpacing(properties) { + var length = properties.length; + + for (var i = 0; i < length; i++) { + verifySpacing(properties[i]); + } + } + + //-------------------------------------------------------------------------- + // Public API + //-------------------------------------------------------------------------- + if (align) { // Verify vertical alignment return { "ObjectExpression": function(node) { - node.properties.reduce(function(groups, property) { - var currentGroup = last(groups), - prev = last(currentGroup); - - if (!prev || continuesPropertyGroup(prev, property)) { - currentGroup.push(property); - } else { - groups.push([property]); - } - - return groups; - }, [[]]).forEach(function(group) { - verifyAlignment(group); - }); + if (isSingleLine(node)) { + verifyListSpacing(node.properties); + } else { + verifyAlignment(node); + } } }; } else { // Strictly obey beforeColon and afterColon in each property return { - "Property": function (node) { - var whitespace = getPropertyWhitespace(node); - if (whitespace) { // Object literal getters/setters lack colons - report(node, "key", whitespace.beforeColon, beforeColon); - report(node, "value", whitespace.afterColon, afterColon); + "Property": function(node) { + verifySpacing(node); + } + }; + + } + +}; + +module.exports.schema = [ + { + "type": "object", + "properties": { + "align": { + "enum": ["colon", "value"] + }, + "mode": { + "enum": ["strict", "minimum"] + }, + "beforeColon": { + "type": "boolean" + }, + "afterColon": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{}],156:[function(require,module,exports){ +/** + * @fileoverview Rule to forbid mixing LF and LFCR line breaks. + * @author Erik Mueller + * @copyright 2015 Varun Verma. All rights reserverd. + * @copyright 2015 James Whitney. All rights reserved. + * @copyright 2015 Erik Mueller. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + var EXPECTED_LF_MSG = "Expected linebreaks to be 'LF' but found 'CRLF'.", + EXPECTED_CRLF_MSG = "Expected linebreaks to be 'CRLF' but found 'LF'."; + + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + + /** + * Builds a fix function that replaces text at the specified range in the source text. + * @param {int[]} range The range to replace + * @param {string} text The text to insert. + * @returns {function} Fixer function + * @private + */ + function createFix(range, text) { + return function(fixer) { + return fixer.replaceTextRange(range, text); + }; + } + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + return { + "Program": function checkForlinebreakStyle(node) { + var linebreakStyle = context.options[0] || "unix", + expectedLF = linebreakStyle === "unix", + expectedLFChars = expectedLF ? "\n" : "\r\n", + source = context.getSource(), + pattern = /\r\n|\r|\n|\u2028|\u2029/g, + match, + index, + range; + + var i = 0; + while ((match = pattern.exec(source)) !== null) { + i++; + if (match[0] === expectedLFChars) { + continue; } + + index = match.index; + range = [index, index + match[0].length]; + context.report({ + node: node, + loc: { + line: i, + column: context.getSourceLines()[i - 1].length + }, + message: expectedLF ? EXPECTED_LF_MSG : EXPECTED_CRLF_MSG, + fix: createFix(range, expectedLFChars) + }); } + } + }; +}; + +module.exports.schema = [ + { + "enum": ["unix", "windows"] + } +]; + +},{}],157:[function(require,module,exports){ +/** + * @fileoverview Enforces empty lines around comments. + * @author Jamund Ferguson + * @copyright 2015 Mathieu M-Gosselin. All rights reserved. + * @copyright 2015 Jamund Ferguson. All rights reserved. + * @copyright 2015 Gyandeep Singh. All rights reserved. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var assign = require("object-assign"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Return an array with with any line numbers that are empty. + * @param {Array} lines An array of each line of the file. + * @returns {Array} An array of line numbers. + */ +function getEmptyLineNums(lines) { + var emptyLines = lines.map(function(line, i) { + return { + code: line.trim(), + num: i + 1 }; + }).filter(function(line) { + return !line.code; + }).map(function(line) { + return line.num; + }); + return emptyLines; +} +/** + * Return an array with with any line numbers that contain comments. + * @param {Array} comments An array of comment nodes. + * @returns {Array} An array of line numbers. + */ +function getCommentLineNums(comments) { + var lines = []; + comments.forEach(function(token) { + var start = token.loc.start.line; + var end = token.loc.end.line; + lines.push(start, end); + }); + return lines; +} + +/** + * Determines if a value is an array. + * @param {number} val The value we wish to check for in the array.. + * @param {Array} array An array. + * @returns {boolean} True if the value is in the array.. + */ +function contains(val, array) { + return array.indexOf(val) > -1; +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + var options = context.options[0] ? assign({}, context.options[0]) : {}; + options.beforeLineComment = options.beforeLineComment || false; + options.afterLineComment = options.afterLineComment || false; + options.beforeBlockComment = typeof options.beforeBlockComment !== "undefined" ? options.beforeBlockComment : true; + options.afterBlockComment = options.afterBlockComment || false; + options.allowBlockStart = options.allowBlockStart || false; + options.allowBlockEnd = options.allowBlockEnd || false; + + /** + * Returns whether or not comments are not on lines starting with or ending with code + * @param {ASTNode} node The comment node to check. + * @returns {boolean} True if the comment is not alone. + */ + function codeAroundComment(node) { + + var lines = context.getSourceLines(); + + // Get the whole line and cut it off at the start of the comment + var startLine = lines[node.loc.start.line - 1]; + var endLine = lines[node.loc.end.line - 1]; + + var preamble = startLine.slice(0, node.loc.start.column).trim(); + + // Also check after the comment + var postamble = endLine.slice(node.loc.end.column).trim(); + + // Should be false if there was only whitespace around the comment + return !!(preamble || postamble); } + /** + * Returns whether or not comments are inside a node type or not. + * @param {ASTNode} node The Comment node. + * @param {ASTNode} parent The Comment parent node. + * @param {string} nodeType The parent type to check against. + * @returns {boolean} True if the comment is inside nodeType. + */ + function isCommentInsideNodeType(node, parent, nodeType) { + return parent.type === nodeType || + (parent.body && parent.body.type === nodeType) || + (parent.consequent && parent.consequent.type === nodeType); + } + + /** + * Returns whether or not comments are at the parent start or not. + * @param {ASTNode} node The Comment node. + * @param {string} nodeType The parent type to check against. + * @returns {boolean} True if the comment is at parent start. + */ + function isCommentAtParentStart(node, nodeType) { + var ancestors = context.getAncestors(); + var parent; + + if (ancestors.length) { + parent = ancestors.pop(); + } + + return parent && isCommentInsideNodeType(node, parent, nodeType) && + node.loc.start.line - parent.loc.start.line === 1; + } + + /** + * Returns whether or not comments are at the parent end or not. + * @param {ASTNode} node The Comment node. + * @param {string} nodeType The parent type to check against. + * @returns {boolean} True if the comment is at parent end. + */ + function isCommentAtParentEnd(node, nodeType) { + var ancestors = context.getAncestors(); + var parent; + + if (ancestors.length) { + parent = ancestors.pop(); + } + + return parent && isCommentInsideNodeType(node, parent, nodeType) && + parent.loc.end.line - node.loc.end.line === 1; + } + + /** + * Returns whether or not comments are at the block start or not. + * @param {ASTNode} node The Comment node. + * @returns {boolean} True if the comment is at block start. + */ + function isCommentAtBlockStart(node) { + return isCommentAtParentStart(node, "ClassBody") || isCommentAtParentStart(node, "BlockStatement"); + } + + /** + * Returns whether or not comments are at the block end or not. + * @param {ASTNode} node The Comment node. + * @returns {boolean} True if the comment is at block end. + */ + function isCommentAtBlockEnd(node) { + return isCommentAtParentEnd(node, "ClassBody") || isCommentAtParentEnd(node, "BlockStatement"); + } + + /** + * Returns whether or not comments are at the object start or not. + * @param {ASTNode} node The Comment node. + * @returns {boolean} True if the comment is at object start. + */ + function isCommentAtObjectStart(node) { + return isCommentAtParentStart(node, "ObjectExpression") || isCommentAtParentStart(node, "ObjectPattern"); + } + + /** + * Returns whether or not comments are at the object end or not. + * @param {ASTNode} node The Comment node. + * @returns {boolean} True if the comment is at object end. + */ + function isCommentAtObjectEnd(node) { + return isCommentAtParentEnd(node, "ObjectExpression") || isCommentAtParentEnd(node, "ObjectPattern"); + } + + /** + * Returns whether or not comments are at the array start or not. + * @param {ASTNode} node The Comment node. + * @returns {boolean} True if the comment is at array start. + */ + function isCommentAtArrayStart(node) { + return isCommentAtParentStart(node, "ArrayExpression") || isCommentAtParentStart(node, "ArrayPattern"); + } + + /** + * Returns whether or not comments are at the array end or not. + * @param {ASTNode} node The Comment node. + * @returns {boolean} True if the comment is at array end. + */ + function isCommentAtArrayEnd(node) { + return isCommentAtParentEnd(node, "ArrayExpression") || isCommentAtParentEnd(node, "ArrayPattern"); + } + + /** + * Checks if a comment node has lines around it (ignores inline comments) + * @param {ASTNode} node The Comment node. + * @param {Object} opts Options to determine the newline. + * @param {Boolean} opts.after Should have a newline after this line. + * @param {Boolean} opts.before Should have a newline before this line. + * @returns {void} + */ + function checkForEmptyLine(node, opts) { + + var lines = context.getSourceLines(), + numLines = lines.length + 1, + comments = context.getAllComments(), + commentLines = getCommentLineNums(comments), + emptyLines = getEmptyLineNums(lines), + commentAndEmptyLines = commentLines.concat(emptyLines); + + var after = opts.after, + before = opts.before; + + var prevLineNum = node.loc.start.line - 1, + nextLineNum = node.loc.end.line + 1, + commentIsNotAlone = codeAroundComment(node); + + var blockStartAllowed = options.allowBlockStart && isCommentAtBlockStart(node), + blockEndAllowed = options.allowBlockEnd && isCommentAtBlockEnd(node), + objectStartAllowed = options.allowObjectStart && isCommentAtObjectStart(node), + objectEndAllowed = options.allowObjectEnd && isCommentAtObjectEnd(node), + arrayStartAllowed = options.allowArrayStart && isCommentAtArrayStart(node), + arrayEndAllowed = options.allowArrayEnd && isCommentAtArrayEnd(node); + + var exceptionStartAllowed = blockStartAllowed || objectStartAllowed || arrayStartAllowed; + var exceptionEndAllowed = blockEndAllowed || objectEndAllowed || arrayEndAllowed; + + // ignore top of the file and bottom of the file + if (prevLineNum < 1) { + before = false; + } + if (nextLineNum >= numLines) { + after = false; + } + + // we ignore all inline comments + if (commentIsNotAlone) { + return; + } + + // check for newline before + if (!exceptionStartAllowed && before && !contains(prevLineNum, commentAndEmptyLines)) { + context.report(node, "Expected line before comment."); + } + + // check for newline after + if (!exceptionEndAllowed && after && !contains(nextLineNum, commentAndEmptyLines)) { + context.report(node, "Expected line after comment."); + } + + } + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + return { + + "LineComment": function(node) { + if (options.beforeLineComment || options.afterLineComment) { + checkForEmptyLine(node, { + after: options.afterLineComment, + before: options.beforeLineComment + }); + } + }, + + "BlockComment": function(node) { + if (options.beforeBlockComment || options.afterBlockComment) { + checkForEmptyLine(node, { + after: options.afterBlockComment, + before: options.beforeBlockComment + }); + } + } + + }; }; -},{}],158:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "beforeBlockComment": { + "type": "boolean" + }, + "afterBlockComment": { + "type": "boolean" + }, + "beforeLineComment": { + "type": "boolean" + }, + "afterLineComment": { + "type": "boolean" + }, + "allowBlockStart": { + "type": "boolean" + }, + "allowBlockEnd": { + "type": "boolean" + }, + "allowObjectStart": { + "type": "boolean" + }, + "allowObjectEnd": { + "type": "boolean" + }, + "allowArrayStart": { + "type": "boolean" + }, + "allowArrayEnd": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{"object-assign":108}],158:[function(require,module,exports){ /** * @fileoverview A rule to set the maximum depth block can be nested in a function. * @author Ian Christian Myers * @copyright 2013 Ian Christian Myers. All rights reserved. */ @@ -20830,27 +28533,48 @@ //-------------------------------------------------------------------------- var functionStack = [], maxDepth = context.options[0] || 4; + /** + * When parsing a new function, store it in our function stack + * @returns {void} + * @private + */ function startFunction() { functionStack.push(0); } + /** + * When parsing is done then pop out the reference + * @returns {void} + * @private + */ function endFunction() { functionStack.pop(); } + /** + * Save the block and Evaluate the node + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function pushBlock(node) { var len = ++functionStack[functionStack.length - 1]; if (len > maxDepth) { context.report(node, "Blocks are nested too deeply ({{depth}}).", { depth: len }); } } + /** + * Pop the saved block + * @returns {void} + * @private + */ function popBlock() { functionStack[functionStack.length - 1]--; } //-------------------------------------------------------------------------- @@ -20893,10 +28617,16 @@ "Program:exit": endFunction }; }; +module.exports.schema = [ + { + "type": "integer" + } +]; + },{}],159:[function(require,module,exports){ /** * @fileoverview Rule to check for max length on a line. * @author Matt DuVall <http://www.mattduvall.com> * @copyright 2013 Matt DuVall. All rights reserved. @@ -20907,10 +28637,16 @@ //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + // takes some ideas from http://tools.ietf.org/html/rfc3986#appendix-B, however: + // - They're matching an entire string that we know is a URI + // - We're matching part of a string where we think there *might* be a URL + // - We're only concerned about URLs, as picking out any URI would cause too many false positives + // - We don't care about matching the entire URL, any small segment is fine + var URL_REGEXP = /[^:/?#]:\/\/[^?#]/; /** * Creates a string that is made up of repeating a given string a certain * number of times. This uses exponentiation of squares to achieve significant * performance gains over the more traditional implementation of such @@ -20928,27 +28664,95 @@ } } return result; } - var tabWidth = context.options[1]; - - var maxLength = context.options[0], + var maxLength = context.options[0] || 80, + tabWidth = context.options[1] || 4, + ignoreOptions = context.options[2] || {}, + ignorePattern = ignoreOptions.ignorePattern || null, + ignoreComments = ignoreOptions.ignoreComments || false, + ignoreUrls = ignoreOptions.ignoreUrls || false, tabString = stringRepeat(" ", tabWidth); + if (ignorePattern) { + ignorePattern = new RegExp(ignorePattern); + } + //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- + + /** + * Tells if a given comment is trailing: it starts on the current line and + * extends to or past the end of the current line. + * @param {string} line The source line we want to check for a trailing comment on + * @param {number} lineNumber The one-indexed line number for line + * @param {ASTNode} comment The comment to inspect + * @returns {boolean} If the comment is trailing on the given line + */ + function isTrailingComment(line, lineNumber, comment) { + return comment && + (comment.loc.start.line <= lineNumber && lineNumber <= comment.loc.end.line) && + (comment.loc.end.line > lineNumber || comment.loc.end.column === line.length); + } + + /** + * Gets the line after the comment and any remaining trailing whitespace is + * stripped. + * @param {string} line The source line with a trailing comment + * @param {number} lineNumber The one-indexed line number this is on + * @param {ASTNode} comment The comment to remove + * @returns {string} Line without comment and trailing whitepace + */ + function stripTrailingComment(line, lineNumber, comment) { + if (comment.loc.start.line < lineNumber) { + // this entire line is a comment + return ""; + } else { + // loc.column is zero-indexed + return line.slice(0, comment.loc.start.column).replace(/\s+$/, ""); + } + } + + /** + * Check the program for max length + * @param {ASTNode} node Node to examine + * @returns {void} + * @private + */ function checkProgramForMaxLength(node) { - var lines = context.getSourceLines(); + // split (honors line-ending) + var lines = context.getSourceLines(), + // list of comments to ignore + comments = ignoreComments ? context.getAllComments() : [], + // we iterate over comments in parallel with the lines + commentsIndex = 0; - // Replace the tabs - // Split (honors line-ending) - // Iterate lines.forEach(function(line, i) { + // i is zero-indexed, line numbers are one-indexed + var lineNumber = i + 1; + // we can short-circuit the comment checks if we're already out of comments to check + if (commentsIndex < comments.length) { + // iterate over comments until we find one past the current line + do { + var comment = comments[++commentsIndex]; + } while (comment && comment.loc.start.line <= lineNumber); + // and step back by one + comment = comments[--commentsIndex]; + if (isTrailingComment(line, lineNumber, comment)) { + line = stripTrailingComment(line, lineNumber, comment); + } + } + if (ignorePattern && ignorePattern.test(line) || + ignoreUrls && URL_REGEXP.test(line)) { + // ignore this line + return; + } + // replace the tabs if (line.replace(/\t/g, tabString).length > maxLength) { - context.report(node, { line: i + 1, col: 1 }, "Line " + (i + 1) + " exceeds the maximum line length of " + maxLength + "."); + context.report(node, { line: lineNumber, column: 0 }, "Line " + (i + 1) + " exceeds the maximum line length of " + maxLength + "."); } }); } @@ -20960,10 +28764,36 @@ "Program": checkProgramForMaxLength }; }; +module.exports.schema = [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "integer", + "minimum": 0 + }, + { + "type": "object", + "properties": { + "ignorePattern": { + "type": "string" + }, + "ignoreComments": { + "type": "boolean" + }, + "ignoreUrls": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + },{}],160:[function(require,module,exports){ /** * @fileoverview Rule to enforce a maximum number of nested callbacks. * @author Ian Christian Myers * @copyright 2013 Ian Christian Myers. All rights reserved. @@ -20979,11 +28809,11 @@ //-------------------------------------------------------------------------- // Constants //-------------------------------------------------------------------------- - var THRESHOLD = context.options[0]; + var THRESHOLD = context.options[0] || 10; //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- @@ -21029,10 +28859,16 @@ "FunctionExpression:exit": popStack }; }; +module.exports.schema = [ + { + "type": "integer" + } +]; + },{}],161:[function(require,module,exports){ /** * @fileoverview Rule to flag when a function has too many parameters * @author Ilya Volodin * @copyright 2014 Nicholas C. Zakas. All rights reserved. @@ -21070,10 +28906,16 @@ "FunctionExpression": checkFunction }; }; +module.exports.schema = [ + { + "type": "integer" + } +]; + },{}],162:[function(require,module,exports){ /** * @fileoverview A rule to set the maximum number of statements in a function. * @author Ian Christian Myers * @copyright 2013 Ian Christian Myers. All rights reserved. @@ -21092,23 +28934,40 @@ //-------------------------------------------------------------------------- var functionStack = [], maxStatements = context.options[0] || 10; + /** + * When parsing a new function, store it in our function stack + * @returns {void} + * @private + */ function startFunction() { functionStack.push(0); } + /** + * Evaluate the node at the end of function + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function endFunction(node) { var count = functionStack.pop(); if (count > maxStatements) { context.report(node, "This function has too many statements ({{count}}). Maximum allowed is {{max}}.", { count: count, max: maxStatements }); } } + /** + * Increment the count of the functions + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function countStatements(node) { functionStack[functionStack.length - 1] += node.body.length; } //-------------------------------------------------------------------------- @@ -21127,40 +28986,58 @@ "ArrowFunctionExpression:exit": endFunction }; }; +module.exports.schema = [ + { + "type": "integer" + } +]; + },{}],163:[function(require,module,exports){ /** * @fileoverview Rule to flag use of constructors without capital letters * @author Nicholas C. Zakas * @copyright 2014 Jordan Harband. All rights reserved. * @copyright 2013-2014 Nicholas C. Zakas. All rights reserved. */ "use strict"; +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var assign = require("object-assign"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + var CAPS_ALLOWED = [ - "Object", + "Array", + "Boolean", + "Date", + "Error", "Function", "Number", + "Object", + "RegExp", "String", - "Boolean", - "Date", - "Array", - "Symbol", - "RegExp" + "Symbol" ]; /** * Ensure that if the key is provided, it must be an array. * @param {Object} obj Object to check with `key`. * @param {string} key Object key to check on `obj`. * @param {*} fallback If obj[key] is not present, this will be returned. * @returns {string[]} Returns obj[key] if it's an Array, otherwise `fallback` */ function checkArray(obj, key, fallback) { + /* istanbul ignore if */ if (Object.prototype.hasOwnProperty.call(obj, key) && !Array.isArray(obj[key])) { throw new TypeError(key + ", if provided, must be an Array"); } return obj[key] || fallback; } @@ -21195,13 +29072,14 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var config = context.options[0] || {}; - config.newIsCap = config.newIsCap === false ? false : true; - config.capIsNew = config.capIsNew === false ? false : true; + var config = context.options[0] ? assign({}, context.options[0]) : {}; + config.newIsCap = config.newIsCap !== false; + config.capIsNew = config.capIsNew !== false; + var skipProperties = config.properties === false; var newIsCapExceptions = checkArray(config, "newIsCapExceptions", []).reduce(invert, {}); var capIsNewExceptions = calculateCapIsNewExceptions(config); @@ -21263,21 +29141,39 @@ * @param {ASTNode} node CallExpression node * @param {string} calleeName Capitalized callee name from a CallExpression * @returns {Boolean} Returns true if the callee may be capitalized */ function isCapAllowed(allowedMap, node, calleeName) { - if (allowedMap[calleeName]) { + if (allowedMap[calleeName] || allowedMap[context.getSource(node.callee)]) { return true; } + if (calleeName === "UTC" && node.callee.type === "MemberExpression") { // allow if callee is Date.UTC return node.callee.object.type === "Identifier" && - node.callee.object.name === "Date"; + node.callee.object.name === "Date"; } - return false; + + return skipProperties && node.callee.type === "MemberExpression"; } + /** + * Reports the given message for the given node. The location will be the start of the property or the callee. + * @param {ASTNode} node CallExpression or NewExpression node. + * @param {string} message The message to report. + * @returns {void} + */ + function report(node, message) { + var callee = node.callee; + + if (callee.type === "MemberExpression") { + callee = callee.property; + } + + context.report(node, callee.loc.start, message); + } + //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- if (config.newIsCap) { @@ -21286,11 +29182,11 @@ var constructorName = extractNameFromExpression(node); if (constructorName) { var capitalization = getCap(constructorName); var isAllowed = capitalization !== "lower" || isCapAllowed(newIsCapExceptions, node, constructorName); if (!isAllowed) { - context.report(node, "A constructor name should not start with a lowercase letter."); + report(node, "A constructor name should not start with a lowercase letter."); } } }; } @@ -21300,20 +29196,50 @@ var calleeName = extractNameFromExpression(node); if (calleeName) { var capitalization = getCap(calleeName); var isAllowed = capitalization !== "upper" || isCapAllowed(capIsNewExceptions, node, calleeName); if (!isAllowed) { - context.report(node, "A function with a name starting with an uppercase letter should only be used as a constructor."); + report(node, "A function with a name starting with an uppercase letter should only be used as a constructor."); } } }; } return listeners; }; -},{}],164:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "newIsCap": { + "type": "boolean" + }, + "capIsNew": { + "type": "boolean" + }, + "newIsCapExceptions": { + "type": "array", + "items": { + "type": "string" + } + }, + "capIsNewExceptions": { + "type": "array", + "items": { + "type": "string" + } + }, + "properties": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{"object-assign":108}],164:[function(require,module,exports){ /** * @fileoverview Rule to flag when using constructor without parentheses * @author Ilya Volodin */ @@ -21338,67 +29264,345 @@ } }; }; +module.exports.schema = []; + },{}],165:[function(require,module,exports){ /** + * @fileoverview Rule to check empty newline after "var" statement + * @author Gopal Venkatesan + * @copyright 2015 Gopal Venkatesan. All rights reserved. + * @copyright 2015 Casey Visco. All rights reserved. + * @copyright 2015 Ian VanSchooten. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + var ALWAYS_MESSAGE = "Expected blank line after variable declarations.", + NEVER_MESSAGE = "Unexpected blank line after variable declarations."; + + // Default `mode` to "always". This means that invalid options will also + // be treated as "always" and the only special case is "never" + var mode = context.options[0] === "never" ? "never" : "always"; + + // Cache starting and ending line numbers of comments for faster lookup + var commentEndLine = context.getAllComments().reduce(function(result, token) { + result[token.loc.start.line] = token.loc.end.line; + return result; + }, {}); + + + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + + /** + * Determine if provided keyword is a variable declaration + * @private + * @param {string} keyword - keyword to test + * @returns {boolean} True if `keyword` is a type of var + */ + function isVar(keyword) { + return keyword === "var" || keyword === "let" || keyword === "const"; + } + + /** + * Determine if provided keyword is a variant of for specifiers + * @private + * @param {string} keyword - keyword to test + * @returns {boolean} True if `keyword` is a variant of for specifier + */ + function isForTypeSpecifier(keyword) { + return keyword === "ForStatement" || keyword === "ForInStatement" || keyword === "ForOfStatement"; + } + + /** + * Determine if provided keyword is an export specifiers + * @private + * @param {string} nodeType - nodeType to test + * @returns {boolean} True if `nodeType` is an export specifier + */ + function isExportSpecifier(nodeType) { + return nodeType === "ExportNamedDeclaration" || nodeType === "ExportSpecifier" || + nodeType === "ExportDefaultDeclaration" || nodeType === "ExportAllDeclaration"; + } + + /** + * Determine if provided nodeType is a function specifier + * @private + * @param {string} nodeType - nodeType to test + * @returns {boolean} True if `nodeType` is a function specifier + */ + function isFunctionSpecifier(nodeType) { + return nodeType === "FunctionDeclaration" || nodeType === "FunctionExpression" || + nodeType === "ArrowFunctionExpression"; + } + + /** + * Determine if provided node is the last of his parent + * @private + * @param {ASTNode} node - node to test + * @returns {boolean} True if `node` is last of his parent + */ + function isLastNode(node) { + return node.parent.body[node.parent.body.length - 1] === node; + } + + /** + * Determine if a token starts more than one line after a comment ends + * @param {token} token The token being checked + * @param {integer} commentStartLine The line number on which the comment starts + * @returns {boolean} True if `token` does not start immediately after a comment + */ + function hasBlankLineAfterComment(token, commentStartLine) { + var commentEnd = commentEndLine[commentStartLine]; + // If there's another comment, repeat check for blank line + if (commentEndLine[commentEnd + 1]) { + return hasBlankLineAfterComment(token, commentEnd + 1); + } + return (token.loc.start.line > commentEndLine[commentStartLine] + 1); + } + + /** + * Checks that a blank line exists after a variable declaration when mode is + * set to "always", or checks that there is no blank line when mode is set + * to "never" + * @private + * @param {ASTNode} node - `VariableDeclaration` node to test + * @returns {void} + */ + function checkForBlankLine(node) { + var lastToken = context.getLastToken(node), + nextToken = context.getTokenAfter(node), + nextLineNum = lastToken.loc.end.line + 1, + noNextLineToken, + hasNextLineComment; + + // Ignore if there is no following statement + if (!nextToken) { + return; + } + + // Ignore if parent of node is a for variant + if (isForTypeSpecifier(node.parent.type)) { + return; + } + + // Ignore if parent of node is an export specifier + if (isExportSpecifier(node.parent.type)) { + return; + } + + // Some coding styles use multiple `var` statements, so do nothing if + // the next token is a `var` statement. + if (nextToken.type === "Keyword" && isVar(nextToken.value)) { + return; + } + + // Ignore if it is last statement in a function + if (node.parent.parent && isFunctionSpecifier(node.parent.parent.type) && isLastNode(node)) { + return; + } + + // Next statement is not a `var`... + noNextLineToken = nextToken.loc.start.line > nextLineNum; + hasNextLineComment = (typeof commentEndLine[nextLineNum] !== "undefined"); + + if (mode === "never" && noNextLineToken && !hasNextLineComment) { + context.report(node, NEVER_MESSAGE, { identifier: node.name }); + } + + // Token on the next line, or comment without blank line + if ( + mode === "always" && ( + !noNextLineToken || + hasNextLineComment && !hasBlankLineAfterComment(nextToken, nextLineNum) + ) + ) { + context.report(node, ALWAYS_MESSAGE, { identifier: node.name }); + } + } + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + return { + "VariableDeclaration": checkForBlankLine + }; + +}; + +module.exports.schema = [ + { + "enum": ["never", "always"] + } +]; + +},{}],166:[function(require,module,exports){ +/** * @fileoverview Rule to flag use of alert, confirm, prompt * @author Nicholas C. Zakas + * @copyright 2015 Mathias Schreck + * @copyright 2013 Nicholas C. Zakas */ "use strict"; //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ -function matchProhibited(name) { - return name.match(/^(alert|confirm|prompt)$/); +/** + * Checks if the given name is a prohibited identifier. + * @param {string} name The name to check + * @returns {boolean} Whether or not the name is prohibited. + */ +function isProhibitedIdentifier(name) { + return /^(alert|confirm|prompt)$/.test(name); } -function report(context, node, result) { - context.report(node, "Unexpected {{name}}.", { name: result[1] }); +/** + * Reports the given node and identifier name. + * @param {RuleContext} context The ESLint rule context. + * @param {ASTNode} node The node to report on. + * @param {string} identifierName The name of the identifier. + * @returns {void} + */ +function report(context, node, identifierName) { + context.report(node, "Unexpected {{name}}.", { name: identifierName }); } +/** + * Returns the property name of a MemberExpression. + * @param {ASTNode} memberExpressionNode The MemberExpression node. + * @returns {string|undefined} Returns the property name if available, undefined else. + */ +function getPropertyName(memberExpressionNode) { + if (memberExpressionNode.computed) { + if (memberExpressionNode.property.type === "Literal") { + return memberExpressionNode.property.value; + } + } else { + return memberExpressionNode.property.name; + } +} +/** + * Finds the escope reference in the given scope. + * @param {Object} scope The scope to search. + * @param {ASTNode} node The identifier node. + * @returns {Reference|undefined} Returns the found reference or undefined if none were found. + */ +function findReference(scope, node) { + var references = scope.references.filter(function(reference) { + return reference.identifier.range[0] === node.range[0] && + reference.identifier.range[1] === node.range[1]; + }); + + if (references.length === 1) { + return references[0]; + } +} + +/** + * Checks if the given identifier name is shadowed in the given global scope. + * @param {Object} globalScope The global scope. + * @param {string} identifierName The identifier name to check + * @returns {boolean} Whether or not the name is shadowed globally. + */ +function isGloballyShadowed(globalScope, identifierName) { + var variable = globalScope.set.get(identifierName); + return Boolean(variable && variable.defs.length > 0); +} + +/** + * Checks if the given identifier node is shadowed in the given scope. + * @param {Object} scope The current scope. + * @param {Object} globalScope The global scope. + * @param {string} node The identifier node to check + * @returns {boolean} Whether or not the name is shadowed. + */ +function isShadowed(scope, globalScope, node) { + var reference = findReference(scope, node), + identifierName = node.name; + + if (reference) { + if (reference.resolved || isGloballyShadowed(globalScope, identifierName)) { + return true; + } + } + + return false; +} + +/** + * Checks if the given identifier node is a ThisExpression in the global scope or the global window property. + * @param {Object} scope The current scope. + * @param {Object} globalScope The global scope. + * @param {string} node The identifier node to check + * @returns {boolean} Whether or not the node is a reference to the global object. + */ +function isGlobalThisReferenceOrGlobalWindow(scope, globalScope, node) { + if (scope.type === "global" && node.type === "ThisExpression") { + return true; + } else if (node.name === "window") { + return !isShadowed(scope, globalScope, node); + } + + return false; +} + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var globalScope; return { + "Program": function() { + globalScope = context.getScope(); + }, + "CallExpression": function(node) { + var callee = node.callee, + identifierName, + currentScope = context.getScope(); - var result; - // without window. - if (node.callee.type === "Identifier") { + if (callee.type === "Identifier") { + identifierName = callee.name; - result = matchProhibited(node.callee.name); - - if (result) { - report(context, node, result); + if (!isShadowed(currentScope, globalScope, callee) && isProhibitedIdentifier(callee.name)) { + report(context, node, identifierName); } - } else if (node.callee.type === "MemberExpression" && node.callee.property.type === "Identifier") { + } else if (callee.type === "MemberExpression" && isGlobalThisReferenceOrGlobalWindow(currentScope, globalScope, callee.object)) { + identifierName = getPropertyName(callee); - result = matchProhibited(node.callee.property.name); - - if (result && node.callee.object.name === "window") { - report(context, node, result); + if (isProhibitedIdentifier(identifierName)) { + report(context, node, identifierName); } - } } }; }; -},{}],166:[function(require,module,exports){ +module.exports.schema = []; + +},{}],167:[function(require,module,exports){ /** * @fileoverview Disallow construction of dense arrays using the Array constructor * @author Matt DuVall <http://www.mattduvall.com/> */ @@ -21408,10 +29612,16 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + /** + * Disallow construction of dense arrays using the Array constructor + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function check(node) { if ( node.arguments.length !== 1 && node.callee.type === "Identifier" && node.callee.name === "Array" @@ -21425,12 +29635,104 @@ "NewExpression": check }; }; -},{}],167:[function(require,module,exports){ +module.exports.schema = []; + +},{}],168:[function(require,module,exports){ /** + * @fileoverview A rule to warn against using arrow functions in conditions. + * @author Jxck <https://github.com/Jxck> + * @copyright 2015 Luke Karrys. All rights reserved. + * The MIT License (MIT) + + * Copyright (c) 2015 Jxck + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Checks whether or not a node is an arrow function expression. + * @param {ASTNode} node - node to test + * @returns {boolean} `true` if the node is an arrow function expression. + */ +function isArrowFunction(node) { + return node.test && node.test.type === "ArrowFunctionExpression"; +} + +/** + * Checks whether or not a node is a conditional expression. + * @param {ASTNode} node - node to test + * @returns {boolean} `true` if the node is a conditional expression. + */ +function isConditional(node) { + return node.body && node.body.type === "ConditionalExpression"; +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + /** + * Reports if a conditional statement is an arrow function. + * @param {ASTNode} node - A node to check and report. + * @returns {void} + */ + function checkCondition(node) { + if (isArrowFunction(node)) { + context.report(node, "Arrow function `=>` used inside {{statementType}} instead of comparison operator.", {statementType: node.type}); + } + } + + /** + * Reports if an arrow function contains an ambiguous conditional. + * @param {ASTNode} node - A node to check and report. + * @returns {void} + */ + function checkArrowFunc(node) { + if (isConditional(node)) { + context.report(node, "Arrow function used ambiguously with a conditional expression."); + } + } + + return { + "IfStatement": checkCondition, + "WhileStatement": checkCondition, + "ForStatement": checkCondition, + "ConditionalExpression": checkCondition, + "ArrowFunctionExpression": checkArrowFunc + }; +}; + +module.exports.schema = []; + +},{}],169:[function(require,module,exports){ +/** * @fileoverview Rule to flag bitwise identifiers * @author Nicholas C. Zakas */ "use strict"; @@ -21482,11 +29784,13 @@ "UnaryExpression": checkNodeForBitwiseOperator }; }; -},{}],168:[function(require,module,exports){ +module.exports.schema = []; + +},{}],170:[function(require,module,exports){ /** * @fileoverview Rule to flag use of arguments.callee and arguments.caller. * @author Nicholas C. Zakas */ @@ -21511,42 +29815,93 @@ } }; }; -},{}],169:[function(require,module,exports){ +module.exports.schema = []; + +},{}],171:[function(require,module,exports){ /** + * @fileoverview Rule to flag use of an lexical declarations inside a case clause + * @author Erik Arvidsson + * @copyright 2015 Erik Arvidsson. All rights reserved. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + /** + * Checks whether or not a node is a lexical declaration. + * @param {ASTNode} node A direct child statement of a switch case. + * @returns {boolean} Whether or not the node is a lexical declaration. + */ + function isLexicalDeclaration(node) { + switch (node.type) { + case "FunctionDeclaration": + case "ClassDeclaration": + return true; + case "VariableDeclaration": + return node.kind !== "var"; + default: + return false; + } + } + + return { + "SwitchCase": function(node) { + for (var i = 0; i < node.consequent.length; i++) { + var statement = node.consequent[i]; + if (isLexicalDeclaration(statement)) { + context.report({ + node: node, + message: "Unexpected lexical declaration in case block." + }); + } + } + } + }; + +}; + +module.exports.schema = []; + +},{}],172:[function(require,module,exports){ +/** * @fileoverview Rule to flag variable leak in CatchClauses in IE 8 and earlier * @author Ian Christian Myers */ "use strict"; //------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- + /** + * Check if the parameters are been shadowed + * @param {object} scope current scope + * @param {string} name parameter name + * @returns {boolean} True is its been shadowed + */ function paramIsShadowing(scope, name) { - var found = scope.variables.some(function(variable) { - return variable.name === name; - }); - - if (found) { - return true; - } - - if (scope.upper) { - return paramIsShadowing(scope.upper, name); - } - - return false; + return astUtils.getVariableByName(scope, name) !== null; } //-------------------------------------------------------------------------- // Public API //-------------------------------------------------------------------------- @@ -21554,65 +29909,78 @@ return { "CatchClause": function(node) { var scope = context.getScope(); + // When blockBindings is enabled, CatchClause creates its own scope + // so start from one upper scope to exclude the current node + if (scope.block === node) { + scope = scope.upper; + } + if (paramIsShadowing(scope, node.param.name)) { context.report(node, "Value of '{{name}}' may be overwritten in IE 8 and earlier.", { name: node.param.name }); } } }; }; -},{}],170:[function(require,module,exports){ +module.exports.schema = []; + +},{"../ast-utils":113}],173:[function(require,module,exports){ /** - * @fileoverview Rule to flag trailing commas in object literals. - * @author Ian Christian Myers + * @fileoverview A rule to disallow modifying variables of class declarations + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. */ "use strict"; +var astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - //------------------------------------------------------------------------- - // Helpers - //------------------------------------------------------------------------- + /** + * Finds and reports references that are non initializer and writable. + * @param {Variable} variable - A variable to check. + * @returns {void} + */ + function checkVariable(variable) { + astUtils.getModifyingReferences(variable.references).forEach(function(reference) { + context.report( + reference.identifier, + "`{{name}}` is a class.", + {name: reference.identifier.name}); - function checkForTrailingComma(node) { - var items = node.properties || node.elements, - length = items.length, - lastItem, penultimateToken; + }); + } - if (length) { - lastItem = items[length - 1]; - if (lastItem) { - penultimateToken = context.getLastToken(node, 1); - if (penultimateToken.value === ",") { - context.report(lastItem, penultimateToken.loc.start, "Trailing comma."); - } - } - } + /** + * Finds and reports references that are non initializer and writable. + * @param {ASTNode} node - A ClassDeclaration/ClassExpression node to check. + * @returns {void} + */ + function checkForClass(node) { + context.getDeclaredVariables(node).forEach(checkVariable); } - //-------------------------------------------------------------------------- - // Public API - //-------------------------------------------------------------------------- - return { - "ObjectExpression": checkForTrailingComma, - "ArrayExpression": checkForTrailingComma + "ClassDeclaration": checkForClass, + "ClassExpression": checkForClass }; }; -},{}],171:[function(require,module,exports){ +module.exports.schema = []; + +},{"../ast-utils":113}],174:[function(require,module,exports){ /** * @fileoverview Rule to flag assignment in a conditional statement's test expression * @author Stephen Murray <spmurrayzzz> */ "use strict"; @@ -21649,15 +30017,15 @@ * @returns {?Object} The closest ancestor node that represents a conditional statement. */ function findConditionalAncestor(node) { var currentAncestor = node; - while ((currentAncestor = currentAncestor.parent)) { + do { if (isConditionalTestExpression(currentAncestor)) { return currentAncestor.parent; } - } + } while ((currentAncestor = currentAncestor.parent)); return null; } /** @@ -21691,13 +30059,23 @@ * Check a conditional statement's test expression for top-level assignments that are not enclosed in parentheses. * @param {!Object} node The node for the conditional statement. * @returns {void} */ function testForAssign(node) { - if (node.test && (node.test.type === "AssignmentExpression") && !isParenthesisedTwice(node.test)) { + if (node.test && + (node.test.type === "AssignmentExpression") && + (node.type === "ForStatement" ? + !isParenthesised(node.test) : + !isParenthesisedTwice(node.test) + ) + ) { // must match JSHint's error message - context.report(node, "Expected a conditional expression and instead saw an assignment."); + context.report({ + node: node, + loc: node.test.loc.start, + message: "Expected a conditional expression and instead saw an assignment." + }); } } /** * Check whether an assignment expression is descended from a conditional statement's test expression. @@ -21727,11 +30105,17 @@ "WhileStatement": testForAssign }; }; -},{}],172:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["except-parens", "always"] + } +]; + +},{}],175:[function(require,module,exports){ /** * @fileoverview Rule to flag use of console object * @author Nicholas C. Zakas */ @@ -21754,12 +30138,57 @@ } }; }; -},{}],173:[function(require,module,exports){ +module.exports.schema = []; + +},{}],176:[function(require,module,exports){ /** + * @fileoverview A rule to disallow modifying variables that are declared using `const` + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + */ + +"use strict"; + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + /** + * Finds and reports references that are non initializer and writable. + * @param {Variable} variable - A variable to check. + * @returns {void} + */ + function checkVariable(variable) { + astUtils.getModifyingReferences(variable.references).forEach(function(reference) { + context.report( + reference.identifier, + "`{{name}}` is constant.", + {name: reference.identifier.name}); + }); + } + + return { + "VariableDeclaration": function(node) { + if (node.kind === "const") { + context.getDeclaredVariables(node).forEach(checkVariable); + } + } + }; + +}; + +module.exports.schema = []; + +},{"../ast-utils":113}],177:[function(require,module,exports){ +/** * @fileoverview Rule to flag use constant conditions * @author Christian Schulz <http://rndm.de> * @copyright 2014 Christian Schulz. All rights reserved. */ @@ -21793,11 +30222,11 @@ return isConstant(node.argument); case "BinaryExpression": case "LogicalExpression": return isConstant(node.left) && isConstant(node.right); case "AssignmentExpression": - return isConstant(node.right); + return (node.operator === "=") && isConstant(node.right); case "SequenceExpression": return isConstant(node.expressions[node.expressions.length - 1]); // no default } return false; @@ -21827,12 +30256,39 @@ "ForStatement": checkConstantCondition }; }; -},{}],174:[function(require,module,exports){ +module.exports.schema = []; + +},{}],178:[function(require,module,exports){ /** + * @fileoverview Rule to flag use of continue statement + * @author Borislav Zhivkov + * @copyright 2015 Borislav Zhivkov. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + return { + "ContinueStatement": function(node) { + context.report(node, "Unexpected use of continue statement"); + } + }; + +}; + +module.exports.schema = []; + +},{}],179:[function(require,module,exports){ +/** * @fileoverview Rule to forbid control charactes from regular expressions. * @author Nicholas C. Zakas */ "use strict"; @@ -21841,10 +30297,16 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + /** + * Get the regex expression + * @param {ASTNode} node node to evaluate + * @returns {*} Regex if found else null + * @private + */ function getRegExp(node) { if (node.value instanceof RegExp) { return node.value; } else if (typeof node.value === "string") { @@ -21885,11 +30347,13 @@ } }; }; -},{}],175:[function(require,module,exports){ +module.exports.schema = []; + +},{}],180:[function(require,module,exports){ /** * @fileoverview Rule to flag use of a debugger statement * @author Nicholas C. Zakas */ @@ -21907,11 +30371,13 @@ } }; }; -},{}],176:[function(require,module,exports){ +module.exports.schema = []; + +},{}],181:[function(require,module,exports){ /** * @fileoverview Rule to flag when deleting variables * @author Ilya Volodin */ @@ -21932,11 +30398,13 @@ } }; }; -},{}],177:[function(require,module,exports){ +module.exports.schema = []; + +},{}],182:[function(require,module,exports){ /** * @fileoverview Rule to check for ambiguous div operator in regexes * @author Matt DuVall <http://www.mattduvall.com> */ @@ -21959,15 +30427,19 @@ } }; }; -},{}],178:[function(require,module,exports){ +module.exports.schema = []; + +},{}],183:[function(require,module,exports){ /** * @fileoverview Rule to flag duplicate arguments * @author Jamund Ferguson * @copyright 2015 Jamund Ferguson. All rights reserved. + * @copyright 2015 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. */ "use strict"; //------------------------------------------------------------------------------ @@ -21979,32 +30451,48 @@ //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- /** + * Checks whether or not a given definition is a parameter's. + * @param {escope.DefEntry} def - A definition to check. + * @returns {boolean} `true` if the definition is a parameter's. + */ + function isParameter(def) { + return def.type === "Parameter"; + } + + /** * Determines if a given node has duplicate parameters. * @param {ASTNode} node The node to check. * @returns {void} * @private */ function checkParams(node) { - var dups = {}; + var variables = context.getDeclaredVariables(node); + var keyMap = Object.create(null); - // loop through and find each duplicate param - node.params.map(function(param) { - return param.name; - }).forEach(function(param, i, params) { - var lastPos = params.lastIndexOf(param); - if (i !== lastPos) { - dups[param] = [i, lastPos]; + for (var i = 0; i < variables.length; ++i) { + var variable = variables[i]; + + // TODO(nagashima): Remove this duplication check after https://github.com/estools/escope/pull/79 + var key = "$" + variable.name; // to avoid __proto__. + if (!isParameter(variable.defs[0]) || keyMap[key]) { + continue; } - }); + keyMap[key] = true; - // log an error for each duplicate (not 2 for each) - Object.keys(dups).forEach(function(currentParam) { - context.report(node, "Duplicate param '{{key}}'.", { key: currentParam }); - }); + // Checks and reports duplications. + var defs = variable.defs.filter(isParameter); + if (defs.length >= 2) { + context.report({ + node: node, + message: "Duplicate param '{{name}}'.", + data: {name: variable.name} + }); + } + } } //-------------------------------------------------------------------------- // Public API //-------------------------------------------------------------------------- @@ -22014,12 +30502,98 @@ "FunctionExpression": checkParams }; }; -},{}],179:[function(require,module,exports){ +module.exports.schema = []; + +},{}],184:[function(require,module,exports){ /** + * @fileoverview A rule to disallow duplicate name in class members. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var stack = []; + + /** + * Gets state of a given member name. + * @param {string} name - A name of a member. + * @param {boolean} isStatic - A flag which specifies that is a static member. + * @returns {object} A state of a given member name. + * - retv.init {boolean} A flag which shows the name is declared as normal member. + * - retv.get {boolean} A flag which shows the name is declared as getter. + * - retv.set {boolean} A flag which shows the name is declared as setter. + */ + function getState(name, isStatic) { + var stateMap = stack[stack.length - 1]; + var key = "$" + name; // to avoid "__proto__". + + if (!stateMap[key]) { + stateMap[key] = { + nonStatic: {init: false, get: false, set: false}, + static: {init: false, get: false, set: false} + }; + } + + return stateMap[key][isStatic ? "static" : "nonStatic"]; + } + + return { + // Initializes the stack of state of member declarations. + "Program": function() { + stack = []; + }, + + // Initializes state of member declarations for the class. + "ClassBody": function() { + stack.push(Object.create(null)); + }, + + // Disposes the state for the class. + "ClassBody:exit": function() { + stack.pop(); + }, + + // Reports the node if its name has been declared already. + "MethodDefinition": function(node) { + if (node.computed) { + return; + } + + var name = node.key.name; + var state = getState(name, node.static); + var isDuplicate = false; + if (node.kind === "get") { + isDuplicate = (state.init || state.get); + state.get = true; + } else if (node.kind === "set") { + isDuplicate = (state.init || state.set); + state.set = true; + } else { + isDuplicate = (state.init || state.get || state.set); + state.init = true; + } + + if (isDuplicate) { + context.report(node, "Duplicate name \"{{name}}\".", {name: name}); + } + } + }; +}; + +module.exports.schema = []; + +},{}],185:[function(require,module,exports){ +/** * @fileoverview Rule to flag use of duplicate keys in an object. * @author Ian Christian Myers * @copyright 2013 Ian Christian Myers. All rights reserved. * @copyright 2013 Nicholas C. Zakas. All rights reserved. */ @@ -22039,17 +30613,22 @@ // Object that will be a map of properties--safe because we will // prefix all of the keys. var nodeProps = Object.create(null); node.properties.forEach(function(property) { + + if (property.type !== "Property") { + return; + } + var keyName = property.key.name || property.key.value, key = property.kind + "-" + keyName, checkProperty = (!property.computed || property.key.type === "Literal"); if (checkProperty) { if (nodeProps[key]) { - context.report(node, "Duplicate key '{{key}}'.", { key: keyName }); + context.report(node, property.loc.start, "Duplicate key '{{key}}'.", { key: keyName }); } else { nodeProps[key] = true; } } }); @@ -22057,12 +30636,49 @@ } }; }; -},{}],180:[function(require,module,exports){ +module.exports.schema = []; + +},{}],186:[function(require,module,exports){ /** + * @fileoverview Rule to disallow a duplicate case label. + * @author Dieter Oberkofler + * @author Burak Yigit Kaya + * @copyright 2015 Dieter Oberkofler. All rights reserved. + * @copyright 2015 Burak Yigit Kaya. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + return { + "SwitchStatement": function(node) { + var mapping = {}; + + node.cases.forEach(function(switchCase) { + var key = context.getSource(switchCase.test); + if (mapping[key]) { + context.report(switchCase, "Duplicate case label."); + } else { + mapping[key] = switchCase; + } + }); + } + }; +}; + +module.exports.schema = []; + +},{}],187:[function(require,module,exports){ +/** * @fileoverview Rule to flag `else` after a `return` in `if` * @author Ian Christian Myers */ "use strict"; @@ -22140,53 +30756,74 @@ } /** * Check the consequent/body node to make sure it is not * a ReturnStatement or an IfStatement that returns on both - * code paths. If it is, display the context report. + * code paths. * * @param {Node} node The consequent or body node * @param {Node} alternate The alternate node - * @returns {void} + * @returns {boolean} `true` if it is a Return/If node that always returns. */ - function checkForReturnOrIf(node, alternate) { - if (checkForReturn(node) || checkForIf(node)) { - displayReport(alternate); + function checkForReturnOrIf(node) { + return checkForReturn(node) || checkForIf(node); + } + + + /** + * Check whether a node returns in every codepath. + * @param {Node} node The node to be checked + * @returns {boolean} `true` if it returns on every codepath. + */ + function alwaysReturns(node) { + // If we have a BlockStatement, check each consequent body node. + if (node.type === "BlockStatement") { + return node.body.some(checkForReturnOrIf); + // If not a block statement, make sure the consequent isn't a ReturnStatement + // or an IfStatement with returns on both paths + } else { + return checkForReturnOrIf(node); } } //-------------------------------------------------------------------------- // Public API //-------------------------------------------------------------------------- return { - "IfStatement": function (node) { - // Don't bother finding a ReturnStatement, if there's no `else` - // or if the alternate is also an if (indicating an else if). - if (hasElse(node)) { - var consequent = node.consequent, - alternate = node.alternate; - // If we have a BlockStatement, check each consequent body node. - if (consequent.type === "BlockStatement") { - var body = consequent.body; - body.forEach(function (bodyNode) { - checkForReturnOrIf(bodyNode, alternate); - }); - // If not a block statement, make sure the consequent isn't a ReturnStatement - // or an IfStatement with returns on both paths - } else { - checkForReturnOrIf(consequent, alternate); + "IfStatement": function(node) { + var parent = context.getAncestors().pop(), + consequents, + alternate; + + // Only "top-level" if statements are checked, meaning the first `if` + // in a `if-else-if-...` chain. + if (parent.type === "IfStatement" && parent.alternate === node) { + return; + } + + for (consequents = []; node.type === "IfStatement"; node = node.alternate) { + if (!node.alternate) { + return; } + consequents.push(node.consequent); + alternate = node.alternate; } + + if (consequents.every(alwaysReturns)) { + displayReport(alternate); + } } }; }; -},{}],181:[function(require,module,exports){ +module.exports.schema = []; + +},{}],188:[function(require,module,exports){ /** * @fileoverview Rule to flag the use of empty character classes in regular expressions * @author Ian Christian Myers */ @@ -22203,14 +30840,14 @@ 2. `([^\\[]|\\.|\[([^\\\]]|\\.)+\])*`: regexp contents; 0 or more of the following 2.0. `[^\\[]`: any character that's not a `\` or a `[` (anything but escape sequences and character classes) 2.1. `\\.`: an escape sequence 2.2. `\[([^\\\]]|\\.)+\]`: a character class that isn't empty 3. `\/` the `/` that ends the regexp -4. `[gimy]*`: optional regexp flags +4. `[gimuy]*`: optional regexp flags 5. `$`: fix the match at the end of the string */ -var regex = /^\/([^\\[]|\\.|\[([^\\\]]|\\.)+\])*\/[gimy]*$/; +var regex = /^\/([^\\[]|\\.|\[([^\\\]]|\\.)+\])*\/[gimuy]*$/; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -22227,11 +30864,13 @@ }; }; -},{}],182:[function(require,module,exports){ +module.exports.schema = []; + +},{}],189:[function(require,module,exports){ /** * @fileoverview Rule to flag when label is not used for a loop or switch * @author Ilya Volodin */ @@ -22247,22 +30886,55 @@ "LabeledStatement": function(node) { var type = node.body.type; if (type !== "ForStatement" && type !== "WhileStatement" && type !== "DoWhileStatement" && type !== "SwitchStatement" && type !== "ForInStatement" && type !== "ForOfStatement") { - context.report(node, "Unexpected label {{l}}", {l: node.label.name}); + context.report(node, "Unexpected label \"{{l}}\"", {l: node.label.name}); } } }; }; -},{}],183:[function(require,module,exports){ +module.exports.schema = []; + +},{}],190:[function(require,module,exports){ /** + * @fileoverview Rule to disallow an empty pattern + * @author Alberto Rodríguez + * @copyright 2015 Alberto Rodríguez. All rights reserved. + * See LICENSE file in root directory for full license. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + return { + "ObjectPattern": function(node) { + if (node.properties.length === 0) { + context.report(node, "Unexpected empty object pattern."); + } + }, + "ArrayPattern": function(node) { + if (node.elements.length === 0) { + context.report(node, "Unexpected empty array pattern."); + } + } + }; +}; + +module.exports.schema = []; + +},{}],191:[function(require,module,exports){ +/** * @fileoverview Rule to flag use of an empty block statement * @author Nicholas C. Zakas * @copyright Nicholas C. Zakas. All rights reserved. + * @copyright 2015 Dieter Oberkofler. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition @@ -22271,24 +30943,29 @@ module.exports = function(context) { return { "BlockStatement": function(node) { - var ancestors = context.getAncestors(), - parent = ancestors[ancestors.length - 1], - parentType = parent.type, - hasHandler = !!(parent.handler || (parent.handlers && parent.handlers.length)), - isFinallyBlock = (parentType === "TryStatement") && (parent.finalizer === node); + var parent = node.parent, + parentType = parent.type; - if (/Function|CatchClause/.test(parentType) || - (isFinallyBlock && !hasHandler)) { + // if the body is not empty, we can just return immediately + if (node.body.length !== 0) { return; } - if (node.body.length === 0) { - context.report(node, "Empty block statement."); + // a function is generally allowed to be empty + if (parentType === "FunctionDeclaration" || parentType === "FunctionExpression" || parentType === "ArrowFunctionExpression") { + return; } + + // any other block is only allowed to be empty, if it contains a comment + if (context.getComments(node).trailing.length > 0) { + return; + } + + context.report(node, "Empty block statement."); }, "SwitchStatement": function(node) { if (typeof node.cases === "undefined" || node.cases.length === 0) { @@ -22297,11 +30974,13 @@ } }; }; -},{}],184:[function(require,module,exports){ +module.exports.schema = []; + +},{}],192:[function(require,module,exports){ /** * @fileoverview Rule to flag comparisons to null without a type-checking * operator. * @author Ian Christian Myers */ @@ -22326,11 +31005,13 @@ } }; }; -},{}],185:[function(require,module,exports){ +module.exports.schema = []; + +},{}],193:[function(require,module,exports){ /** * @fileoverview Rule to flag use of eval() statement * @author Nicholas C. Zakas * @copyright 2015 Mathias Schreck. All rights reserved. * @copyright 2013 Nicholas C. Zakas. All rights reserved. @@ -22352,54 +31033,52 @@ } }; }; -},{}],186:[function(require,module,exports){ +module.exports.schema = []; + +},{}],194:[function(require,module,exports){ /** * @fileoverview Rule to flag assignment of the exception parameter * @author Stephen Murray <spmurrayzzz> */ "use strict"; +var astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var inCatch = false, - exceptionName = null; + /** + * Finds and reports references that are non initializer and writable. + * @param {Variable} variable - A variable to check. + * @returns {void} + */ + function checkVariable(variable) { + astUtils.getModifyingReferences(variable.references).forEach(function(reference) { + context.report( + reference.identifier, + "Do not assign to the exception parameter."); + }); + } return { - "CatchClause": function(node) { - inCatch = true; - exceptionName = node.param.name; - }, - - "CatchClause:exit": function() { - inCatch = false; - exceptionName = null; - }, - - "AssignmentExpression": function(node) { - - if (inCatch) { - - if (node.left.name === exceptionName) { - context.report(node, "Do not assign to the exception parameter."); - } - } + context.getDeclaredVariables(node).forEach(checkVariable); } - }; }; -},{}],187:[function(require,module,exports){ +module.exports.schema = []; + +},{"../ast-utils":113}],195:[function(require,module,exports){ /** * @fileoverview Rule to flag adding properties to native object's prototypes. * @author David Nelson */ @@ -22407,22 +31086,30 @@ //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -var BUILTINS = [ - "Object", "Function", "Array", "String", "Boolean", "Number", "Date", - "RegExp", "Error", "EvalError", "RangeError", "ReferenceError", - "SyntaxError", "TypeError", "URIError" -]; +var globals = require("globals"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var config = context.options[0] || {}; + var exceptions = config.exceptions || []; + var modifiedBuiltins = Object.keys(globals.builtin).filter(function(builtin) { + return builtin[0].toUpperCase() === builtin[0]; + }); + + if (exceptions.length) { + modifiedBuiltins = modifiedBuiltins.filter(function(builtIn) { + return exceptions.indexOf(builtIn) === -1; + }); + } + return { // handle the Array.prototype.extra style case "AssignmentExpression": function(node) { var lhs = node.left, affectsProto; @@ -22437,36 +31124,35 @@ if (!affectsProto) { return; } - BUILTINS.forEach(function(builtin) { + modifiedBuiltins.forEach(function(builtin) { if (lhs.object.object.name === builtin) { context.report(node, builtin + " prototype is read only, properties should not be added."); } }); }, - // handle the Object.defineProperty(Array.prototype) case + // handle the Object.definePropert[y|ies](Array.prototype) case "CallExpression": function(node) { var callee = node.callee, subject, object; - // only worry about Object.defineProperty + // only worry about Object.definePropert[y|ies] if (callee.type === "MemberExpression" && callee.object.name === "Object" && - callee.property.name === "defineProperty") { + (callee.property.name === "defineProperty" || callee.property.name === "defineProperties")) { // verify the object being added to is a native prototype subject = node.arguments[0]; - object = subject.object; - + object = subject && subject.object; if (object && object.type === "Identifier" && - (BUILTINS.indexOf(object.name) > -1) && + (modifiedBuiltins.indexOf(object.name) > -1) && subject.property.name === "prototype") { context.report(node, object.name + " prototype is read only, properties should not be added."); } } @@ -22474,15 +31160,32 @@ } }; }; -},{}],188:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "exceptions": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + } + }, + "additionalProperties": false + } +]; + +},{"globals":100}],196:[function(require,module,exports){ /** * @fileoverview Rule to flag unnecessary bind calls * @author Bence Dányi <bence@danyi.me> * @copyright 2014 Bence Dányi. All rights reserved. + * See LICENSE in root directory for full license. */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition @@ -22533,12 +31236,14 @@ found: 0 }); } }, "CallExpression:exit": function(node) { - var top = getTopScope(); - if (top.call === node && top.found === 0) { + var top = getTopScope(), + isArrowFunction = node.callee.type === "MemberExpression" && node.callee.object.type === "ArrowFunctionExpression"; + + if (top.call === node && (top.found === 0 || isArrowFunction)) { context.report(node, "The function binding is unnecessary."); scope.pop(); } }, "ArrowFunctionExpression": incrementScopeDepth, @@ -22555,11 +31260,13 @@ } }; }; -},{}],189:[function(require,module,exports){ +module.exports.schema = []; + +},{}],197:[function(require,module,exports){ /** * @fileoverview Rule to flag unnecessary double negation in Boolean contexts * @author Brandon Mills */ @@ -22570,11 +31277,11 @@ //------------------------------------------------------------------------------ module.exports = function(context) { return { - "UnaryExpression": function (node) { + "UnaryExpression": function(node) { var ancestors = context.getAncestors(), parent = ancestors.pop(), grandparent = ancestors.pop(); // Exit early if it's guaranteed not to match @@ -22626,49 +31333,166 @@ } }; }; -},{}],190:[function(require,module,exports){ +module.exports.schema = []; + +},{}],198:[function(require,module,exports){ /** - * @fileoverview Disallow parenthesesisng higher precedence subexpressions. + * @fileoverview Disallow parenthesising higher precedence subexpressions. * @author Michael Ficarra * @copyright 2014 Michael Ficarra. All rights reserved. + * See LICENSE file in root directory for full license. */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var ALL_NODES = context.options[0] !== "functions"; + + /** + * Determines if this rule should be enforced for a node given the current configuration. + * @param {ASTNode} node - The node to be checked. + * @returns {boolean} True if the rule should be enforced for this node. + * @private + */ + function ruleApplies(node) { + return ALL_NODES || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression"; + } + + /** + * Determines if a node is surrounded by parentheses. + * @param {ASTNode} node - The node to be checked. + * @returns {boolean} True if the node is parenthesised. + * @private + */ function isParenthesised(node) { var previousToken = context.getTokenBefore(node), nextToken = context.getTokenAfter(node); return previousToken && nextToken && previousToken.value === "(" && previousToken.range[1] <= node.range[0] && nextToken.value === ")" && nextToken.range[0] >= node.range[1]; } + /** + * Determines if a node is surrounded by parentheses twice. + * @param {ASTNode} node - The node to be checked. + * @returns {boolean} True if the node is doubly parenthesised. + * @private + */ function isParenthesisedTwice(node) { var previousToken = context.getTokenBefore(node, 1), nextToken = context.getTokenAfter(node, 1); return isParenthesised(node) && previousToken && nextToken && previousToken.value === "(" && previousToken.range[1] <= node.range[0] && nextToken.value === ")" && nextToken.range[0] >= node.range[1]; } + /** + * Determines if a node is surrounded by (potentially) invalid parentheses. + * @param {ASTNode} node - The node to be checked. + * @returns {boolean} True if the node is incorrectly parenthesised. + * @private + */ + function hasExcessParens(node) { + return ruleApplies(node) && isParenthesised(node); + } + + /** + * Determines if a node that is expected to be parenthesised is surrounded by + * (potentially) invalid extra parentheses. + * @param {ASTNode} node - The node to be checked. + * @returns {boolean} True if the node is has an unexpected extra pair of parentheses. + * @private + */ + function hasDoubleExcessParens(node) { + return ruleApplies(node) && isParenthesisedTwice(node); + } + + /** + * Checks whether or not a given node is located at the head of ExpressionStatement. + * @param {ASTNode} node - A node to check. + * @returns {boolean} `true` if the node is located at the head of ExpressionStatement. + */ + function isHeadOfExpressionStatement(node) { + var parent = node.parent; + while (parent) { + switch (parent.type) { + case "SequenceExpression": + if (parent.expressions[0] !== node || isParenthesised(node)) { + return false; + } + break; + + case "UnaryExpression": + case "UpdateExpression": + if (parent.prefix || isParenthesised(node)) { + return false; + } + break; + + case "BinaryExpression": + case "LogicalExpression": + if (parent.left !== node || isParenthesised(node)) { + return false; + } + break; + + case "ConditionalExpression": + if (parent.test !== node || isParenthesised(node)) { + return false; + } + break; + + case "CallExpression": + if (parent.callee !== node || isParenthesised(node)) { + return false; + } + break; + + case "MemberExpression": + if (parent.object !== node || isParenthesised(node)) { + return false; + } + break; + + case "ExpressionStatement": + return true; + + default: + return false; + } + + node = parent; + parent = parent.parent; + } + + /* istanbul ignore next */ + throw new Error("unreachable"); + } + + /** + * Get the precedence level based on the node type + * @param {ASTNode} node node to evaluate + * @returns {int} precedence level + * @private + */ function precedence(node) { switch (node.type) { case "SequenceExpression": return 0; case "AssignmentExpression": + case "ArrowFunctionExpression": case "YieldExpression": return 1; case "ConditionalExpression": return 3; @@ -22732,121 +31556,180 @@ // no default } return 18; } + /** + * Report the node + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function report(node) { var previousToken = context.getTokenBefore(node); context.report(node, previousToken.loc.start, "Gratuitous parentheses around expression."); } + /** + * Evaluate Unary update + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function dryUnaryUpdate(node) { - if (isParenthesised(node.argument) && precedence(node.argument) >= precedence(node)) { + if (hasExcessParens(node.argument) && precedence(node.argument) >= precedence(node)) { report(node.argument); } } + /** + * Evaluate a new call + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function dryCallNew(node) { - if (isParenthesised(node.callee) && precedence(node.callee) >= precedence(node) && - !(node.type === "CallExpression" && node.callee.type === "FunctionExpression")) { + if (hasExcessParens(node.callee) && precedence(node.callee) >= precedence(node) && !( + node.type === "CallExpression" && + node.callee.type === "FunctionExpression" && + // One set of parentheses are allowed for a function expression + !hasDoubleExcessParens(node.callee) + )) { report(node.callee); } if (node.arguments.length === 1) { - if (isParenthesisedTwice(node.arguments[0]) && precedence(node.arguments[0]) >= precedence({type: "AssignmentExpression"})) { + if (hasDoubleExcessParens(node.arguments[0]) && precedence(node.arguments[0]) >= precedence({type: "AssignmentExpression"})) { report(node.arguments[0]); } } else { [].forEach.call(node.arguments, function(arg) { - if (isParenthesised(arg) && precedence(arg) >= precedence({type: "AssignmentExpression"})) { + if (hasExcessParens(arg) && precedence(arg) >= precedence({type: "AssignmentExpression"})) { report(arg); } }); } } + /** + * Evaluate binary logicals + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function dryBinaryLogical(node) { var prec = precedence(node); - if (isParenthesised(node.left) && precedence(node.left) >= prec) { + if (hasExcessParens(node.left) && precedence(node.left) >= prec) { report(node.left); } - if (isParenthesised(node.right) && precedence(node.right) > prec) { + if (hasExcessParens(node.right) && precedence(node.right) > prec) { report(node.right); } } return { "ArrayExpression": function(node) { [].forEach.call(node.elements, function(e) { - if (e && isParenthesised(e) && precedence(e) >= precedence({type: "AssignmentExpression"})) { + if (e && hasExcessParens(e) && precedence(e) >= precedence({type: "AssignmentExpression"})) { report(e); } }); }, + "ArrowFunctionExpression": function(node) { + if (node.body.type !== "BlockStatement") { + if (node.body.type !== "ObjectExpression" && hasExcessParens(node.body) && precedence(node.body) >= precedence({type: "AssignmentExpression"})) { + report(node.body); + return; + } + + // Object literals *must* be parenthesized + if (node.body.type === "ObjectExpression" && hasDoubleExcessParens(node.body)) { + report(node.body); + return; + } + } + }, "AssignmentExpression": function(node) { - if (isParenthesised(node.right) && precedence(node.right) >= precedence(node)) { + if (hasExcessParens(node.right) && precedence(node.right) >= precedence(node)) { report(node.right); } }, "BinaryExpression": dryBinaryLogical, "CallExpression": dryCallNew, "ConditionalExpression": function(node) { - if (isParenthesised(node.test) && precedence(node.test) >= precedence({type: "LogicalExpression", operator: "||"})) { + if (hasExcessParens(node.test) && precedence(node.test) >= precedence({type: "LogicalExpression", operator: "||"})) { report(node.test); } - if (isParenthesised(node.consequent) && precedence(node.consequent) >= precedence({type: "AssignmentExpression"})) { + if (hasExcessParens(node.consequent) && precedence(node.consequent) >= precedence({type: "AssignmentExpression"})) { report(node.consequent); } - if (isParenthesised(node.alternate) && precedence(node.alternate) >= precedence({type: "AssignmentExpression"})) { + if (hasExcessParens(node.alternate) && precedence(node.alternate) >= precedence({type: "AssignmentExpression"})) { report(node.alternate); } }, "DoWhileStatement": function(node) { - if (isParenthesisedTwice(node.test)) { + if (hasDoubleExcessParens(node.test)) { report(node.test); } }, "ExpressionStatement": function(node) { var firstToken; - if (isParenthesised(node.expression)) { + if (hasExcessParens(node.expression)) { firstToken = context.getFirstToken(node.expression); - if (firstToken.value !== "function" && firstToken.value !== "{") { + + // Pure object literals ({}) do not need parentheses but + // member expressions do ({}.toString()) + if (( + firstToken.value !== "{" || + node.expression.type === "ObjectExpression" + ) && + // For such as `(function(){}.foo.bar)` + ( + firstToken.value !== "function" || + node.expression.type === "FunctionExpression" + ) && + // For such as `(class{}.foo.bar)` + ( + firstToken.value !== "class" || + node.expression.type === "ClassExpression" + ) + ) { report(node.expression); } } }, "ForInStatement": function(node) { - if (isParenthesised(node.right)) { + if (hasExcessParens(node.right)) { report(node.right); } }, "ForOfStatement": function(node) { - if (isParenthesised(node.right)) { + if (hasExcessParens(node.right)) { report(node.right); } }, "ForStatement": function(node) { - if (node.init && isParenthesised(node.init)) { + if (node.init && hasExcessParens(node.init)) { report(node.init); } - if (node.test && isParenthesised(node.test)) { + if (node.test && hasExcessParens(node.test)) { report(node.test); } - if (node.update && isParenthesised(node.update)) { + if (node.update && hasExcessParens(node.update)) { report(node.update); } }, "IfStatement": function(node) { - if (isParenthesisedTwice(node.test)) { + if (hasDoubleExcessParens(node.test)) { report(node.test); } }, "LogicalExpression": dryBinaryLogical, "MemberExpression": function(node) { if ( - isParenthesised(node.object) && + hasExcessParens(node.object) && precedence(node.object) >= precedence(node) && ( node.computed || !( (node.object.type === "Literal" && @@ -22854,78 +31737,92 @@ /^[0-9]+$/.test(context.getFirstToken(node.object).value)) || // RegExp literal is allowed to have parens (#1589) (node.object.type === "Literal" && node.object.regex) ) + ) && + !( + (node.object.type === "FunctionExpression" || node.object.type === "ClassExpression") && + isHeadOfExpressionStatement(node) && + !hasDoubleExcessParens(node.object) ) ) { report(node.object); } + if (node.computed && hasExcessParens(node.property)) { + report(node.property); + } }, "NewExpression": dryCallNew, "ObjectExpression": function(node) { [].forEach.call(node.properties, function(e) { var v = e.value; - if (v && isParenthesised(v) && precedence(v) >= precedence({type: "AssignmentExpression"})) { + if (v && hasExcessParens(v) && precedence(v) >= precedence({type: "AssignmentExpression"})) { report(v); } }); }, "ReturnStatement": function(node) { - if (node.argument && isParenthesised(node.argument) && + if (node.argument && hasExcessParens(node.argument) && // RegExp literal is allowed to have parens (#1589) !(node.argument.type === "Literal" && node.argument.regex)) { report(node.argument); } }, "SequenceExpression": function(node) { [].forEach.call(node.expressions, function(e) { - if (isParenthesised(e) && precedence(e) >= precedence(node)) { + if (hasExcessParens(e) && precedence(e) >= precedence(node)) { report(e); } }); }, "SwitchCase": function(node) { - if (node.test && isParenthesised(node.test)) { + if (node.test && hasExcessParens(node.test)) { report(node.test); } }, "SwitchStatement": function(node) { - if (isParenthesisedTwice(node.discriminant)) { + if (hasDoubleExcessParens(node.discriminant)) { report(node.discriminant); } }, "ThrowStatement": function(node) { - if (isParenthesised(node.argument)) { + if (hasExcessParens(node.argument)) { report(node.argument); } }, "UnaryExpression": dryUnaryUpdate, "UpdateExpression": dryUnaryUpdate, "VariableDeclarator": function(node) { - if (node.init && isParenthesised(node.init) && + if (node.init && hasExcessParens(node.init) && precedence(node.init) >= precedence({type: "AssignmentExpression"}) && // RegExp literal is allowed to have parens (#1589) !(node.init.type === "Literal" && node.init.regex)) { report(node.init); } }, "WhileStatement": function(node) { - if (isParenthesisedTwice(node.test)) { + if (hasDoubleExcessParens(node.test)) { report(node.test); } }, "WithStatement": function(node) { - if (isParenthesisedTwice(node.object)) { + if (hasDoubleExcessParens(node.object)) { report(node.object); } } }; }; -},{}],191:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["all", "functions"] + } +]; + +},{}],199:[function(require,module,exports){ /** * @fileoverview Rule to flag use of unnecessary semicolons * @author Nicholas C. Zakas */ @@ -22935,114 +31832,90 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - return { - - "EmptyStatement": function(node) { - context.report(node, "Unnecessary semicolon."); - } - }; - -}; - -},{}],192:[function(require,module,exports){ -/** - * @fileoverview Rule to flag unnecessary strict directives. - * @author Ian Christian Myers - * @copyright 2014 Ian Christian Myers. All rights reserved. - */ -"use strict"; - -//------------------------------------------------------------------------------ -// Rule Definition -//------------------------------------------------------------------------------ - -module.exports = function(context) { - - function directives(block) { - var ds = [], body = block.body, e, i, l; - - if (body) { - for (i = 0, l = body.length; i < l; ++i) { - e = body[i]; - - if ( - e.type === "ExpressionStatement" && - e.expression.type === "Literal" && - typeof e.expression.value === "string" - ) { - ds.push(e.expression); - } else { - break; - } + /** + * Reports an unnecessary semicolon error. + * @param {Node|Token} nodeOrToken - A node or a token to be reported. + * @returns {void} + */ + function report(nodeOrToken) { + context.report({ + node: nodeOrToken, + message: "Unnecessary semicolon.", + fix: function(fixer) { + return fixer.remove(nodeOrToken); } - } - - return ds; + }); } - function isStrict(directive) { - return directive.value === "use strict"; - } - - function checkForUnnecessaryUseStrict(node) { - var useStrictDirectives = directives(node).filter(isStrict), - scope, - upper; - - switch (useStrictDirectives.length) { - case 0: - break; - - case 1: - scope = context.getScope(); - upper = scope.upper; - - if (upper && upper.functionExpressionScope) { - upper = upper.upper; - } - - if (upper && upper.isStrict) { - context.report(useStrictDirectives[0], "Unnecessary 'use strict'."); - } - break; - - default: - context.report(useStrictDirectives[1], "Multiple 'use strict' directives."); + /** + * Checks for a part of a class body. + * This checks tokens from a specified token to a next MethodDefinition or the end of class body. + * + * @param {Token} firstToken - The first token to check. + * @returns {void} + */ + function checkForPartOfClassBody(firstToken) { + for (var token = firstToken; + token.type === "Punctuator" && token.value !== "}"; + token = context.getTokenAfter(token) + ) { + if (token.value === ";") { + report(token); + } } } return { + /** + * Reports this empty statement, except if the parent node is a loop. + * @param {Node} node - A EmptyStatement node to be reported. + * @returns {void} + */ + "EmptyStatement": function(node) { + var parent = node.parent, + allowedParentTypes = ["ForStatement", "ForInStatement", "ForOfStatement", "WhileStatement", "DoWhileStatement"]; - "Program": checkForUnnecessaryUseStrict, - - "ArrowFunctionExpression": function(node) { - checkForUnnecessaryUseStrict(node.body); + if (allowedParentTypes.indexOf(parent.type) === -1) { + report(node); + } }, - "FunctionExpression": function(node) { - checkForUnnecessaryUseStrict(node.body); + /** + * Checks tokens from the head of this class body to the first MethodDefinition or the end of this class body. + * @param {Node} node - A ClassBody node to check. + * @returns {void} + */ + "ClassBody": function(node) { + checkForPartOfClassBody(context.getFirstToken(node, 1)); // 0 is `{`. }, - "FunctionDeclaration": function(node) { - checkForUnnecessaryUseStrict(node.body); + /** + * Checks tokens from this MethodDefinition to the next MethodDefinition or the end of this class body. + * @param {Node} node - A MethodDefinition node of the start point. + * @returns {void} + */ + "MethodDefinition": function(node) { + checkForPartOfClassBody(context.getTokenAfter(node)); } }; }; -},{}],193:[function(require,module,exports){ +module.exports.schema = []; + +},{}],200:[function(require,module,exports){ /** * @fileoverview Rule to flag fall-through cases in switch statements. * @author Matt DuVall <http://mattduvall.com/> */ "use strict"; -var FALLTHROUGH_COMMENT = /falls\sthrough/; +var FALLTHROUGH_COMMENT = /falls?\s?through/i; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -23127,11 +32000,13 @@ } }; }; -},{}],194:[function(require,module,exports){ +module.exports.schema = []; + +},{}],201:[function(require,module,exports){ /** * @fileoverview Rule to flag use of a leading/trailing decimal point in a numeric literal * @author James Allardice */ @@ -23157,94 +32032,324 @@ } }; }; -},{}],195:[function(require,module,exports){ +module.exports.schema = []; + +},{}],202:[function(require,module,exports){ /** * @fileoverview Rule to flag use of function declaration identifiers as variables. * @author Ian Christian Myers * @copyright 2013 Ian Christian Myers. All rights reserved. */ "use strict"; +var astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - //-------------------------------------------------------------------------- - // Helpers - //-------------------------------------------------------------------------- + var unresolved = Object.create(null); - /* - * Walk the scope chain looking for either a FunctionDeclaration or a - * VariableDeclaration with the same name as left-hand side of the - * AssignmentExpression. If we find the FunctionDeclaration first, then we - * warn, because a FunctionDeclaration is trying to become a Variable or a - * FunctionExpression. If we find a VariableDeclaration first, then we have - * a legitimate shadow variable. + /** + * Collects unresolved references from the global scope, then creates a map to references from its name. + * Usage of the map is explained at `checkVariable(variable)`. + * @returns {void} */ - function checkIfIdentifierIsFunction(scope, name) { - var variable, - def, - i, - j; + function collectUnresolvedReferences() { + unresolved = Object.create(null); - // Loop over all of the identifiers available in scope. - for (i = 0; i < scope.variables.length; i++) { - variable = scope.variables[i]; + var references = context.getScope().through; + for (var i = 0; i < references.length; ++i) { + var reference = references[i]; + var name = reference.identifier.name; - // For each identifier, see if it was defined in _this_ scope. - for (j = 0; j < variable.defs.length; j++) { - def = variable.defs[j]; + if (name in unresolved === false) { + unresolved[name] = []; + } + unresolved[name].push(reference); + } + } - // Identifier is a function and was declared in this scope - if (def.name.name === name && def.type === "FunctionName") { - return true; - } + /** + * Reports a reference if is non initializer and writable. + * @param {References} references - Collection of reference to check. + * @returns {void} + */ + function checkReference(references) { + astUtils.getModifyingReferences(references).forEach(function(reference) { + context.report( + reference.identifier, + "'{{name}}' is a function.", + {name: reference.identifier.name}); + }); + } - // Identifier is a variable and was declared in this scope. This - // is a legitimate shadow variable. - if (def.name.name === name) { - return false; - } + /** + * Finds and reports references that are non initializer and writable. + * @param {Variable} variable - A variable to check. + * @returns {void} + */ + function checkVariable(variable) { + if (variable.defs[0].type === "FunctionName") { + // If the function is in global scope, its references are not resolved (by escope's design). + // So when references of the function are nothing, this checks in unresolved. + if (variable.references.length > 0) { + checkReference(variable.references); + } else if (unresolved[variable.name]) { + checkReference(unresolved[variable.name]); } } + } - // Check the upper scope. - if (scope.upper) { - return checkIfIdentifierIsFunction(scope.upper, name); - } + /** + * Checks parameters of a given function node. + * @param {ASTNode} node - A function node to check. + * @returns {void} + */ + function checkForFunction(node) { + context.getDeclaredVariables(node).forEach(checkVariable); + } - // We've reached the global scope and haven't found anything. - return false; + return { + "Program": collectUnresolvedReferences, + "FunctionDeclaration": checkForFunction, + "FunctionExpression": checkForFunction + }; + +}; + +module.exports.schema = []; + +},{"../ast-utils":113}],203:[function(require,module,exports){ +/** + * @fileoverview A rule to disallow the type conversions with shorter notations. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +var INDEX_OF_PATTERN = /^(?:i|lastI)ndexOf$/; + +/** + * Parses and normalizes an option object. + * @param {object} options - An option object to parse. + * @returns {object} The parsed and normalized option object. + */ +function parseOptions(options) { + options = options || {}; + return { + boolean: "boolean" in options ? Boolean(options.boolean) : true, + number: "number" in options ? Boolean(options.number) : true, + string: "string" in options ? Boolean(options.string) : true + }; +} + +/** + * Checks whether or not a node is a double logical nigating. + * @param {ASTNode} node - An UnaryExpression node to check. + * @returns {boolean} Whether or not the node is a double logical nigating. + */ +function isDoubleLogicalNegating(node) { + return ( + node.operator === "!" && + node.argument.type === "UnaryExpression" && + node.argument.operator === "!" + ); +} + +/** + * Checks whether or not a node is a binary negating of `.indexOf()` method calling. + * @param {ASTNode} node - An UnaryExpression node to check. + * @returns {boolean} Whether or not the node is a binary negating of `.indexOf()` method calling. + */ +function isBinaryNegatingOfIndexOf(node) { + return ( + node.operator === "~" && + node.argument.type === "CallExpression" && + node.argument.callee.type === "MemberExpression" && + node.argument.callee.property.type === "Identifier" && + INDEX_OF_PATTERN.test(node.argument.callee.property.name) + ); +} + +/** + * Checks whether or not a node is a multiplying by one. + * @param {BinaryExpression} node - A BinaryExpression node to check. + * @returns {boolean} Whether or not the node is a multiplying by one. + */ +function isMultiplyByOne(node) { + return node.operator === "*" && ( + node.left.type === "Literal" && node.left.value === 1 || + node.right.type === "Literal" && node.right.value === 1 + ); +} + +/** + * Checks whether the result of a node is numeric or not + * @param {ASTNode} node The node to test + * @returns {boolean} true if the node is a number literal or a `Number()`, `parseInt` or `parseFloat` call + */ +function isNumeric(node) { + return ( + node.type === "Literal" && typeof node.value === "number" || + node.type === "CallExpression" && ( + node.callee.name === "Number" || + node.callee.name === "parseInt" || + node.callee.name === "parseFloat" + ) + ); +} + +/** + * Returns the first non-numeric operand in a BinaryExpression. Designed to be + * used from bottom to up since it walks up the BinaryExpression trees using + * node.parent to find the result. + * @param {BinaryExpression} node The BinaryExpression node to be walked up on + * @returns {ASTNode|undefined} The first non-numeric item in the BinaryExpression tree or undefined + */ +function getNonNumericOperand(node) { + var left = node.left, right = node.right; + + if (right.type !== "BinaryExpression" && !isNumeric(right)) { + return right; } - //-------------------------------------------------------------------------- - // Public API - //-------------------------------------------------------------------------- + if (left.type !== "BinaryExpression" && !isNumeric(left)) { + return left; + } +} +/** + * Checks whether or not a node is a concatenating with an empty string. + * @param {ASTNode} node - A BinaryExpression node to check. + * @returns {boolean} Whether or not the node is a concatenating with an empty string. + */ +function isConcatWithEmptyString(node) { + return node.operator === "+" && ( + (node.left.type === "Literal" && node.left.value === "") || + (node.right.type === "Literal" && node.right.value === "") + ); +} + +/** + * Checks whether or not a node is appended with an empty string. + * @param {ASTNode} node - An AssignmentExpression node to check. + * @returns {boolean} Whether or not the node is appended with an empty string. + */ +function isAppendEmptyString(node) { + return node.operator === "+=" && node.right.type === "Literal" && node.right.value === ""; +} + +/** + * Gets a node that is the left or right operand of a node, is not the specified literal. + * @param {ASTNode} node - A BinaryExpression node to get. + * @param {any} value - A literal value to check. + * @returns {ASTNode} A node that is the left or right operand of the node, is not the specified literal. + */ +function getOtherOperand(node, value) { + if (node.left.type === "Literal" && node.left.value === value) { + return node.right; + } + return node.left; +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var options = parseOptions(context.options[0]); + return { + "UnaryExpression": function(node) { + // !!foo + if (options.boolean && isDoubleLogicalNegating(node)) { + context.report( + node, + "use `Boolean({{code}})` instead.", + {code: context.getSource(node.argument.argument)}); + } - "AssignmentExpression": function(node) { - var scope = context.getScope(), - name = node.left.name; + // ~foo.indexOf(bar) + if (options.boolean && isBinaryNegatingOfIndexOf(node)) { + context.report( + node, + "use `{{code}} !== -1` instead.", + {code: context.getSource(node.argument)}); + } - if (checkIfIdentifierIsFunction(scope, name)) { - context.report(node, "'{{name}}' is a function.", { name: name }); + // +foo + if (options.number && node.operator === "+" && !isNumeric(node.argument)) { + context.report( + node, + "use `Number({{code}})` instead.", + {code: context.getSource(node.argument)}); } + }, - } + // Use `:exit` to prevent double reporting + "BinaryExpression:exit": function(node) { + // 1 * foo + var nonNumericOperand = options.number && isMultiplyByOne(node) && getNonNumericOperand(node); + if (nonNumericOperand) { + context.report( + node, + "use `Number({{code}})` instead.", + {code: context.getSource(nonNumericOperand)}); + } - }; + // "" + foo + if (options.string && isConcatWithEmptyString(node)) { + context.report( + node, + "use `String({{code}})` instead.", + {code: context.getSource(getOtherOperand(node, ""))}); + } + }, + "AssignmentExpression": function(node) { + // foo += "" + if (options.string && isAppendEmptyString(node)) { + context.report( + node, + "use `{{code}} = String({{code}})` instead.", + {code: context.getSource(getOtherOperand(node, ""))}); + } + } + }; }; -},{}],196:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "boolean": { + "type": "boolean" + }, + "number": { + "type": "boolean" + }, + "string": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{}],204:[function(require,module,exports){ /** * @fileoverview Rule to flag use of implied eval via setTimeout and setInterval * @author James Allardice * @copyright 2015 Mathias Schreck. All rights reserved. * @copyright 2013 James Allardice. All rights reserved. @@ -23255,79 +32360,150 @@ //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var IMPLIED_EVAL = /set(?:Timeout|Interval)/; + var CALLEE_RE = /set(?:Timeout|Interval)|execScript/; + // Figures out if we should inspect a given binary expression. Is a stack of + // stacks, where the first element in each substack is a CallExpression. + var impliedEvalAncestorsStack = []; + //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- /** - * Checks if the first argument of a given CallExpression node is a string literal. - * @param {ASTNode} node The CallExpression node the check. - * @returns {boolean} True if the first argument is a string literal, false if not. + * Get the last element of an array, without modifying arr, like pop(), but non-destructive. + * @param {array} arr What to inspect + * @returns {*} The last element of arr + * @private */ - function hasStringLiteralArgument(node) { - var firstArgument = node.arguments[0]; - - return firstArgument && firstArgument.type === "Literal" && typeof firstArgument.value === "string"; + function last(arr) { + return arr ? arr[arr.length - 1] : null; } /** - * Checks if the given MemberExpression node is window.setTimeout or window.setInterval. + * Checks if the given MemberExpression node is a potentially implied eval identifier on window. * @param {ASTNode} node The MemberExpression node to check. - * @returns {boolean} Whether or not the given node is window.set*. + * @returns {boolean} Whether or not the given node is potentially an implied eval. + * @private */ - function isSetMemberExpression(node) { + function isImpliedEvalMemberExpression(node) { var object = node.object, property = node.property, - hasSetPropertyName = IMPLIED_EVAL.test(property.name) || IMPLIED_EVAL.test(property.value); + hasImpliedEvalName = CALLEE_RE.test(property.name) || CALLEE_RE.test(property.value); - return object.name === "window" && hasSetPropertyName; - + return object.name === "window" && hasImpliedEvalName; } /** - * Determines if a node represents a call to setTimeout/setInterval with - * a string argument. - * @param {ASTNode} node The node to check. + * Determines if a node represents a call to a potentially implied eval. + * + * This checks the callee name and that there's an argument, but not the type of the argument. + * + * @param {ASTNode} node The CallExpression to check. * @returns {boolean} True if the node matches, false if not. * @private */ - function isImpliedEval(node) { + function isImpliedEvalCallExpression(node) { var isMemberExpression = (node.callee.type === "MemberExpression"), isIdentifier = (node.callee.type === "Identifier"), - isSetMethod = (isIdentifier && IMPLIED_EVAL.test(node.callee.name)) || - (isMemberExpression && isSetMemberExpression(node.callee)); + isImpliedEvalCallee = + (isIdentifier && CALLEE_RE.test(node.callee.name)) || + (isMemberExpression && isImpliedEvalMemberExpression(node.callee)); - return isSetMethod && hasStringLiteralArgument(node); + return isImpliedEvalCallee && node.arguments.length; } + /** + * Checks that the parent is a direct descendent of an potential implied eval CallExpression, and if the parent is a CallExpression, that we're the first argument. + * @param {ASTNode} node The node to inspect the parent of. + * @returns {boolean} Was the parent a direct descendent, and is the child therefore potentially part of a dangerous argument? + * @private + */ + function hasImpliedEvalParent(node) { + // make sure our parent is marked + return node.parent === last(last(impliedEvalAncestorsStack)) && + // if our parent is a CallExpression, make sure we're the first argument + (node.parent.type !== "CallExpression" || node === node.parent.arguments[0]); + } + + /** + * Checks if our parent is marked as part of an implied eval argument. If + * so, collapses the top of impliedEvalAncestorsStack and reports on the + * original CallExpression. + * @param {ASTNode} node The CallExpression to check. + * @returns {boolean} True if the node matches, false if not. + * @private + */ + function checkString(node) { + if (hasImpliedEvalParent(node)) { + // remove the entire substack, to avoid duplicate reports + var substack = impliedEvalAncestorsStack.pop(); + context.report(substack[0], "Implied eval. Consider passing a function instead of a string."); + } + } + //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- return { "CallExpression": function(node) { - if (isImpliedEval(node)) { - context.report(node, "Implied eval. Consider passing a function instead of a string."); + if (isImpliedEvalCallExpression(node)) { + // call expressions create a new substack + impliedEvalAncestorsStack.push([node]); } + }, + + "CallExpression:exit": function(node) { + if (node === last(last(impliedEvalAncestorsStack))) { + // destroys the entire sub-stack, rather than just using + // last(impliedEvalAncestorsStack).pop(), as a CallExpression is + // always the bottom of a impliedEvalAncestorsStack substack. + impliedEvalAncestorsStack.pop(); + } + }, + + "BinaryExpression": function(node) { + if (node.operator === "+" && hasImpliedEvalParent(node)) { + last(impliedEvalAncestorsStack).push(node); + } + }, + + "BinaryExpression:exit": function(node) { + if (node === last(last(impliedEvalAncestorsStack))) { + last(impliedEvalAncestorsStack).pop(); + } + }, + + "Literal": function(node) { + if (typeof node.value === "string") { + checkString(node); + } + }, + + "TemplateLiteral": function(node) { + checkString(node); } }; }; -},{}],197:[function(require,module,exports){ +module.exports.schema = []; + +},{}],205:[function(require,module,exports){ /** * @fileoverview Enforces or disallows inline comments. * @author Greg Cochard * @copyright 2014 Greg Cochard. All rights reserved. */ "use strict"; +var astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { @@ -23347,12 +32523,15 @@ var preamble = startLine.slice(0, node.loc.start.column).trim(); // Also check after the comment var postamble = endLine.slice(node.loc.end.column).trim(); + // Check that this comment isn't an ESLint directive + var isDirective = astUtils.isDirectiveComment(node); + // Should be empty if there was only whitespace around the comment - if (preamble || postamble) { + if (!isDirective && (preamble || postamble)) { context.report(node, "Unexpected comment inline with code."); } } //-------------------------------------------------------------------------- @@ -23365,11 +32544,13 @@ "BlockComment": testCodeAroundComment }; }; -},{}],198:[function(require,module,exports){ +module.exports.schema = []; + +},{"../ast-utils":113}],206:[function(require,module,exports){ /** * @fileoverview Rule to enforce declarations in program or function body root. * @author Brandon Mills * @copyright 2014 Brandon Mills. All rights reserved. */ @@ -23439,11 +32620,17 @@ }; }; -},{}],199:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["functions", "both"] + } +]; + +},{}],207:[function(require,module,exports){ /** * @fileoverview Validate strings passed to the RegExp constructor * @author Michael Ficarra * @copyright 2014 Michael Ficarra. All rights reserved. */ @@ -23459,21 +32646,33 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + /** + * Check if node is a string + * @param {ASTNode} node node to evaluate + * @returns {boolean} True if its a string + * @private + */ function isString(node) { return node && node.type === "Literal" && typeof node.value === "string"; } + /** + * Validate strings passed to the RegExp constructor + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function check(node) { if (node.callee.type === "Identifier" && node.callee.name === "RegExp" && isString(node.arguments[0])) { var flags = isString(node.arguments[1]) ? node.arguments[1].value : ""; try { void new RegExp(node.arguments[0].value); - } catch(e) { + } catch (e) { context.report(node, e.message); } if (flags) { @@ -23492,12 +32691,366 @@ "NewExpression": check }; }; -},{"espree":"espree"}],200:[function(require,module,exports){ +module.exports.schema = []; + +},{"espree":"espree"}],208:[function(require,module,exports){ /** + * @fileoverview A rule to disallow `this` keywords outside of classes or class-like objects. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +var thisTagPattern = /^[\s\*]*@this/m; +var anyFunctionPattern = /^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression)$/; +var bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/; +var arrayOrTypedArrayPattern = /Array$/; +var arrayMethodPattern = /^(?:every|filter|find|findIndex|forEach|map|some)$/; + +/** + * Checks whether or not a node is a constructor. + * @param {ASTNode} node - A function node to check. + * @returns {boolean} Wehether or not a node is a constructor. + */ +function isES5Constructor(node) { + return ( + node.id && + node.id.name[0] === node.id.name[0].toLocaleUpperCase() + ); +} + +/** + * Finds a function node from ancestors of a node. + * @param {ASTNode} node - A start node to find. + * @returns {Node|null} A found function node. + */ +function getUpperFunction(node) { + while (node) { + if (anyFunctionPattern.test(node.type)) { + return node; + } + node = node.parent; + } + return null; +} + +/** + * Checks whether or not a node is callee. + * @param {ASTNode} node - A node to check. + * @returns {boolean} Whether or not the node is callee. + */ +function isCallee(node) { + return node.parent.type === "CallExpression" && node.parent.callee === node; +} + +/** + * Checks whether or not a node is `Reclect.apply`. + * @param {ASTNode} node - A node to check. + * @returns {boolean} Whether or not the node is a `Reclect.apply`. + */ +function isReflectApply(node) { + return ( + node.type === "MemberExpression" && + node.object.type === "Identifier" && + node.object.name === "Reflect" && + node.property.type === "Identifier" && + node.property.name === "apply" && + node.computed === false + ); +} + +/** + * Checks whether or not a node is `Array.from`. + * @param {ASTNode} node - A node to check. + * @returns {boolean} Whether or not the node is a `Array.from`. + */ +function isArrayFrom(node) { + return ( + node.type === "MemberExpression" && + node.object.type === "Identifier" && + arrayOrTypedArrayPattern.test(node.object.name) && + node.property.type === "Identifier" && + node.property.name === "from" && + node.computed === false + ); +} + +/** + * Checks whether or not a node is a method which has `thisArg`. + * @param {ASTNode} node - A node to check. + * @returns {boolean} Whether or not the node is a method which has `thisArg`. + */ +function isMethodWhichHasThisArg(node) { + while (node) { + if (node.type === "Identifier") { + return arrayMethodPattern.test(node.name); + } + if (node.type === "MemberExpression" && !node.computed) { + node = node.property; + continue; + } + + break; + } + + return false; +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var stack = [], + sourceCode = context.getSourceCode(); + + + /** + * Checks whether or not a node has a `@this` tag in its comments. + * @param {ASTNode} node - A node to check. + * @returns {boolean} Whether or not the node has a `@this` tag in its comments. + */ + function hasJSDocThisTag(node) { + var jsdocComment = sourceCode.getJSDocComment(node); + if (jsdocComment && thisTagPattern.test(jsdocComment.value)) { + return true; + } + + // Checks `@this` in its leading comments for callbacks, + // because callbacks don't have its JSDoc comment. + // e.g. + // sinon.test(/* @this sinon.Sandbox */function() { this.spy(); }); + return sourceCode.getComments(node).leading.some(function(comment) { + return thisTagPattern.test(comment.value); + }); + } + + /** + * Checks whether or not a node has valid `this`. + * + * First, this checks the node: + * + * - The function name starts with uppercase (it's a constructor). + * - The function has a JSDoc comment that has a @this tag. + * + * Next, this checks the location of the node. + * If the location is below, this judges `this` is valid. + * + * - The location is on an object literal. + * - The location assigns to a property. + * - The location is on an ES2015 class. + * - The location calls its `bind`/`call`/`apply` method directly. + * - The function is a callback of array methods (such as `.forEach()`) if `thisArg` is given. + * + * @param {ASTNode} node - A node to check. + * @returns {boolean} A found function node. + */ + function hasValidThis(node) { + if (isES5Constructor(node) || hasJSDocThisTag(node)) { + return true; + } + + while (node) { + var parent = node.parent; + switch (parent.type) { + // Looks up the destination. + // e.g. + // obj.foo = nativeFoo || function foo() { ... }; + case "LogicalExpression": + case "ConditionalExpression": + node = parent; + break; + + // If the upper function is IIFE, checks the destination of the return value. + // e.g. + // obj.foo = (function() { + // // setup... + // return function foo() { ... }; + // })(); + case "ReturnStatement": + var func = getUpperFunction(parent); + if (func === null || !isCallee(func)) { + return false; + } + node = func.parent; + break; + + // e.g. + // var obj = { foo() { ... } }; + // var obj = { foo: function() { ... } }; + case "Property": + return true; + + // e.g. + // obj.foo = foo() { ... }; + case "AssignmentExpression": + return ( + parent.right === node && + parent.left.type === "MemberExpression" + ); + + // e.g. + // class A { constructor() { ... } } + // class A { foo() { ... } } + // class A { get foo() { ... } } + // class A { set foo() { ... } } + // class A { static foo() { ... } } + case "MethodDefinition": + return !parent.static; + + // e.g. + // var foo = function foo() { ... }.bind(obj); + // (function foo() { ... }).call(obj); + // (function foo() { ... }).apply(obj, []); + case "MemberExpression": + return ( + parent.object === node && + parent.property.type === "Identifier" && + bindOrCallOrApplyPattern.test(parent.property.name) && + isCallee(parent) && + parent.parent.arguments.length > 0 && + !astUtils.isNullOrUndefined(parent.parent.arguments[0]) + ); + + // e.g. + // Reflect.apply(function() {}, obj, []); + // Array.from([], function() {}, obj); + // list.forEach(function() {}, obj); + case "CallExpression": + if (isReflectApply(parent.callee)) { + return ( + parent.arguments.length === 3 && + parent.arguments[0] === node && + !astUtils.isNullOrUndefined(parent.arguments[1]) + ); + } + if (isArrayFrom(parent.callee)) { + return ( + parent.arguments.length === 3 && + parent.arguments[1] === node && + !astUtils.isNullOrUndefined(parent.arguments[2]) + ); + } + if (isMethodWhichHasThisArg(parent.callee)) { + return ( + parent.arguments.length === 2 && + parent.arguments[0] === node && + !astUtils.isNullOrUndefined(parent.arguments[1]) + ); + } + return false; + + // Otherwise `this` is invalid. + default: + return false; + } + } + + /* istanbul ignore next */ + throw new Error("unreachable"); + } + + /** + * Gets the current checking context. + * + * The return value has a flag that whether or not `this` keyword is valid. + * The flag is initialized when got at the first time. + * + * @returns {{valid: boolean}} + * an object which has a flag that whether or not `this` keyword is valid. + */ + stack.getCurrent = function() { + var current = this[this.length - 1]; + if (!current.init) { + current.init = true; + current.valid = hasValidThis(current.node); + } + return current; + }; + + /** + * Pushs new checking context into the stack. + * + * The checking context is not initialized yet. + * Because most functions don't have `this` keyword. + * When `this` keyword was found, the checking context is initialized. + * + * @param {ASTNode} node - A function node that was entered. + * @returns {void} + */ + function enterFunction(node) { + // `this` can be invalid only under strict mode. + stack.push({ + init: !context.getScope().isStrict, + node: node, + valid: true + }); + } + + /** + * Pops the current checking context from the stack. + * @returns {void} + */ + function exitFunction() { + stack.pop(); + } + + return { + // `this` is invalid only under strict mode. + // Modules is always strict mode. + "Program": function(node) { + var scope = context.getScope(); + var features = context.ecmaFeatures; + + stack.push({ + init: true, + node: node, + valid: !( + scope.isStrict || + features.modules || + (features.globalReturn && scope.childScopes[0].isStrict) + ) + }); + }, + "Program:exit": function() { + stack.pop(); + }, + + "FunctionDeclaration": enterFunction, + "FunctionDeclaration:exit": exitFunction, + "FunctionExpression": enterFunction, + "FunctionExpression:exit": exitFunction, + + // Reports if `this` of the current context is invalid. + "ThisExpression": function(node) { + var current = stack.getCurrent(); + if (current && !current.valid) { + context.report(node, "Unexpected `this`."); + } + } + }; +}; + +module.exports.schema = []; + +},{"../ast-utils":113}],209:[function(require,module,exports){ +/** * @fileoverview Rule to disalow whitespace that is not a tab or space, whitespace inside strings and comments are allowed * @author Jonathan Kingston * @copyright 2014 Jonathan Kingston. All rights reserved. */ @@ -23507,11 +33060,12 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var irregularWhitespace = /[\u0085\u00A0\ufeff\f\v\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u202f\u205f\u3000]+/mg; + var irregularWhitespace = /[\u0085\u00A0\ufeff\f\v\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000]+/mg, + irregularLineTerminators = /[\u2028\u2029]/mg; // Module store of errors that we have found var errors = []; /** @@ -23522,75 +33076,117 @@ */ function removeStringError(node) { var locStart = node.loc.start; var locEnd = node.loc.end; - errors = errors.filter(function (error) { + errors = errors.filter(function(error) { var errorLoc = error[1]; if (errorLoc.line >= locStart.line && errorLoc.line <= locEnd.line) { - if (errorLoc.column >= locStart.column && errorLoc.column <= locEnd.column) { + if (errorLoc.column >= locStart.column && (errorLoc.column <= locEnd.column || errorLoc.line < locEnd.line)) { return false; } } return true; }); } /** - * Checks nodes for errors that we are choosing to ignore and calls the relevent methods to remove the errors + * Checks nodes for errors that we are choosing to ignore and calls the relevant methods to remove the errors * @param {ASTNode} node to check for matching errors. * @returns {void} * @private */ function removeInvalidNodeErrors(node) { if (typeof node.value === "string") { // If we have irregular characters remove them from the errors list - if (node.value.match(irregularWhitespace)) { + if (node.raw.match(irregularWhitespace) || node.raw.match(irregularLineTerminators)) { removeStringError(node); } } } + /** + * Checks the program source for irregular whitespace + * @param {ASTNode} node The program node + * @returns {void} + * @private + */ + function checkForIrregularWhitespace(node) { + var sourceLines = context.getSourceLines(); + + sourceLines.forEach(function(sourceLine, lineIndex) { + var lineNumber = lineIndex + 1, + location, + match; + + while ((match = irregularWhitespace.exec(sourceLine)) !== null) { + location = { + line: lineNumber, + column: match.index + }; + + errors.push([node, location, "Irregular whitespace not allowed"]); + } + }); + } + + /** + * Checks the program source for irregular line terminators + * @param {ASTNode} node The program node + * @returns {void} + * @private + */ + function checkForIrregularLineTerminators(node) { + var source = context.getSource(), + sourceLines = context.getSourceLines(), + linebreaks = source.match(/\r\n|\r|\n|\u2028|\u2029/g), + lastLineIndex = -1, + lineIndex, + location, + match; + + while ((match = irregularLineTerminators.exec(source)) !== null) { + lineIndex = linebreaks.indexOf(match[0], lastLineIndex + 1) || 0; + + location = { + line: lineIndex + 1, + column: sourceLines[lineIndex].length + }; + + errors.push([node, location, "Irregular whitespace not allowed"]); + lastLineIndex = lineIndex; + } + } + return { - "Program": function (node) { + "Program": function(node) { /** * As we can easily fire warnings for all white space issues with all the source its simpler to fire them here * This means we can check all the application code without having to worry about issues caused in the parser tokens * When writing this code also evaluating per node was missing out connecting tokens in some cases * We can later filter the errors when they are found to be not an issue in nodes we don't care about */ - var sourceLines = context.getSourceLines(); - sourceLines.forEach(function (sourceLine, lineIndex) { - var location, - match = irregularWhitespace.exec(sourceLine); - - if (match !== null) { - location = { - line: lineIndex + 1, - column: match.index - }; - - errors.push([node, location, "Irregular whitespace not allowed"]); - } - }); + checkForIrregularWhitespace(node); + checkForIrregularLineTerminators(node); }, + "Identifier": removeInvalidNodeErrors, "Literal": removeInvalidNodeErrors, - "Statement": removeInvalidNodeErrors, - "Expression": removeInvalidNodeErrors, - "Program:exit": function () { + "Program:exit": function() { // If we have any errors remaining report on them - errors.forEach(function (error) { - context.report.apply(this, error); + errors.forEach(function(error) { + context.report.apply(context, error); }); } }; }; -},{}],201:[function(require,module,exports){ +module.exports.schema = []; + +},{}],210:[function(require,module,exports){ /** * @fileoverview Rule to flag usage of __iterator__ property * @author Ian Christian Myers */ @@ -23614,50 +33210,45 @@ } }; }; -},{}],202:[function(require,module,exports){ +module.exports.schema = []; + +},{}],211:[function(require,module,exports){ /** * @fileoverview Rule to flag labels that are the same as an identifier * @author Ian Christian Myers */ "use strict"; //------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- - function findIdentifier(scope, identifier) { - var found = false; - - scope.variables.forEach(function(variable) { - if (variable.name === identifier) { - found = true; - } - }); - - scope.references.forEach(function(reference) { - if (reference.identifier.name === identifier) { - found = true; - } - }); - - // If we have not found the identifier in this scope, check the parent - // scope. - if (scope.upper && !found) { - return findIdentifier(scope.upper, identifier); - } - - return found; + /** + * Check if the identifier is present inside current scope + * @param {object} scope current scope + * @param {string} name To evaluate + * @returns {boolean} True if its present + * @private + */ + function findIdentifier(scope, name) { + return astUtils.getVariableByName(scope, name) !== null; } //-------------------------------------------------------------------------- // Public API //-------------------------------------------------------------------------- @@ -23678,11 +33269,13 @@ }; }; -},{}],203:[function(require,module,exports){ +module.exports.schema = []; + +},{"../ast-utils":113}],212:[function(require,module,exports){ /** * @fileoverview Disallow Labeled Statements * @author Nicholas C. Zakas */ "use strict"; @@ -23722,38 +33315,121 @@ }; }; -},{}],204:[function(require,module,exports){ +module.exports.schema = []; + +},{}],213:[function(require,module,exports){ /** * @fileoverview Rule to flag blocks with no reason to exist * @author Brandon Mills + * @copyright 2015 Roberto Vidal. All rights reserved. + * @copyright 2014 Brandon Mills. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - return { - "BlockStatement": function (node) { - // Check for any occurrence of BlockStatement > BlockStatement or - // Program > BlockStatement - var parent = context.getAncestors().pop(); - if (parent.type === "BlockStatement" || parent.type === "Program") { - context.report(node, "Block is nested inside another block."); + // A stack of lone blocks to be checked for block-level bindings + var loneBlocks = [], + ruleDef; + + /** + * Reports a node as invalid. + * @param {ASTNode} node - The node to be reported. + * @returns {void} + */ + function report(node) { + var parent = context.getAncestors().pop(); + context.report(node, parent.type === "Program" ? + "Block is redundant." : + "Nested block is redundant." + ); + } + + /** + * Checks for any ocurrence of BlockStatement > BlockStatement or Program > BlockStatement + * @returns {boolean} True if the current node is a lone block. + */ + function isLoneBlock() { + var parent = context.getAncestors().pop(); + return parent.type === "BlockStatement" || parent.type === "Program"; + } + + /** + * Checks the enclosing block of the current node for block-level bindings, + * and "marks it" as valid if any. + * @returns {void} + */ + function markLoneBlock() { + if (loneBlocks.length === 0) { + return; + } + + var block = context.getAncestors().pop(); + + if (loneBlocks[loneBlocks.length - 1] === block) { + loneBlocks.pop(); + } + } + + // Default rule definition: report all lone blocks + ruleDef = { + BlockStatement: function(node) { + if (isLoneBlock(node)) { + report(node); } } }; + // ES6: report blocks without block-level bindings + if (context.ecmaFeatures.blockBindings || context.ecmaFeatures.classes) { + ruleDef = { + "BlockStatement": function(node) { + if (isLoneBlock(node)) { + loneBlocks.push(node); + } + }, + "BlockStatement:exit": function(node) { + if (loneBlocks.length > 0 && loneBlocks[loneBlocks.length - 1] === node) { + loneBlocks.pop(); + report(node); + } + } + }; + } + + if (context.ecmaFeatures.blockBindings) { + ruleDef.VariableDeclaration = function(node) { + if (node.kind === "let" || node.kind === "const") { + markLoneBlock(node); + } + }; + + ruleDef.FunctionDeclaration = function(node) { + if (context.getScope().isStrict) { + markLoneBlock(node); + } + }; + } + + if (context.ecmaFeatures.classes) { + ruleDef.ClassDeclaration = markLoneBlock; + } + + return ruleDef; }; -},{}],205:[function(require,module,exports){ +module.exports.schema = []; + +},{}],214:[function(require,module,exports){ /** * @fileoverview Rule to disallow if as the only statmenet in an else block * @author Brandon Mills */ "use strict"; @@ -23779,50 +33455,119 @@ } }; }; -},{}],206:[function(require,module,exports){ +module.exports.schema = []; + +},{}],215:[function(require,module,exports){ /** * @fileoverview Rule to flag creation of function inside a loop * @author Ilya Volodin * @copyright 2013 Ilya Volodin. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ -// Rule Definition +// Helpers //------------------------------------------------------------------------------ -module.exports = function(context) { - var loopNodeTypes = [ - "ForStatement", - "WhileStatement", - "ForInStatement", - "ForOfStatement", - "DoWhileStatement" - ]; +/** + * Gets the containing loop node of a specified node. + * + * We don't need to check nested functions, so this ignores those. + * `Scope.through` contains references of nested functions. + * + * @param {ASTNode} node - An AST node to get. + * @returns {ASTNode|null} The containing loop node of the specified node, or `null`. + */ +function getContainingLoopNode(node) { + var parent = node.parent; + while (parent) { + switch (parent.type) { + case "WhileStatement": + case "DoWhileStatement": + return parent; - /** - * Checks if the given node is a loop. - * @param {ASTNode} node The AST node to check. - * @returns {boolean} Whether or not the node is a loop. - */ - function isLoop(node) { - return loopNodeTypes.indexOf(node.type) > -1; + case "ForStatement": + // `init` is outside of the loop. + if (parent.init !== node) { + return parent; + } + break; + + case "ForInStatement": + case "ForOfStatement": + // `right` is outside of the loop. + if (parent.right !== node) { + return parent; + } + break; + + case "ArrowFunctionExpression": + case "FunctionExpression": + case "FunctionDeclaration": + // We don't need to check nested functions. + return null; + + default: + break; + } + + node = parent; + parent = node.parent; } + return null; +} + +/** + * Checks whether or not a reference refers to a variable that is block-binding in the loop. + * @param {ASTNode} loopNode - A containing loop node. + * @param {escope.Reference} reference - A reference to check. + * @returns {boolean} Whether or not a reference refers to a variable that is block-binding in the loop. + */ +function isBlockBindingsInLoop(loopNode, reference) { + // A reference to a `let`/`const` variable always has a resolved variable. + var variable = reference.resolved; + var definition = variable && variable.defs[0]; + var declaration = definition && definition.parent; + + return ( + // Checks whether this is `let`/`const`. + declaration && + declaration.type === "VariableDeclaration" && + (declaration.kind === "let" || declaration.kind === "const") && + // Checks whether this is in the loop. + declaration.range[0] > loopNode.range[0] && + declaration.range[1] < loopNode.range[1] + ); +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { /** - * Reports if the given node has an ancestor node which is a loop. + * Reports such functions: + * + * - has an ancestor node which is a loop. + * - has a reference that refers to a variable that is block-binding in the loop. + * * @param {ASTNode} node The AST node to check. * @returns {boolean} Whether or not the node is within a loop. */ function checkForLoops(node) { - var ancestors = context.getAncestors(); + var loopNode = getContainingLoopNode(node); + if (!loopNode) { + return; + } - if (ancestors.some(isLoop)) { + var references = context.getScope().through; + if (references.length > 0 && !references.every(isBlockBindingsInLoop.bind(null, loopNode))) { context.report(node, "Don't make functions within a loop"); } } return { @@ -23830,12 +33575,146 @@ "FunctionExpression": checkForLoops, "FunctionDeclaration": checkForLoops }; }; -},{}],207:[function(require,module,exports){ +module.exports.schema = []; + +},{}],216:[function(require,module,exports){ /** + * @fileoverview Rule to flag statements that use magic numbers (adapted from https://github.com/danielstjules/buddy.js) + * @author Vincent Lemeunier + * @copyright 2015 Vincent Lemeunier. All rights reserved. + * + * This rule was adapted from danielstjules/buddy.js + * The MIT License (MIT) + * + * Copyright (c) 2014 Daniel St. Jules + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * See LICENSE file in root directory for full license. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var config = context.options[0] || {}, + ignore = config.ignore || [0, 1, 2], + detectObjects = !!config.detectObjects, + enforceConst = !!config.enforceConst; + + /** + * Returns whether the node is number literal + * @param {Node} node - the node literal being evaluated + * @returns {boolean} true if the node is a number literal + */ + function isNumber(node) { + return typeof node.value === "number"; + } + + /** + * Returns whether the number should be ignored + * @param {number} num - the number + * @returns {boolean} true if the number should be ignored + */ + function shouldIgnoreNumber(num) { + return ignore.indexOf(num) !== -1; + } + + + return { + "Literal": function(node) { + var parent = node.parent, + value = node.value, + raw = node.raw, + okTypes = detectObjects ? [] : ["ObjectExpression", "Property", "AssignmentExpression"]; + + if (!isNumber(node)) { + return; + } + + if (parent.type === "UnaryExpression" && parent.operator === "-") { + node = parent; + parent = node.parent; + value = -value; + raw = "-" + raw; + } + + if (shouldIgnoreNumber(value)) { + return; + } + + // don't warn on parseInt() or Number.parseInt() radix + if (parent.type === "CallExpression" && node === parent.arguments[1] && + (parent.callee.name === "parseInt" || + parent.callee.type === "MemberExpression" && + parent.callee.object.name === "Number" && + parent.callee.property.name === "parseInt") + ) { + return; + } + + if (parent.type === "VariableDeclarator") { + if (enforceConst && parent.parent.kind !== "const") { + context.report({ + node: node, + message: "Number constants declarations must use 'const'" + }); + } + } else if (okTypes.indexOf(parent.type) === -1) { + context.report({ + node: node, + message: "No magic number: " + raw + }); + } + } + }; +}; + +module.exports.schema = [{ + "type": "object", + "properties": { + "detectObjects": { + "type": "boolean" + }, + "enforceConst": { + "type": "boolean" + }, + "ignore": { + "type": "array", + "items": { + "type": "number" + }, + "uniqueItems": true + } + }, + "additionalProperties": false +}]; + +},{}],217:[function(require,module,exports){ +/** * @fileoverview Rule to enforce grouped require statements for Node.JS * @author Raphael Pigulla */ "use strict"; @@ -23851,17 +33730,17 @@ * * @returns {string[]} An array of built-in Node.js modules. */ function getBuiltinModules() { // This list is generated using `require("repl")._builtinLibs.concat('repl').sort()` - // This particular list was generated using node v0.11.9 + // This particular list is as per nodejs v0.12.2 and iojs v0.7.1 return [ "assert", "buffer", "child_process", "cluster", "crypto", "dgram", "dns", "domain", "events", "fs", "http", "https", "net", "os", "path", "punycode", "querystring", "readline", "repl", "smalloc", "stream", "string_decoder", "tls", "tty", - "url", "util", "vm", "zlib" + "url", "util", "v8", "vm", "zlib" ]; } var BUILTIN_MODULES = getBuiltinModules(); @@ -23940,11 +33819,11 @@ * @returns {boolean} True if the declarations are mixed, false if not. */ function isMixed(declarations) { var contains = {}; - declarations.forEach(function (declaration) { + declarations.forEach(function(declaration) { var type = getDeclarationType(declaration.init); contains[type] = true; }); return !!( @@ -23960,11 +33839,11 @@ * @returns {boolean} True if the declarations are grouped, false if not. */ function isGrouped(declarations) { var found = {}; - declarations.forEach(function (declaration) { + declarations.forEach(function(declaration) { if (getDeclarationType(declaration.init) === DECL_REQUIRE) { found[inferModuleType(declaration.init)] = true; } }); @@ -23973,12 +33852,18 @@ return { "VariableDeclaration": function(node) { - var grouping = !!context.options[0]; + var grouping = false; + if (typeof context.options[0] === "object") { + grouping = context.options[0].grouping; + } else { + grouping = !!context.options[0]; + } + if (isMixed(node.declarations)) { context.report( node, "Do not mix 'require' and other declarations." ); @@ -23991,55 +33876,124 @@ } }; }; -},{}],208:[function(require,module,exports){ +module.exports.schema = [ + { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "grouping": { + "type": "boolean" + } + }, + "additionalProperties": false + } + ] + } +]; + +},{}],218:[function(require,module,exports){ /** * @fileoverview Disallow mixed spaces and tabs for indentation * @author Jary Niebur * @copyright 2014 Nicholas C. Zakas. All rights reserved. * @copyright 2014 Jary Niebur. All rights reserved. + * See LICENSE in root directory for full license. */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var smartTabs; + var smartTabs, + ignoredLocs = []; switch (context.options[0]) { case true: // Support old syntax, maybe add deprecation warning here case "smart-tabs": smartTabs = true; break; default: smartTabs = false; } - var COMMENT_START = /^\s*\/\*/, - MAYBE_COMMENT = /^\s*\*/; + /** + * Determines if a given line and column are before a location. + * @param {Location} loc The location object from an AST node. + * @param {int} line The line to check. + * @param {int} column The column to check. + * @returns {boolean} True if the line and column are before the location, false if not. + * @private + */ + function beforeLoc(loc, line, column) { + if (line < loc.start.line) { + return true; + } + return line === loc.start.line && column < loc.start.column; + } + /** + * Determines if a given line and column are after a location. + * @param {Location} loc The location object from an AST node. + * @param {int} line The line to check. + * @param {int} column The column to check. + * @returns {boolean} True if the line and column are after the location, false if not. + * @private + */ + function afterLoc(loc, line, column) { + if (line > loc.end.line) { + return true; + } + return line === loc.end.line && column > loc.end.column; + } + //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- return { - "Program": function(node) { + "TemplateElement": function(node) { + ignoredLocs.push(node.loc); + }, + + "Program:exit": function(node) { /* * At least one space followed by a tab * or the reverse before non-tab/-space * characters begin. */ var regex = /^(?=[\t ]*(\t | \t))/, match, - lines = context.getSourceLines(); + lines = context.getSourceLines(), + comments = context.getAllComments(); + comments.forEach(function(comment) { + ignoredLocs.push(comment.loc); + }); + + ignoredLocs.sort(function(first, second) { + if (beforeLoc(first, second.start.line, second.start.column)) { + return 1; + } + + if (beforeLoc(second, first.start.line, second.start.column)) { + return -1; + } + + return 0; + }); + if (smartTabs) { /* * At least one space followed by a tab * before non-tab/-space characters begin. */ @@ -24048,24 +34002,40 @@ lines.forEach(function(line, i) { match = regex.exec(line); if (match) { + var lineNumber = i + 1, + column = match.index + 1; - if (!MAYBE_COMMENT.test(line) && !COMMENT_START.test(lines[i - 1])) { - context.report(node, { line: i + 1, column: match.index + 1 }, "Mixed spaces and tabs."); + for (var j = 0; j < ignoredLocs.length; j++) { + if (beforeLoc(ignoredLocs[j], lineNumber, column)) { + continue; + } + if (afterLoc(ignoredLocs[j], lineNumber, column)) { + continue; + } + + return; } + context.report(node, { line: lineNumber, column: column }, "Mixed spaces and tabs."); } }); } }; }; -},{}],209:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["smart-tabs", true, false] + } +]; + +},{}],219:[function(require,module,exports){ /** * @fileoverview Disallow use of multiple spaces. * @author Nicholas C. Zakas * @copyright 2015 Brandon Mills. All rights reserved. * @copyright 2015 Nicholas C. Zakas. All rights reserved. @@ -24084,11 +34054,11 @@ hasExceptions = true, options = context.options[0], lastCommentIndex = 0; if (options && options.exceptions) { - Object.keys(options.exceptions).forEach(function (key) { + Object.keys(options.exceptions).forEach(function(key) { if (options.exceptions[key]) { exceptions[key] = true; } else { delete exceptions[key]; } @@ -24136,39 +34106,77 @@ var source = context.getSource(), allComments = context.getAllComments(), pattern = /[^\n\r\u2028\u2029 ] {2,}/g, // note: repeating space token, + previousToken, parent; + + /** + * Creates a fix function that removes the multiple spaces between the two tokens + * @param {RuleFixer} leftToken left token + * @param {RuleFixer} rightToken right token + * @returns {function} fix function + * @private + */ + function createFix(leftToken, rightToken) { + return function(fixer) { + return fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], " "); + }; + } + while (pattern.test(source)) { // do not flag anything inside of comments if (!isIndexInComment(pattern.lastIndex, allComments)) { token = context.getTokenByRangeStart(pattern.lastIndex); - if (token) { + previousToken = context.getTokenBefore(token); + if (hasExceptions) { parent = context.getNodeByRangeIndex(pattern.lastIndex - 1); } if (!parent || !exceptions[parent.type]) { - context.report(token, token.loc.start, - "Multiple spaces found before '{{value}}'.", - { value: token.value }); + context.report({ + node: token, + loc: token.loc.start, + message: "Multiple spaces found before '{{value}}'.", + data: { value: token.value }, + fix: createFix(previousToken, token) + }); } } } } } }; }; -},{}],210:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "exceptions": { + "type": "object", + "patternProperties": { + "^([A-Z][a-z]*)+$": { + "type": "boolean" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } +]; + +},{}],220:[function(require,module,exports){ /** * @fileoverview Rule to flag when using multiline strings * @author Ilya Volodin * @copyright 2014 Nicholas C. Zakas. All rights reserved. * @copyright 2013 Ilya Volodin. All rights reserved. @@ -24207,11 +34215,13 @@ } }; }; -},{}],211:[function(require,module,exports){ +module.exports.schema = []; + +},{}],221:[function(require,module,exports){ /** * @fileoverview Disallows multiple blank lines. * implementation adapted from the no-trailing-spaces rule. * @author Greg Cochard * @copyright 2014 Greg Cochard. All rights reserved. @@ -24223,57 +34233,121 @@ //------------------------------------------------------------------------------ module.exports = function(context) { // Use options.max or 2 as default - var numLines = 2; + var max = 2, + maxEOF; + // store lines that appear empty but really aren't + var notEmpty = []; + if (context.options.length) { - numLines = context.options[0].max; + max = context.options[0].max; + maxEOF = context.options[0].maxEOF; } //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- return { - "Program": function checkBlankLines(node) { + "TemplateLiteral": function(node) { + var start = node.loc.start.line; + var end = node.loc.end.line; + while (start <= end) { + notEmpty.push(start); + start++; + } + }, + + "Program:exit": function checkBlankLines(node) { var lines = context.getSourceLines(), currentLocation = -1, lastLocation, blankCounter = 0, location, trimmedLines = lines.map(function(str) { return str.trim(); - }); + }), + firstOfEndingBlankLines; + // add the notEmpty lines in there with a placeholder + notEmpty.forEach(function(x, i) { + trimmedLines[i] = x; + }); + + if (typeof maxEOF === "undefined") { + // swallow the final newline, as some editors add it + // automatically and we don't want it to cause an issue + if (trimmedLines[trimmedLines.length - 1] === "") { + trimmedLines = trimmedLines.slice(0, -1); + } + firstOfEndingBlankLines = trimmedLines.length; + } else { + // save the number of the first of the last blank lines + firstOfEndingBlankLines = trimmedLines.length; + while (trimmedLines[firstOfEndingBlankLines - 1] === "" + && firstOfEndingBlankLines > 0) { + firstOfEndingBlankLines--; + } + } + // Aggregate and count blank lines - do { + lastLocation = currentLocation; + currentLocation = trimmedLines.indexOf("", currentLocation + 1); + while (currentLocation !== -1) { lastLocation = currentLocation; currentLocation = trimmedLines.indexOf("", currentLocation + 1); if (lastLocation === currentLocation - 1) { blankCounter++; } else { - if (blankCounter >= numLines) { - location = { - line: lastLocation + 1, - column: lines[lastLocation].length - }; - context.report(node, location, "Multiple blank lines not allowed."); + location = { + line: lastLocation + 1, + column: 1 + }; + if (lastLocation < firstOfEndingBlankLines) { + // within the file, not at the end + if (blankCounter >= max) { + context.report(node, location, + "More than " + max + " blank " + (max === 1 ? "line" : "lines") + " not allowed."); + } + } else { + // inside the last blank lines + if (blankCounter >= maxEOF) { + context.report(node, location, + "Too many blank lines at the end of file. Max of " + maxEOF + " allowed."); + } } // Finally, reset the blank counter blankCounter = 0; } - } while (currentLocation !== -1); + } } }; }; -},{}],212:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "max": { + "type": "integer" + }, + "maxEOF": { + "type": "integer" + } + }, + "required": ["max"], + "additionalProperties": false + } +]; + +},{}],222:[function(require,module,exports){ /** * @fileoverview Rule to flag when re-assigning native objects * @author Ilya Volodin */ @@ -24283,36 +34357,158 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var nativeObjects = ["Array", "Boolean", "Date", "decodeURI", - "decodeURIComponent", "encodeURI", "encodeURIComponent", - "Error", "eval", "EvalError", "Function", "isFinite", - "isNaN", "JSON", "Math", "Number", "Object", "parseInt", - "parseFloat", "RangeError", "ReferenceError", "RegExp", - "String", "SyntaxError", "TypeError", "URIError", - "Map", "NaN", "Set", "WeakMap", "Infinity", "undefined"]; + var config = context.options[0]; + var exceptions = (config && config.exceptions) || []; + /** + * Gets the names of writeable built-in variables. + * @param {escope.Scope} scope - A scope to get. + * @returns {object} A map that its key is variable names. + */ + function getBuiltinGlobals(scope) { + return scope.variables.reduce(function(retv, variable) { + if (variable.writeable === false && variable.name !== "__proto__") { + retv[variable.name] = true; + } + return retv; + }, Object.create(null)); + } + + /** + * Reports if a given reference's name is same as native object's. + * @param {object} builtins - A map that its key is a variable name. + * @param {Reference} reference - A reference to check. + * @param {int} index - The index of the reference in the references. + * @param {Reference[]} references - The array that the reference belongs to. + * @returns {void} + */ + function checkThroughReference(builtins, reference, index, references) { + var identifier = reference.identifier; + + if (identifier && + builtins[identifier.name] && + exceptions.indexOf(identifier.name) === -1 && + reference.init === false && + reference.isWrite() && + // Destructuring assignments can have multiple default value, + // so possibly there are multiple writeable references for the same identifier. + (index === 0 || references[index - 1].identifier !== identifier) + ) { + context.report( + identifier, + "{{name}} is a read-only native object.", + {name: identifier.name}); + } + } + return { + // Checks assignments of global variables. + // References to implicit global variables are not resolved, + // so those are in the `through` of the global scope. + "Program": function() { + var globalScope = context.getScope(); + var builtins = getBuiltinGlobals(globalScope); + globalScope.through.forEach(checkThroughReference.bind(null, builtins)); + } + }; - "AssignmentExpression": function(node) { - if (nativeObjects.indexOf(node.left.name) >= 0) { - context.report(node, node.left.name + " is a read-only native object."); +}; + +module.exports.schema = [ + { + "type": "object", + "properties": { + "exceptions": { + "type": "array", + "items": {"type": "string"}, + "uniqueItems": true } }, + "additionalProperties": false + } +]; - "VariableDeclarator": function(node) { - if (nativeObjects.indexOf(node.id.name) >= 0) { - context.report(node, "Redefinition of '{{nativeObject}}'.", { nativeObject: node.id.name }); +},{}],223:[function(require,module,exports){ +/** + * @fileoverview Rule to disallow a negated condition + * @author Alberto Rodríguez + * @copyright 2015 Alberto Rodríguez. All rights reserved. + * See LICENSE file in root directory for full license. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + /** + * Determines if a given node is an if-else without a condition on the else + * @param {ASTNode} node The node to check. + * @returns {boolean} True if the node has an else without an if. + * @private + */ + function hasElseWithoutCondition(node) { + return node.alternate && node.alternate.type !== "IfStatement"; + } + + /** + * Determines if a given node is a negated unary expression + * @param {Object} test The test object to check. + * @returns {boolean} True if the node is a negated unary expression. + * @private + */ + function isNegatedUnaryExpression(test) { + return test.type === "UnaryExpression" && test.operator === "!"; + } + + /** + * Determines if a given node is a negated binary expression + * @param {Test} test The test to check. + * @returns {boolean} True if the node is a negated binary expression. + * @private + */ + function isNegatedBinaryExpression(test) { + return test.type === "BinaryExpression" && + (test.operator === "!=" || test.operator === "!=="); + } + + /** + * Determines if a given node has a negated if expression + * @param {ASTNode} node The node to check. + * @returns {boolean} True if the node has a negated if expression. + * @private + */ + function isNegatedIf(node) { + return isNegatedUnaryExpression(node.test) || isNegatedBinaryExpression(node.test); + } + + return { + "IfStatement": function(node) { + if (!hasElseWithoutCondition(node)) { + return; } + + if (isNegatedIf(node)) { + context.report(node, "Unexpected negated condition."); + } + }, + "ConditionalExpression": function(node) { + if (isNegatedIf(node)) { + context.report(node, "Unexpected negated condition."); + } } }; - }; -},{}],213:[function(require,module,exports){ +module.exports.schema = []; + +},{}],224:[function(require,module,exports){ /** * @fileoverview A rule to disallow negated left operands of the `in` operator * @author Michael Ficarra */ @@ -24333,11 +34529,13 @@ } }; }; -},{}],214:[function(require,module,exports){ +module.exports.schema = []; + +},{}],225:[function(require,module,exports){ /** * @fileoverview Rule to flag nested ternary expressions * @author Ian Christian Myers */ @@ -24357,11 +34555,13 @@ } } }; }; -},{}],215:[function(require,module,exports){ +module.exports.schema = []; + +},{}],226:[function(require,module,exports){ /** * @fileoverview Rule to flag when using new Function * @author Ilya Volodin */ @@ -24371,22 +34571,36 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - return { + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- - "NewExpression": function(node) { - if (node.callee.name === "Function") { - context.report(node, "The Function constructor is eval."); - } + /** + * Checks if the callee if the Function constructor, and if so, reports an issue. + * @param {ASTNode} node The node to check and report on + * @returns {void} + * @private + */ + function validateCallee(node) { + if (node.callee.name === "Function") { + context.report(node, "The Function constructor is eval."); } + } + + return { + "NewExpression": validateCallee, + "CallExpression": validateCallee }; }; -},{}],216:[function(require,module,exports){ +module.exports.schema = []; + +},{}],227:[function(require,module,exports){ /** * @fileoverview A rule to disallow calls to the Object constructor * @author Matt DuVall <http://www.mattduvall.com/> */ @@ -24407,11 +34621,13 @@ } }; }; -},{}],217:[function(require,module,exports){ +module.exports.schema = []; + +},{}],228:[function(require,module,exports){ /** * @fileoverview Rule to disallow use of new operator with the `require` function * @author Wil Moore III */ @@ -24432,11 +34648,13 @@ } }; }; -},{}],218:[function(require,module,exports){ +module.exports.schema = []; + +},{}],229:[function(require,module,exports){ /** * @fileoverview Rule to flag when using constructor for wrapper objects * @author Ilya Volodin */ @@ -24458,11 +34676,13 @@ } }; }; -},{}],219:[function(require,module,exports){ +module.exports.schema = []; + +},{}],230:[function(require,module,exports){ /** * @fileoverview Rule to flag statements with function invocation preceded by * "new" and not part of assignment * @author Ilya Volodin */ @@ -24485,11 +34705,13 @@ } }; }; -},{}],220:[function(require,module,exports){ +module.exports.schema = []; + +},{}],231:[function(require,module,exports){ /** * @fileoverview Rule to flag use of an object property of the global object (Math and JSON) as a function * @author James Allardice */ @@ -24513,11 +34735,13 @@ } }; }; -},{}],221:[function(require,module,exports){ +module.exports.schema = []; + +},{}],232:[function(require,module,exports){ /** * @fileoverview Rule to flag octal escape sequences in string literals. * @author Ian Christian Myers */ @@ -24533,25 +34757,32 @@ "Literal": function(node) { if (typeof node.value !== "string") { return; } - var match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-7])/), + + var match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-3][0-7]{1,2}|[4-7][0-7]|[0-7])/), octalDigit; if (match) { octalDigit = match[2]; - context.report(node, "Don't use octal: '\\{{octalDigit}}'. Use '\\u....' instead.", - { octalDigit: octalDigit }); + + // \0 is actually not considered an octal + if (match[2] !== "0" || typeof match[3] !== "undefined") { + context.report(node, "Don't use octal: '\\{{octalDigit}}'. Use '\\u....' instead.", + { octalDigit: octalDigit }); + } } } }; }; -},{}],222:[function(require,module,exports){ +module.exports.schema = []; + +},{}],233:[function(require,module,exports){ /** * @fileoverview Rule to flag when initializing octal literal * @author Ilya Volodin */ @@ -24572,12 +34803,152 @@ } }; }; -},{}],223:[function(require,module,exports){ +module.exports.schema = []; + +},{}],234:[function(require,module,exports){ /** + * @fileoverview Disallow reassignment of function parameters. + * @author Nat Burns + * @copyright 2014 Nat Burns. All rights reserved. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +var stopNodePattern = /(?:Statement|Declaration|Function(?:Expression)?|Program)$/; + +module.exports = function(context) { + var props = context.options[0] && Boolean(context.options[0].props); + + /** + * Checks whether or not a reference modifies its variable. + * If the `props` option is `true`, this checks whether or not the reference modifies properties of its variable also. + * @param {Reference} reference - A reference to check. + * @returns {boolean} Whether or not the reference modifies its variable. + */ + function isModifying(reference) { + if (reference.isWrite()) { + return true; + } + + // Checks whether its property is modified. + if (props) { + var node = reference.identifier; + var parent = node.parent; + while (parent && !stopNodePattern.test(parent.type)) { + switch (parent.type) { + // e.g. foo.a = 0; + case "AssignmentExpression": + return parent.left === node; + + // e.g. ++foo.a; + case "UpdateExpression": + return true; + + // e.g. delete foo.a; + case "UnaryExpression": + if (parent.operator === "delete") { + return true; + } + break; + + // EXCLUDES: e.g. cache.get(foo.a).b = 0; + case "CallExpression": + if (parent.callee !== node) { + return false; + } + break; + + // EXCLUDES: e.g. cache[foo.a] = 0; + case "MemberExpression": + if (parent.property === node) { + return false; + } + break; + + default: + break; + } + + node = parent; + parent = parent.parent; + } + } + + return false; + } + + /** + * Reports a reference if is non initializer and writable. + * @param {Reference} reference - A reference to check. + * @param {int} index - The index of the reference in the references. + * @param {Reference[]} references - The array that the reference belongs to. + * @returns {void} + */ + function checkReference(reference, index, references) { + var identifier = reference.identifier; + + if (identifier && + !reference.init && + isModifying(reference) && + // Destructuring assignments can have multiple default value, + // so possibly there are multiple writeable references for the same identifier. + (index === 0 || references[index - 1].identifier !== identifier) + ) { + context.report( + identifier, + "Assignment to function parameter '{{name}}'.", + {name: identifier.name}); + } + } + + /** + * Finds and reports references that are non initializer and writable. + * @param {Variable} variable - A variable to check. + * @returns {void} + */ + function checkVariable(variable) { + if (variable.defs[0].type === "Parameter") { + variable.references.forEach(checkReference); + } + } + + /** + * Checks parameters of a given function node. + * @param {ASTNode} node - A function node to check. + * @returns {void} + */ + function checkForFunction(node) { + context.getDeclaredVariables(node).forEach(checkVariable); + } + + return { + // `:exit` is needed for the `node.parent` property of identifier nodes. + "FunctionDeclaration:exit": checkForFunction, + "FunctionExpression:exit": checkForFunction, + "ArrowFunctionExpression:exit": checkForFunction + }; + +}; + +module.exports.schema = [ + { + "type": "object", + "properties": { + "props": {"type": "boolean"} + }, + "additionalProperties": false + } +]; + +},{}],235:[function(require,module,exports){ +/** * @fileoverview Disallow string concatenation when using __dirname and __filename * @author Nicholas C. Zakas */ "use strict"; @@ -24611,35 +34982,60 @@ }; }; -},{}],224:[function(require,module,exports){ +module.exports.schema = []; + +},{}],236:[function(require,module,exports){ /** * @fileoverview Rule to flag use of unary increment and decrement operators. * @author Ian Christian Myers + * @author Brody McKee (github.com/mrmckeb) */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var config = context.options[0], + allowInForAfterthought = false; + + if (typeof config === "object") { + allowInForAfterthought = config.allowForLoopAfterthoughts === true; + } + return { "UpdateExpression": function(node) { + if (allowInForAfterthought && node.parent.type === "ForStatement") { + return; + } context.report(node, "Unary operator '" + node.operator + "' used."); } }; }; -},{}],225:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "allowForLoopAfterthoughts": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{}],237:[function(require,module,exports){ /** * @fileoverview Disallow the use of process.env() * @author Vignesh Anand * @copyright 2014 Vignesh Anand. All rights reserved. */ @@ -24665,11 +35061,13 @@ }; }; -},{}],226:[function(require,module,exports){ +module.exports.schema = []; + +},{}],238:[function(require,module,exports){ /** * @fileoverview Disallow the use of process.exit() * @author Nicholas C. Zakas */ "use strict"; @@ -24698,11 +35096,13 @@ }; }; -},{}],227:[function(require,module,exports){ +module.exports.schema = []; + +},{}],239:[function(require,module,exports){ /** * @fileoverview Rule to flag usage of __proto__ property * @author Ilya Volodin */ @@ -24726,11 +35126,13 @@ } }; }; -},{}],228:[function(require,module,exports){ +module.exports.schema = []; + +},{}],240:[function(require,module,exports){ /** * @fileoverview Rule to flag when the same variable is declared more then once. * @author Ilya Volodin */ @@ -24739,35 +35141,93 @@ //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var options = { + builtinGlobals: Boolean(context.options[0] && context.options[0].builtinGlobals) + }; - function findVariables() { - var scope = context.getScope(); - + /** + * Find variables in a given scope and flag redeclared ones. + * @param {Scope} scope - An escope scope object. + * @returns {void} + * @private + */ + function findVariablesInScope(scope) { scope.variables.forEach(function(variable) { - if (variable.identifiers && variable.identifiers.length > 1) { + var hasBuiltin = options.builtinGlobals && "writeable" in variable; + var count = (hasBuiltin ? 1 : 0) + variable.identifiers.length; + + if (count >= 2) { variable.identifiers.sort(function(a, b) { return a.range[1] - b.range[1]; }); - for (var i = 1, l = variable.identifiers.length; i < l; i++) { - context.report(variable.identifiers[i], "{{a}} is already defined", {a: variable.name}); + for (var i = (hasBuiltin ? 0 : 1), l = variable.identifiers.length; i < l; i++) { + context.report( + variable.identifiers[i], + "\"{{a}}\" is already defined", + {a: variable.name}); } } }); + } - return { - "Program": findVariables, - "FunctionExpression": findVariables, - "FunctionDeclaration": findVariables - }; + /** + * Find variables in the current scope. + * @returns {void} + * @private + */ + function checkForGlobal() { + var scope = context.getScope(); + + // Nodejs env or modules has a special scope. + if (context.ecmaFeatures.globalReturn || context.ecmaFeatures.modules) { + findVariablesInScope(scope.childScopes[0]); + } else { + findVariablesInScope(scope); + } + } + + /** + * Find variables in the current scope. + * @returns {void} + * @private + */ + function checkForBlock() { + findVariablesInScope(context.getScope()); + } + + if (context.ecmaFeatures.blockBindings) { + return { + "Program": checkForGlobal, + "BlockStatement": checkForBlock, + "SwitchStatement": checkForBlock + }; + } else { + return { + "Program": checkForGlobal, + "FunctionDeclaration": checkForBlock, + "FunctionExpression": checkForBlock, + "ArrowFunctionExpression": checkForBlock + }; + } }; -},{}],229:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "builtinGlobals": {"type": "boolean"} + }, + "additionalProperties": false + } +]; + +},{}],241:[function(require,module,exports){ /** * @fileoverview Rule to count multiple spaces in regular expressions * @author Matt DuVall <http://www.mattduvall.com/> */ @@ -24798,78 +35258,24 @@ } }; }; -},{}],230:[function(require,module,exports){ -/** - * @fileoverview Rule to disallow reserved words being used as keys - * @author Emil Bay - * @copyright 2014 Emil Bay. All rights reserved. - */ +module.exports.schema = []; -"use strict"; - -//------------------------------------------------------------------------------ -// Rule Definition -//------------------------------------------------------------------------------ - -module.exports = function(context) { - - var MESSAGE = "Reserved word '{{key}}' used as key."; - - var reservedWords = [ - "abstract", - "boolean", "break", "byte", - "case", "catch", "char", "class", "const", "continue", - "debugger", "default", "delete", "do", "double", - "else", "enum", "export", "extends", - "final", "finally", "float", "for", "function", - "goto", - "if", "implements", "import", "in", "instanceof", "int", "interface", - "long", - "native", "new", - "package", "private", "protected", "public", - "return", - "short", "static", "super", "switch", "synchronized", - "this", "throw", "throws", "transient", "try", "typeof", - "var", "void", "volatile", - "while", "with" - ]; - - return { - - "ObjectExpression": function(node) { - node.properties.forEach(function(property) { - - if (property.key.type === "Identifier") { - var keyName = property.key.name; - - if (reservedWords.indexOf("" + keyName) !== -1) { - context.report(node, MESSAGE, { key: keyName }); - } - } - - }); - - } - }; - -}; - -},{}],231:[function(require,module,exports){ +},{}],242:[function(require,module,exports){ /** * @fileoverview Restrict usage of specified node modules. * @author Christian Schulz */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = function (context) { +module.exports = function(context) { // trim restricted module names var restrictedModules = context.options; // if no modules are restricted we don't need to check the CallExpressions if (restrictedModules.length === 0) { @@ -24914,11 +35320,11 @@ return moduleName; } return { - "CallExpression": function (node) { + "CallExpression": function(node) { if (isRequireCall(node)) { var restrictedModuleName = getRestrictedModuleName(node); if (restrictedModuleName) { context.report(node, "'{{moduleName}}' module is restricted from being used.", { @@ -24928,41 +35334,133 @@ } } }; }; -},{}],232:[function(require,module,exports){ +module.exports.schema = { + "type": "array", + "items": [ + { + "enum": [0, 1, 2] + } + ], + "additionalItems": { + "type": "string" + }, + "uniqueItems": true +}; + +},{}],243:[function(require,module,exports){ /** + * @fileoverview Rule to flag use of certain node types + * @author Burak Yigit Kaya + * @copyright 2015 Burak Yigit Kaya. All rights reserved. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +var nodeTypes = require("espree").Syntax; + +module.exports = function(context) { + /** + * Generates a warning from the provided node, saying that node type is not allowed. + * @param {ASTNode} node The node to warn on + * @returns {void} + */ + function warn(node) { + context.report(node, "Using \"{{type}}\" is not allowed.", node); + } + + return context.options.reduce(function(result, nodeType) { + result[nodeType] = warn; + + return result; + }, {}); + +}; + +module.exports.schema = { + "type": "array", + "items": [ + { + "enum": [0, 1, 2] + }, + { + "enum": Object.keys(nodeTypes).map(function(k) { + return nodeTypes[k]; + }) + } + ], + "uniqueItems": true, + "minItems": 1 +}; + +},{"espree":"espree"}],244:[function(require,module,exports){ +/** * @fileoverview Rule to flag when return statement contains assignment * @author Ilya Volodin */ "use strict"; //------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Checks whether or not a node is an `AssignmentExpression`. + * @param {Node|null} node - A node to check. + * @returns {boolean} Whether or not the node is an `AssignmentExpression`. + */ +function isAssignment(node) { + return node && node.type === "AssignmentExpression"; +} + +/** + * Checks whether or not a node is enclosed in parentheses. + * @param {Node|null} node - A node to check. + * @param {RuleContext} context - The current context. + * @returns {boolean} Whether or not the node is enclosed in parentheses. + */ +function isEnclosedInParens(node, context) { + var prevToken = context.getTokenBefore(node); + var nextToken = context.getTokenAfter(node); + + return prevToken.value === "(" && nextToken.value === ")"; +} + +//------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var always = (context.options[0] || "except-parens") !== "except-parens"; return { - "ReturnStatement": function(node) { - if (node.argument && node.argument.type === "AssignmentExpression") { + if (isAssignment(node.argument) && (always || !isEnclosedInParens(node.argument, context))) { context.report(node, "Return statement should not contain assignment."); } } }; - }; -},{}],233:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["except-parens", "always"] + } +]; + +},{}],245:[function(require,module,exports){ /** * @fileoverview Rule to flag when using javascript: urls * @author Ilya Volodin */ -/*jshint scripturl: true */ -/*eslint no-script-url: 0*/ +/* jshint scripturl: true */ +/* eslint no-script-url: 0 */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition @@ -24986,11 +35484,13 @@ } }; }; -},{}],234:[function(require,module,exports){ +module.exports.schema = []; + +},{}],246:[function(require,module,exports){ /** * @fileoverview Rule to flag comparison where left part is the same as the right * part. * @author Ilya Volodin */ @@ -25015,11 +35515,13 @@ } }; }; -},{}],235:[function(require,module,exports){ +module.exports.schema = []; + +},{}],247:[function(require,module,exports){ /** * @fileoverview Rule to flag use of comma operator * @author Brandon Mills */ @@ -25052,11 +35554,11 @@ * parens, e.g. the test of an if statement. * @param {ASTNode} node - The AST node * @returns {boolean} True if parens around node belong to parent node. */ function requiresExtraParens(node) { - return node.parent && parenthesized[node.parent.type] != null && + return node.parent && parenthesized[node.parent.type] && node === node.parent[parenthesized[node.parent.type]]; } /** * Check if a node is wrapped in parens. @@ -25103,17 +35605,20 @@ if (isParenthesised(node)) { return; } } - context.report(node, "Unexpected use of comma operator."); + var child = context.getTokenAfter(node.expressions[0]); + context.report(node, child.loc.start, "Unexpected use of comma operator."); } }; }; -},{}],236:[function(require,module,exports){ +module.exports.schema = []; + +},{}],248:[function(require,module,exports){ /** * @fileoverview Disallow shadowing of NaN, undefined, and Infinity (ES5 section 15.1.1) * @author Michael Ficarra * @copyright 2013 Michael Ficarra. All rights reserved. */ @@ -25125,10 +35630,16 @@ module.exports = function(context) { var RESTRICTED = ["undefined", "NaN", "Infinity", "arguments", "eval"]; + /** + * Check if the node name is present inside the restricted list + * @param {ASTNode} id id to evaluate + * @returns {void} + * @private + */ function checkForViolation(id) { if (RESTRICTED.indexOf(id.name) > -1) { context.report(id, "Shadowing of global property \"" + id.name + "\"."); } } @@ -25148,190 +35659,200 @@ checkForViolation(node.id); } [].map.call(node.params, checkForViolation); }, "FunctionDeclaration": function(node) { - checkForViolation(node.id); - [].map.call(node.params, checkForViolation); + if (node.id) { + checkForViolation(node.id); + [].map.call(node.params, checkForViolation); + } }, "CatchClause": function(node) { checkForViolation(node.param); } }; }; -},{}],237:[function(require,module,exports){ +module.exports.schema = []; + +},{}],249:[function(require,module,exports){ /** * @fileoverview Rule to flag on declaring variables already declared in the outer scope * @author Ilya Volodin * @copyright 2013 Ilya Volodin. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ -// Rule Definition +// Requirements //------------------------------------------------------------------------------ -module.exports = function(context) { +var astUtils = require("../ast-utils"); - /** - * Checks if a variable is contained in the list of given scope variables. - * @param {Object} variable The variable to check. - * @param {Array} scopeVars The scope variables to look for. - * @returns {boolean} Whether or not the variable is contains in the list of scope variables. - */ - function isContainedInScopeVars(variable, scopeVars) { - return scopeVars.some(function (scopeVar) { - if (scopeVar.identifiers.length > 0) { - return variable.name === scopeVar.name; - } - return false; - }); - } - - /** - * Checks if the given variables are shadowed in the given scope. - * @param {Array} variables The variables to look for - * @param {Object} scope The scope to be checked. - * @returns {void} - */ - function checkShadowsInScope(variables, scope) { - variables.forEach(function (variable) { - if (isContainedInScopeVars(variable, scope.variables) && - // "arguments" is a special case that has no identifiers (#1759) - variable.identifiers.length > 0 - ) { - - context.report(variable.identifiers[0], "{{a}} is already declared in the upper scope.", {a: variable.name}); - } - }); - } - - /** - * Checks the current context for shadowed variables. - * @returns {void} - */ - function checkForShadows() { - var scope = context.getScope(), - variables = scope.variables; - - // iterate through the array of variables and find duplicates with the upper scope - var upper = scope.upper; - while (upper) { - checkShadowsInScope(variables, upper); - upper = upper.upper; - } - } - - return { - "FunctionDeclaration": checkForShadows, - "FunctionExpression": checkForShadows - }; - -}; - -},{}],238:[function(require,module,exports){ -/** - * @fileoverview Rule to disallow whitespace before the semicolon - * @author Jonathan Kingston - * @copyright 2015 Mathias Schreck - * @copyright 2014 Jonathan Kingston - */ - -"use strict"; - //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var options = { + builtinGlobals: Boolean(context.options[0] && context.options[0].builtinGlobals), + hoist: (context.options[0] && context.options[0].hoist) || "functions", + allow: (context.options[0] && context.options[0].allow) || [] + }; + /** - * Determines whether two adjacent tokens are have whitespace between them. - * @param {Object} left - The left token object. - * @param {Object} right - The right token object. - * @returns {boolean} Whether or not there is space between the tokens. + * Check if variable name is allowed. + * + * @param {ASTNode} variable The variable to check. + * @returns {boolean} Whether or not the variable name is allowed. */ - function isSpaced(left, right) { - return left.range[1] < right.range[0]; + function isAllowed(variable) { + return options.allow.indexOf(variable.name) !== -1; } /** - * Checks whether two tokens are on the same line. - * @param {Object} left The leftmost token. - * @param {Object} right The rightmost token. - * @returns {boolean} True if the tokens are on the same line, false if not. - * @private + * Checks if a variable of the class name in the class scope of ClassDeclaration. + * + * ClassDeclaration creates two variables of its name into its outer scope and its class scope. + * So we should ignore the variable in the class scope. + * + * @param {Object} variable The variable to check. + * @returns {boolean} Whether or not the variable of the class name in the class scope of ClassDeclaration. */ - function isSameLine(left, right) { - return left.loc.end.line === right.loc.start.line; + function isDuplicatedClassNameVariable(variable) { + var block = variable.scope.block; + return block.type === "ClassDeclaration" && block.id === variable.identifiers[0]; } /** - * Checks if a given token has leading whitespace. - * @param {Object} token The token to check. - * @returns {boolean} True if the given token has leading space, false if not. + * Checks if a variable is inside the initializer of scopeVar. + * + * To avoid reporting at declarations such as `var a = function a() {};`. + * But it should report `var a = function(a) {};` or `var a = function() { function a() {} };`. + * + * @param {Object} variable The variable to check. + * @param {Object} scopeVar The scope variable to look for. + * @returns {boolean} Whether or not the variable is inside initializer of scopeVar. */ - function hasLeadingSpace(token) { - var tokenBefore = context.getTokenBefore(token); - return isSameLine(tokenBefore, token) && isSpaced(tokenBefore, token); + function isOnInitializer(variable, scopeVar) { + var outerScope = scopeVar.scope; + var outerDef = scopeVar.defs[0]; + var outer = outerDef && outerDef.parent && outerDef.parent.range; + var innerScope = variable.scope; + var innerDef = variable.defs[0]; + var inner = innerDef && innerDef.name.range; + + return ( + outer && + inner && + outer[0] < inner[0] && + inner[1] < outer[1] && + ((innerDef.type === "FunctionName" && innerDef.node.type === "FunctionExpression") || innerDef.node.type === "ClassExpression") && + outerScope === innerScope.upper + ); } /** - * Checks if the given token is a semicolon. - * @param {Token} token The token to check. - * @returns {boolean} Whether or not the given token is a semicolon. + * Get a range of a variable's identifier node. + * @param {Object} variable The variable to get. + * @returns {Array|undefined} The range of the variable's identifier node. */ - function isSemicolon(token) { - return token.type === "Punctuator" && token.value === ";"; + function getNameRange(variable) { + var def = variable.defs[0]; + return def && def.name.range; } /** - * Reports if the given token has leading space. - * @param {Token} token The semicolon token to check. - * @param {ASTNode} node The corresponding node of the token. - * @returns {void} + * Checks if a variable is in TDZ of scopeVar. + * @param {Object} variable The variable to check. + * @param {Object} scopeVar The variable of TDZ. + * @returns {boolean} Whether or not the variable is in TDZ of scopeVar. */ - function checkSemiTokenForLeadingSpace(token, node) { - if (isSemicolon(token) && hasLeadingSpace(token)) { - context.report(node, token.loc.start, "Unexpected whitespace before semicolon."); - } + function isInTdz(variable, scopeVar) { + var outerDef = scopeVar.defs[0]; + var inner = getNameRange(variable); + var outer = getNameRange(scopeVar); + return ( + inner && + outer && + inner[1] < outer[0] && + // Excepts FunctionDeclaration if is {"hoist":"function"}. + (options.hoist !== "functions" || !outerDef || outerDef.node.type !== "FunctionDeclaration") + ); } /** - * Checks leading space before the semicolon with the assumption that the last token is the semicolon. - * @param {ASTNode} node The node to check. + * Checks the current context for shadowed variables. + * @param {Scope} scope - Fixme * @returns {void} */ - function checkNode(node) { - var token = context.getLastToken(node); - checkSemiTokenForLeadingSpace(token, node); + function checkForShadows(scope) { + var variables = scope.variables; + for (var i = 0; i < variables.length; ++i) { + var variable = variables[i]; + + // Skips "arguments" or variables of a class name in the class scope of ClassDeclaration. + if (variable.identifiers.length === 0 || + isDuplicatedClassNameVariable(variable) || + isAllowed(variable) + ) { + continue; + } + + // Gets shadowed variable. + var shadowed = astUtils.getVariableByName(scope.upper, variable.name); + if (shadowed && + (shadowed.identifiers.length > 0 || (options.builtinGlobals && "writeable" in shadowed)) && + !isOnInitializer(variable, shadowed) && + !(options.hoist !== "all" && isInTdz(variable, shadowed)) + ) { + context.report({ + node: variable.identifiers[0], + message: "\"{{name}}\" is already declared in the upper scope.", + data: variable + }); + } + } } return { - "VariableDeclaration": checkNode, - "ExpressionStatement": checkNode, - "BreakStatement": checkNode, - "ContinueStatement": checkNode, - "DebuggerStatement": checkNode, - "ReturnStatement": checkNode, - "ThrowStatement": checkNode, - "ForStatement": function (node) { - if (node.init) { - checkSemiTokenForLeadingSpace(context.getTokenAfter(node.init), node); - } + "Program:exit": function() { + var globalScope = context.getScope(); + var stack = globalScope.childScopes.slice(); + var scope; - if (node.test) { - checkSemiTokenForLeadingSpace(context.getTokenAfter(node.test), node); + while (stack.length) { + scope = stack.pop(); + stack.push.apply(stack, scope.childScopes); + checkForShadows(scope); } } }; + }; -},{}],239:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "builtinGlobals": {"type": "boolean"}, + "hoist": {"enum": ["all", "functions", "never"]}, + "allow": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } +]; + +},{"../ast-utils":113}],250:[function(require,module,exports){ /** * @fileoverview Rule to check that spaced function application * @author Matt DuVall <http://www.mattduvall.com> */ @@ -25341,34 +35862,55 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var sourceCode = context.getSourceCode(); + + /** + * Check if open space is present in a function name + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function detectOpenSpaces(node) { - var lastCalleeToken = context.getLastToken(node.callee); - var tokens = context.getTokens(node); - var i = tokens.indexOf(lastCalleeToken), l = tokens.length; - while (i < l && tokens[i].value !== "(") { - ++i; - } - if (i >= l) { + var lastCalleeToken = sourceCode.getLastToken(node.callee), + prevToken = lastCalleeToken, + parenToken = sourceCode.getTokenAfter(lastCalleeToken); + + if (sourceCode.getLastToken(node).value !== ")") { return; } + + while (parenToken.value !== "(") { + prevToken = parenToken; + parenToken = sourceCode.getTokenAfter(parenToken); + } + // look for a space between the callee and the open paren - if (tokens[i - 1].range[1] !== tokens[i].range[0]) { - context.report(node, "Unexpected space between function name and paren."); + if (sourceCode.isSpaceBetweenTokens(prevToken, parenToken)) { + context.report({ + node: node, + loc: lastCalleeToken.loc.start, + message: "Unexpected space between function name and paren.", + fix: function(fixer) { + return fixer.removeRange([prevToken.range[1], parenToken.range[0]]); + } + }); } } return { "CallExpression": detectOpenSpaces, "NewExpression": detectOpenSpaces }; }; -},{}],240:[function(require,module,exports){ +module.exports.schema = []; + +},{}],251:[function(require,module,exports){ /** * @fileoverview Disallow sparse arrays * @author Nicholas C. Zakas */ "use strict"; @@ -25397,17 +35939,19 @@ }; }; -},{}],241:[function(require,module,exports){ +module.exports.schema = []; + +},{}],252:[function(require,module,exports){ /** * @fileoverview Rule to check for properties whose identifier ends with the string Sync * @author Matt DuVall<http://mattduvall.com/> */ -/*jshint node:true*/ +/* jshint node:true */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition @@ -25427,11 +35971,13 @@ } }; }; -},{}],242:[function(require,module,exports){ +module.exports.schema = []; + +},{}],253:[function(require,module,exports){ /** * @fileoverview Rule to flag use of ternary operators. * @author Ian Christian Myers */ @@ -25451,31 +35997,216 @@ }; }; -},{}],243:[function(require,module,exports){ +module.exports.schema = []; + +},{}],254:[function(require,module,exports){ /** + * @fileoverview A rule to disallow using `this`/`super` before `super()`. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + /** + * Searches a class node that a node is belonging to. + * @param {Node} node - A node to start searching. + * @returns {ClassDeclaration|ClassExpression|null} the found class node, or `null`. + */ + function getClassInAncestor(node) { + while (node) { + if (node.type === "ClassDeclaration" || node.type === "ClassExpression") { + return node; + } + node = node.parent; + } + /* istanbul ignore next */ + return null; + } + + /** + * Checks whether or not a node is the null literal. + * @param {Node} node - A node to check. + * @returns {boolean} whether or not a node is the null literal. + */ + function isNullLiteral(node) { + return node && node.type === "Literal" && node.value === null; + } + + /** + * Checks whether or not a node is the callee of a call expression. + * @param {Node} node - A node to check. + * @returns {boolean} whether or not a node is the callee of a call expression. + */ + function isCallee(node) { + return node && node.parent.type === "CallExpression" && node.parent.callee === node; + } + + /** + * Checks whether or not the current traversal context is before `super()`. + * @param {object} item - A checking context. + * @returns {boolean} whether or not the current traversal context is before `super()`. + */ + function isBeforeSuperCalling(item) { + return ( + item && + item.scope === context.getScope().variableScope.upper.variableScope && + item.superCalled === false + ); + } + + var stack = []; + + return { + /** + * Start checking. + * @param {MethodDefinition} node - A target node. + * @returns {void} + */ + "MethodDefinition": function(node) { + if (node.kind !== "constructor") { + return; + } + stack.push({ + thisOrSuperBeforeSuperCalled: [], + superCalled: false, + scope: context.getScope().variableScope + }); + }, + + /** + * Treats the result of checking and reports invalid `this`/`super`. + * @param {MethodDefinition} node - A target node. + * @returns {void} + */ + "MethodDefinition:exit": function(node) { + if (node.kind !== "constructor") { + return; + } + var result = stack.pop(); + + // Skip if it has no extends or `extends null`. + var classNode = getClassInAncestor(node); + if (!classNode || !classNode.superClass || isNullLiteral(classNode.superClass)) { + return; + } + + // Reports. + result.thisOrSuperBeforeSuperCalled.forEach(function(thisOrSuper) { + var type = (thisOrSuper.type === "Super" ? "super" : "this"); + context.report(thisOrSuper, "\"{{type}}\" is not allowed before super()", {type: type}); + }); + }, + + /** + * Marks the node if is before `super()`. + * @param {ThisExpression} node - A target node. + * @returns {void} + */ + "ThisExpression": function(node) { + var item = stack[stack.length - 1]; + if (isBeforeSuperCalling(item)) { + item.thisOrSuperBeforeSuperCalled.push(node); + } + }, + + /** + * Marks the node if is before `super()`. (exclude `super()` itself) + * @param {Super} node - A target node. + * @returns {void} + */ + "Super": function(node) { + var item = stack[stack.length - 1]; + if (isBeforeSuperCalling(item) && isCallee(node) === false) { + item.thisOrSuperBeforeSuperCalled.push(node); + } + }, + + /** + * Marks `super()` called. + * To catch `super(this.a);`, marks on `CallExpression:exit`. + * @param {CallExpression} node - A target node. + * @returns {void} + */ + "CallExpression:exit": function(node) { + var item = stack[stack.length - 1]; + if (isBeforeSuperCalling(item) && node.callee.type === "Super") { + item.superCalled = true; + } + } + }; +}; + +module.exports.schema = []; + +},{}],255:[function(require,module,exports){ +/** * @fileoverview Rule to restrict what can be thrown as an exception. * @author Dieter Oberkofler + * @copyright 2015 Ian VanSchooten. All rights reserved. * @copyright 2015 Dieter Oberkofler. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Determine if a node has a possiblity to be an Error object + * @param {ASTNode} node ASTNode to check + * @returns {boolean} True if there is a chance it contains an Error obj + */ +function couldBeError(node) { + switch (node.type) { + case "Identifier": + case "CallExpression": + case "NewExpression": + case "MemberExpression": + case "TaggedTemplateExpression": + case "YieldExpression": + return true; // possibly an error object. + + case "AssignmentExpression": + return couldBeError(node.right); + + case "SequenceExpression": + var exprs = node.expressions; + return exprs.length !== 0 && couldBeError(exprs[exprs.length - 1]); + + case "LogicalExpression": + return couldBeError(node.left) || couldBeError(node.right); + + case "ConditionalExpression": + return couldBeError(node.consequent) || couldBeError(node.alternate); + + default: + return false; + } +} + +//------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { return { "ThrowStatement": function(node) { - - if (node.argument.type === "Literal") { - context.report(node, "Do not throw a literal."); + if (!couldBeError(node.argument)) { + context.report(node, "Expected an object to be thrown."); } else if (node.argument.type === "Identifier") { if (node.argument.name === "undefined") { context.report(node, "Do not throw undefined."); } } @@ -25484,62 +36215,126 @@ }; }; -},{}],244:[function(require,module,exports){ +module.exports.schema = []; + +},{}],256:[function(require,module,exports){ /** * @fileoverview Disallow trailing spaces at the end of lines. * @author Nodeca Team <https://github.com/nodeca> + * @copyright 2015 Greg Cochard */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var TRAILER = "[ \t\u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]+$"; + var BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u2028\u2029\u3000]", + SKIP_BLANK = "^" + BLANK_CLASS + "*$", + NONBLANK = BLANK_CLASS + "+$"; + var options = context.options[0] || {}, + skipBlankLines = options.skipBlankLines || false; + + /** + * Report the error message + * @param {ASTNode} node node to report + * @param {int[]} location range information + * @param {int[]} fixRange Range based on the whole program + * @returns {void} + */ + function report(node, location, fixRange) { + // Passing node is a bit dirty, because message data will contain + // big text in `source`. But... who cares :) ? + // One more kludge will not make worse the bloody wizardry of this plugin. + context.report({ + node: node, + loc: location, + message: "Trailing spaces not allowed.", + fix: function(fixer) { + return fixer.removeRange(fixRange); + } + }); + } + + //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- return { "Program": function checkTrailingSpaces(node) { - // Let's hack. Since Esprima does not return whitespace nodes, - // fetch the source code and do black magic via regexps. + // Let's hack. Since Espree does not return whitespace nodes, + // fetch the source code and do matching via regexps. var src = context.getSource(), - re = new RegExp(TRAILER, "mg"), - match, lines, location; + re = new RegExp(NONBLANK), + skipMatch = new RegExp(SKIP_BLANK), + matches, lines = src.split(/\r?\n/), + linebreaks = context.getSource().match(/\r\n|\r|\n|\u2028|\u2029/g), + location, + totalLength = 0, + fixRange = []; - while ((match = re.exec(src)) !== null) { - lines = src.slice(0, re.lastIndex).split(/\r?\n/g); + for (var i = 0, ii = lines.length; i < ii; i++) { + matches = re.exec(lines[i]); - location = { - line: lines.length, - column: lines[lines.length - 1].length - match[0].length + 1 - }; + // Always add linebreak length to line length to accommodate for line break (\n or \r\n) + // Because during the fix time they also reserve one spot in the array. + // Usually linebreak length is 2 for \r\n (CRLF) and 1 for \n (LF) + var linebreakLength = linebreaks && linebreaks[i] ? linebreaks[i].length : 1; + var lineLength = lines[i].length + linebreakLength; - // Passing node is a bit dirty, because message data will contain - // big text in `source`. But... who cares :) ? - // One more kludge will not make worse the bloody wizardry of this plugin. - context.report(node, location, "Trailing spaces not allowed."); + if (matches) { + + // If the line has only whitespace, and skipBlankLines + // is true, don't report it + if (skipBlankLines && skipMatch.test(lines[i])) { + continue; + } + location = { + line: i + 1, + column: matches.index + }; + + fixRange = [totalLength + location.column, totalLength + lineLength - linebreakLength]; + + report(node, location, fixRange); + } + + totalLength += lineLength; } } }; }; -},{}],245:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "skipBlankLines": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{}],257:[function(require,module,exports){ /** * @fileoverview Rule to flag when initializing to undefined * @author Ilya Volodin + * @copyright 2013 Ilya Volodin. All rights reserved. + * See LICENSE in root directory for full license. */ "use strict"; //------------------------------------------------------------------------------ @@ -25549,34 +36344,50 @@ module.exports = function(context) { return { "VariableDeclarator": function(node) { - var name = node.id.name; - var init = node.init && node.init.name; + var name = node.id.name, + init = node.init && node.init.name; - if (init === "undefined") { + if (init === "undefined" && node.parent.kind !== "const") { context.report(node, "It's not necessary to initialize '{{name}}' to undefined.", { name: name }); } } }; }; -},{}],246:[function(require,module,exports){ +module.exports.schema = []; + +},{}],258:[function(require,module,exports){ /** * @fileoverview Rule to flag references to undeclared variables. * @author Mark Macdonald * @copyright 2015 Nicholas C. Zakas. All rights reserved. * @copyright 2013 Mark Macdonald. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Check if a variable is an implicit declaration + * @param {ASTNode} variable node to evaluate + * @returns {boolean} True if its an implicit declaration + * @private + */ function isImplicitGlobal(variable) { return variable.defs.every(function(def) { return def.type === "ImplicitGlobalVariable"; }); } @@ -25586,22 +36397,17 @@ * @param {Scope} scope The scope in which to search. * @param {Reference} ref The reference to find in the scope. * @returns {Variable} The variable, or null if ref refers to an undeclared variable. */ function getDeclaredGlobalVariable(scope, ref) { - var declaredGlobal = null; - scope.variables.some(function(variable) { - if (variable.name === ref.identifier.name) { - // If it's an implicit global, it must have a `writeable` field (indicating it was declared) - if (!isImplicitGlobal(variable) || {}.hasOwnProperty.call(variable, "writeable")) { - declaredGlobal = variable; - return true; - } - } - return false; - }); - return declaredGlobal; + var variable = astUtils.getVariableByName(scope, ref.identifier.name); + + // If it's an implicit global, it must have a `writeable` field (indicating it was declared) + if (variable && (!isImplicitGlobal(variable) || hasOwnProperty.call(variable, "writeable"))) { + return variable; + } + return null; } /** * Checks if the given node is the argument of a typeof operator. * @param {ASTNode} node The AST node being checked. @@ -25610,88 +36416,62 @@ function hasTypeOfOperator(node) { var parent = node.parent; return parent.type === "UnaryExpression" && parent.operator === "typeof"; } -/** - * Checks if a node name match the JSX tag convention. - * @param {String} name - Name of the node to check. - * @returns {boolean} Whether or not the node name match the JSX tag convention. - */ -var tagConvention = /^[a-z]|\-/; -function isTagName(name) { - return tagConvention.test(name); -} - //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var NOT_DEFINED_MESSAGE = "'{{name}}' is not defined.", - READ_ONLY_MESSAGE = "'{{name}}' is read only."; + var NOT_DEFINED_MESSAGE = "\"{{name}}\" is not defined.", + READ_ONLY_MESSAGE = "\"{{name}}\" is read only."; - /** - * Compare an identifier with the variables declared in the scope - * @param {ASTNode} node - Identifier or JSXIdentifier node - * @returns {void} - */ - function checkIdentifierInJSX(node) { - var scope = context.getScope(), - variables = scope.variables, - i, - len; + var options = context.options[0]; + var considerTypeOf = options && options.typeof === true || false; - while (scope.type !== "global") { - scope = scope.upper; - variables = scope.variables.concat(variables); - } - - for (i = 0, len = variables.length; i < len; i++) { - - if (variables[i].name === node.name) { - return; - } - } - - context.report(node, NOT_DEFINED_MESSAGE, { name: node.name }); - } - return { - "Program:exit": function(/*node*/) { + "Program:exit": function(/* node */) { var globalScope = context.getScope(); globalScope.through.forEach(function(ref) { var variable = getDeclaredGlobalVariable(globalScope, ref), name = ref.identifier.name; - if (hasTypeOfOperator(ref.identifier)) { + if (hasTypeOfOperator(ref.identifier) && !considerTypeOf) { return; } if (!variable) { context.report(ref.identifier, NOT_DEFINED_MESSAGE, { name: name }); } else if (ref.isWrite() && variable.writeable === false) { context.report(ref.identifier, READ_ONLY_MESSAGE, { name: name }); } }); - }, - "JSXOpeningElement": function(node) { - if (!isTagName(node.name.name)) { - checkIdentifierInJSX(node.name); - } } }; }; -},{}],247:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "typeof": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{"../ast-utils":113}],259:[function(require,module,exports){ /** * @fileoverview Rule to flag references to the undefined variable. * @author Michael Ficarra */ "use strict"; @@ -25714,11 +36494,13 @@ } }; }; -},{}],248:[function(require,module,exports){ +module.exports.schema = []; + +},{}],260:[function(require,module,exports){ /** * @fileoverview Rule to flag trailing underscores in variable declarations. * @author Matt DuVall <http://www.mattduvall.com> */ @@ -25728,52 +36510,104 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var ALLOWED_VARIABLES = context.options[0] && context.options[0].allow ? context.options[0].allow : []; + //------------------------------------------------------------------------- // Helpers //------------------------------------------------------------------------- + /** + * Check if identifier is present inside the allowed option + * @param {string} identifier name of the node + * @returns {boolean} true if its is present + * @private + */ + function isAllowed(identifier) { + return ALLOWED_VARIABLES.some(function(ident) { + return ident === identifier; + }); + } + + /** + * Check if identifier has a underscore at the end + * @param {ASTNode} identifier node to evaluate + * @returns {boolean} true if its is present + * @private + */ function hasTrailingUnderscore(identifier) { var len = identifier.length; return identifier !== "_" && (identifier[0] === "_" || identifier[len - 1] === "_"); } + /** + * Check if identifier is a special case member expression + * @param {ASTNode} identifier node to evaluate + * @returns {boolean} true if its is a special case + * @private + */ function isSpecialCaseIdentifierForMemberExpression(identifier) { return identifier === "__proto__"; } + /** + * Check if identifier is a special case variable expression + * @param {ASTNode} identifier node to evaluate + * @returns {boolean} true if its is a special case + * @private + */ function isSpecialCaseIdentifierInVariableExpression(identifier) { // Checks for the underscore library usage here return identifier === "_"; } + /** + * Check if function has a underscore at the end + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function checkForTrailingUnderscoreInFunctionDeclaration(node) { - var identifier = node.id.name; + if (node.id) { + var identifier = node.id.name; - if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier)) { - context.report(node, "Unexpected dangling '_' in '" + identifier + "'."); + if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && !isAllowed(identifier)) { + context.report(node, "Unexpected dangling \"_\" in \"" + identifier + "\"."); + } } } + /** + * Check if variable expression has a underscore at the end + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function checkForTrailingUnderscoreInVariableExpression(node) { var identifier = node.id.name; if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && - !isSpecialCaseIdentifierInVariableExpression(identifier)) { - context.report(node, "Unexpected dangling '_' in '" + identifier + "'."); + !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) { + context.report(node, "Unexpected dangling \"_\" in \"" + identifier + "\"."); } } + /** + * Check if member expression has a underscore at the end + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function checkForTrailingUnderscoreInMemberExpression(node) { var identifier = node.property.name; if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && - !isSpecialCaseIdentifierForMemberExpression(identifier)) { - context.report(node, "Unexpected dangling '_' in '" + identifier + "'."); + !isSpecialCaseIdentifierForMemberExpression(identifier) && !isAllowed(identifier)) { + context.report(node, "Unexpected dangling \"_\" in \"" + identifier + "\"."); } } //-------------------------------------------------------------------------- // Public API @@ -25785,22 +36619,168 @@ "MemberExpression": checkForTrailingUnderscoreInMemberExpression }; }; -},{}],249:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "allow": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } +]; + +},{}],261:[function(require,module,exports){ /** + * @fileoverview Rule to spot scenarios where a newline looks like it is ending a statement, but is not. + * @author Glen Mailer + * @copyright 2015 Glen Mailer + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ +module.exports = function(context) { + + var FUNCTION_MESSAGE = "Unexpected newline between function and ( of function call."; + var PROPERTY_MESSAGE = "Unexpected newline between object and [ of property access."; + + /** + * Check to see if the bracket prior to the node is continuing the previous + * line's expression + * @param {ASTNode} node The node to check. + * @param {string} msg The error message to use. + * @returns {void} + * @private + */ + function checkForBreakBefore(node, msg) { + var tokens = context.getTokensBefore(node, 2); + var paren = tokens[1]; + var before = tokens[0]; + if (paren.loc.start.line !== before.loc.end.line) { + context.report(node, paren.loc.start, msg, { char: paren.value }); + } + } + + //-------------------------------------------------------------------------- + // Public API + //-------------------------------------------------------------------------- + + return { + + "MemberExpression": function(node) { + if (!node.computed) { + return; + } + + checkForBreakBefore(node.property, PROPERTY_MESSAGE); + }, + + "CallExpression": function(node) { + if (node.arguments.length === 0) { + return; + } + + checkForBreakBefore(node.arguments[0], FUNCTION_MESSAGE); + } + }; + +}; + +module.exports.schema = []; + +},{}],262:[function(require,module,exports){ +/** + * @fileoverview Rule to flag no-unneeded-ternary + * @author Gyandeep Singh + * @copyright 2015 Gyandeep Singh. All rights reserved. + * @copyright 2015 Michael Ficarra. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var options = context.options[0] || {}; + var defaultAssignment = options.defaultAssignment !== false; + + /** + * Test if the node is a boolean literal + * @param {ASTNode} node - The node to report. + * @returns {boolean} True if the its a boolean literal + * @private + */ + function isBooleanLiteral(node) { + return node.type === "Literal" && typeof node.value === "boolean"; + } + + /** + * Test if the node matches the pattern id ? id : expression + * @param {ASTNode} node - The ConditionalExpression to check. + * @returns {boolean} True if the pattern is matched, and false otherwise + * @private + */ + function matchesDefaultAssignment(node) { + return node.test.type === "Identifier" && + node.consequent.type === "Identifier" && + node.test.name === node.consequent.name; + } + + return { + + "ConditionalExpression": function(node) { + if (isBooleanLiteral(node.alternate) && isBooleanLiteral(node.consequent)) { + context.report(node, node.consequent.loc.start, "Unnecessary use of boolean literals in conditional expression"); + } else if (!defaultAssignment && matchesDefaultAssignment(node)) { + context.report(node, node.consequent.loc.start, "Unnecessary use of conditional expression for default assignment"); + } + } + }; +}; + +module.exports.schema = [ + { + "type": "object", + "properties": { + "defaultAssignment": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{}],263:[function(require,module,exports){ +/** * @fileoverview Checks for unreachable code due to return, throws, break, and continue. * @author Joel Feenstra */ "use strict"; //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ - +/** + * Report the node + * @param {object} context Current context as passed to the rule + * @param {ASTNode} node node to evaluate + * @param {string} unreachableType Type of the statement + * @returns {void} + * @private + */ function report(context, node, unreachableType) { var keyword; switch (unreachableType) { case "BreakStatement": keyword = "break"; @@ -25839,11 +36819,11 @@ node.declarations.every(function(declaration) { return declaration.type === "VariableDeclarator" && declaration.init === null; }); } - /* + /** * Verifies that the given node is the last node or followed exclusively by * hoisted declarations * @param {ASTNode} node Node that should be the last node * @returns {void} * @private @@ -25883,11 +36863,13 @@ "BreakStatement": checkNode }; }; -},{}],250:[function(require,module,exports){ +module.exports.schema = []; + +},{}],264:[function(require,module,exports){ /** * @fileoverview Flag expressions in statement position that do not side effect * @author Michael Ficarra * @copyright 2013 Michael Ficarra. All rights reserved. */ @@ -25896,14 +36878,17 @@ //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var config = context.options[0] || {}, + allowShortCircuit = config.allowShortCircuit || false, + allowTernary = config.allowTernary || false; /** * @param {ASTNode} node - any node - * @returns {Boolean} whether the given node structurally represents a directive + * @returns {boolean} whether the given node structurally represents a directive */ function looksLikeDirective(node) { return node.type === "ExpressionStatement" && node.expression.type === "Literal" && typeof node.expression.value === "string"; } @@ -25931,226 +36916,416 @@ } /** * @param {ASTNode} node - any node * @param {ASTNode[]} ancestors - the given node's ancestors - * @returns {Boolean} whether the given node is considered a directive in its current position + * @returns {boolean} whether the given node is considered a directive in its current position */ function isDirective(node, ancestors) { var parent = ancestors[ancestors.length - 1], grandparent = ancestors[ancestors.length - 2]; return (parent.type === "Program" || parent.type === "BlockStatement" && (/Function/.test(grandparent.type))) && directives(parent).indexOf(node) >= 0; } - return { - "ExpressionStatement": function(node) { + /** + * Determines whether or not a given node is a valid expression. Recurses on short circuit eval and ternary nodes if enabled by flags. + * @param {ASTNode} node - any node + * @returns {boolean} whether the given node is a valid expression + */ + function isValidExpression(node) { + if (allowTernary) { + // Recursive check for ternary and logical expressions + if (node.type === "ConditionalExpression") { + return isValidExpression(node.consequent) && isValidExpression(node.alternate); + } + } + if (allowShortCircuit) { + if (node.type === "LogicalExpression") { + return isValidExpression(node.right); + } + } - var type = node.expression.type, - ancestors = context.getAncestors(); + return /^(?:Assignment|Call|New|Update|Yield)Expression$/.test(node.type) || + (node.type === "UnaryExpression" && ["delete", "void"].indexOf(node.operator) >= 0); + } - if ( - !/^(?:Assignment|Call|New|Update|Yield)Expression$/.test(type) && - (type !== "UnaryExpression" || ["delete", "void"].indexOf(node.expression.operator) < 0) && - !isDirective(node, ancestors) - ) { + return { + "ExpressionStatement": function(node) { + if (!isValidExpression(node.expression) && !isDirective(node, context.getAncestors())) { context.report(node, "Expected an assignment or function call and instead saw an expression."); } } }; }; -},{}],251:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "allowShortCircuit": { + "type": "boolean" + }, + "allowTernary": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{}],265:[function(require,module,exports){ /** * @fileoverview Rule to flag declared but unused variables * @author Ilya Volodin */ "use strict"; //------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var escape = require("escape-string-regexp"); + +//------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var MESSAGE = "{{name}} is defined but never used"; + var MESSAGE = "\"{{name}}\" is defined but never used"; var config = { vars: "all", args: "after-used" }; - if (context.options[0]) { - if (typeof context.options[0] === "string") { - config.vars = context.options[0]; + var firstOption = context.options[0]; + + if (firstOption) { + if (typeof firstOption === "string") { + config.vars = firstOption; } else { - config.vars = context.options[0].vars || config.vars; - config.args = context.options[0].args || config.args; + config.vars = firstOption.vars || config.vars; + config.args = firstOption.args || config.args; + + if (firstOption.varsIgnorePattern) { + config.varsIgnorePattern = new RegExp(firstOption.varsIgnorePattern); + } + + if (firstOption.argsIgnorePattern) { + config.argsIgnorePattern = new RegExp(firstOption.argsIgnorePattern); + } } } + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + /** * Determines if a given variable is being exported from a module. - * @param {Variable} variable EScope variable object. + * @param {Variable} variable - EScope variable object. * @returns {boolean} True if the variable is exported, false if not. * @private */ function isExported(variable) { var definition = variable.defs[0]; if (definition) { - definition = definition.node; - if (definition.type === "VariableDeclarator") { - definition = definition.parent; + var node = definition.node; + if (node.type === "VariableDeclarator") { + node = node.parent; + } else if (definition.type === "Parameter") { + return false; } - return definition.parent.type.indexOf("Export") === 0; + return node.parent.type.indexOf("Export") === 0; } else { return false; } } /** - * @param {Reference} ref - an escope Reference + * Determines if a reference is a read operation. + * @param {Reference} ref - An escope Reference * @returns {Boolean} whether the given reference represents a read operation + * @private */ function isReadRef(ref) { return ref.isRead(); } /** - * Gets an array of local variables without read references. - * @param {Scope} scope - an escope Scope object - * @returns {Variable[]} most of the local variables with no read references + * Determine if an identifier is referencing an enclosing function name. + * @param {Reference} ref - The reference to check. + * @param {ASTNode[]} nodes - The candidate function nodes. + * @returns {boolean} True if it's a self-reference, false if not. + * @private */ - function getUnusedLocals(scope) { - var unused = []; + function isSelfReference(ref, nodes) { + var scope = ref.from; + + while (scope) { + if (nodes.indexOf(scope.block) >= 0) { + return true; + } + + scope = scope.upper; + } + + return false; + } + + /** + * Determines if the variable is used. + * @param {Variable} variable - The variable to check. + * @param {Reference[]} references - The variable references to check. + * @returns {boolean} True if the variable is used + */ + function isUsedVariable(variable, references) { + var functionNodes = variable.defs.filter(function(def) { + return def.type === "FunctionName"; + }).map(function(def) { + return def.node; + }), + isFunctionDefinition = functionNodes.length > 0; + + return references.some(function(ref) { + return isReadRef(ref) && !(isFunctionDefinition && isSelfReference(ref, functionNodes)); + }); + } + + /** + * Gets unresolved references. + * They contains var's, function's, and explicit global variable's. + * If `config.vars` is not "all", returns empty map. + * @param {Scope} scope - the global scope. + * @returns {object} Unresolved references. Keys of the object is its variable name. Values of the object is an array of its references. + * @private + */ + function collectUnresolvedReferences(scope) { + var unresolvedRefs = Object.create(null); + + if (config.vars === "all") { + for (var i = 0, l = scope.through.length; i < l; ++i) { + var ref = scope.through[i]; + var name = ref.identifier.name; + + if (isReadRef(ref)) { + if (!unresolvedRefs[name]) { + unresolvedRefs[name] = []; + } + unresolvedRefs[name].push(ref); + } + } + } + + return unresolvedRefs; + } + + /** + * Gets an array of variables without read references. + * @param {Scope} scope - an escope Scope object. + * @param {object} unresolvedRefs - a map of each variable name and its references. + * @param {Variable[]} unusedVars - an array that saving result. + * @returns {Variable[]} unused variables of the scope and descendant scopes. + * @private + */ + function collectUnusedVariables(scope, unresolvedRefs, unusedVars) { var variables = scope.variables; + var childScopes = scope.childScopes; + var i, l; - if (scope.type !== "global" && scope.type !== "TDZ") { - for (var i = 0, l = variables.length; i < l; ++i) { + if (scope.type !== "TDZ" && (scope.type !== "global" || config.vars === "all")) { + for (i = 0, l = variables.length; i < l; ++i) { + var variable = variables[i]; - // skip function expression names - if (scope.functionExpressionScope || variables[i].eslintJSXUsed) { + // skip a variable of class itself name in the class scope + if (scope.type === "class" && scope.block.id === variable.identifiers[0]) { continue; } - // skip implicit "arguments" variable - if (scope.type === "function" && variables[i].name === "arguments" && variables[i].identifiers.length === 0) { + // skip function expression names and variables marked with markVariableAsUsed() + if (scope.functionExpressionScope || variable.eslintUsed) { continue; } - var type = variables[i].defs[0].type; - - // skip catch variables - if (type === "CatchClause") { + // skip implicit "arguments" variable + if (scope.type === "function" && variable.name === "arguments" && variable.identifiers.length === 0) { continue; } - // if "args" option is "none", skip any parameter - if (config.args === "none" && type === "Parameter") { - continue; - } - // if "args" option is "after-used", skip all but the last parameter - if (config.args === "after-used" && type === "Parameter" && variables[i].defs[0].index < variables[i].defs[0].node.params.length - 1) { - continue; + // explicit global variables don't have definitions. + var def = variable.defs[0]; + if (def) { + var type = def.type; + + // skip catch variables + if (type === "CatchClause") { + continue; + } + + if (type === "Parameter") { + // skip any setter argument + if (def.node.parent.type === "Property" && def.node.parent.kind === "set") { + continue; + } + + // if "args" option is "none", skip any parameter + if (config.args === "none") { + continue; + } + + // skip ignored parameters + if (config.argsIgnorePattern && config.argsIgnorePattern.test(def.name.name)) { + continue; + } + + // if "args" option is "after-used", skip all but the last parameter + if (config.args === "after-used" && def.index < def.node.params.length - 1) { + continue; + } + } else { + // skip ignored variables + if (config.varsIgnorePattern && config.varsIgnorePattern.test(def.name.name)) { + continue; + } + } } - if (variables[i].references.filter(isReadRef).length === 0 && !isExported(variables[i])) { - unused.push(variables[i]); + // On global, variables without let/const/class are unresolved. + var references = (scope.type === "global" ? unresolvedRefs[variable.name] : null) || variable.references; + if (!isUsedVariable(variable, references) && !isExported(variable)) { + unusedVars.push(variable); } } } - return [].concat.apply(unused, scope.childScopes.map(getUnusedLocals)); + for (i = 0, l = childScopes.length; i < l; ++i) { + collectUnusedVariables(childScopes[i], unresolvedRefs, unusedVars); + } + + return unusedVars; } /** - * @param {String} nodeName - Name of the node to check. - * @returns {void} + * Gets the index of a given variable name in a given comment. + * @param {escope.Variable} variable - A variable to get. + * @param {ASTNode} comment - A comment node which includes the variable name. + * @returns {number} The index of the variable name's location. */ - function flagVariableAsUsedInJSX(nodeName) { - var scope = context.getScope(), - variables = scope.variables, - i, - len; + function getColumnInComment(variable, comment) { + var namePattern = new RegExp("[\\s,]" + escape(variable.name) + "(?:$|[\\s,:])", "g"); - while (scope.type !== "global") { - scope = scope.upper; - variables = [].concat.apply(scope.variables, variables); - } + // To ignore the first text "global". + namePattern.lastIndex = comment.value.indexOf("global") + 6; - // mark JSXIdentifiers with a special flag - for (i = 0, len = variables.length; i < len; i++) { - if (variables[i].name === nodeName) { - variables[i].eslintJSXUsed = true; - break; - } + // Search a given variable name. + var match = namePattern.exec(comment.value); + return match ? match.index + 1 : 0; + } + + /** + * Creates the correct location of a given variables. + * The location is at its name string in a `/*global` comment. + * + * @param {escope.Variable} variable - A variable to get its location. + * @returns {{line: number, column: number}} The location object for the variable. + */ + function getLocation(variable) { + var comment = variable.eslintExplicitGlobalComment; + var baseLoc = comment.loc.start; + var column = getColumnInComment(variable, comment); + var prefix = comment.value.slice(0, column); + var lineInComment = (prefix.match(/\n/g) || []).length; + + if (lineInComment > 0) { + column -= 1 + prefix.lastIndexOf("\n"); + } else { + // 2 is for `/*` + column += baseLoc.column + 2; } + + return { + line: baseLoc.line + lineInComment, + column: column + }; } + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + return { "Program:exit": function(programNode) { var globalScope = context.getScope(); - var unused = getUnusedLocals(globalScope); - var i, l; + var unresolvedRefs = collectUnresolvedReferences(globalScope); + var unusedVars = collectUnusedVariables(globalScope, unresolvedRefs, []); - // determine unused globals - if (config.vars === "all") { - var unresolvedRefs = globalScope.through.filter(isReadRef).map(function(ref) { - return ref.identifier.name; - }); + for (var i = 0, l = unusedVars.length; i < l; ++i) { + var unusedVar = unusedVars[i]; - for (i = 0, l = globalScope.variables.length; i < l; ++i) { - if (unresolvedRefs.indexOf(globalScope.variables[i].name) < 0 && - !globalScope.variables[i].eslintJSXUsed && !isExported(globalScope.variables[i])) { - unused.push(globalScope.variables[i]); - } + if (unusedVar.eslintUsed) { + continue; // explicitly exported variables + } else if (unusedVar.eslintExplicitGlobal) { + context.report(programNode, getLocation(unusedVar), MESSAGE, unusedVar); + } else if (unusedVar.defs.length > 0) { + context.report(unusedVar.identifiers[0], MESSAGE, unusedVar); } } + } + }; - for (i = 0, l = unused.length; i < l; ++i) { - if (unused[i].eslintExplicitGlobal) { - context.report(programNode, MESSAGE, unused[i]); - } else if (unused[i].defs.length > 0) { +}; - // TODO: Remove when https://github.com/estools/escope/issues/49 is resolved - if (unused[i].defs[0].type === "ClassName") { - continue; +module.exports.schema = [ + { + "oneOf": [ + { + "enum": ["all", "local"] + }, + { + "type": "object", + "properties": { + "vars": { + "enum": ["all", "local"] + }, + "varsIgnorePattern": { + "type": "string" + }, + "args": { + "enum": ["all", "after-used", "none"] + }, + "argsIgnorePattern": { + "type": "string" } - - context.report(unused[i].identifiers[0], MESSAGE, unused[i]); } } - }, + ] + } +]; - "JSXExpressionContainer": function(node) { - if (node.expression.type === "Identifier") { - flagVariableAsUsedInJSX(node.expression.name); - } - }, - - "JSXIdentifier": function(node) { - flagVariableAsUsedInJSX(node.name); - } - }; - -}; - -},{}],252:[function(require,module,exports){ +},{"escape-string-regexp":74}],266:[function(require,module,exports){ /** * @fileoverview Rule to flag use of variables before they are defined * @author Ilya Volodin * @copyright 2013 Ilya Volodin. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------------ var NO_FUNC = "nofunc"; @@ -26158,60 +37333,285 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - function findDeclaration(name, scope) { - // try searching in the current scope first - for (var i = 0, l = scope.variables.length; i < l; i++) { - if (scope.variables[i].name === name) { - return scope.variables[i]; - } - } - // check if there's upper scope and call recursivly till we find the variable - if (scope.upper) { - return findDeclaration(name, scope.upper); - } - } - - function findVariables() { - var scope = context.getScope(); + /** + * Finds and validates all variables in a given scope. + * @param {Scope} scope The scope object. + * @returns {void} + * @private + */ + function findVariablesInScope(scope) { var typeOption = context.options[0]; + /** + * Report the node + * @param {object} reference reference object + * @param {ASTNode} declaration node to evaluate + * @returns {void} + * @private + */ function checkLocationAndReport(reference, declaration) { if (typeOption !== NO_FUNC || declaration.defs[0].type !== "FunctionName") { if (declaration.identifiers[0].range[1] > reference.identifier.range[1]) { - context.report(reference.identifier, "{{a}} was used before it was defined", {a: reference.identifier.name}); + context.report(reference.identifier, "\"{{a}}\" was used before it was defined", {a: reference.identifier.name}); } } } scope.references.forEach(function(reference) { // if the reference is resolved check for declaration location // if not, it could be function invocation, try to find manually if (reference.resolved && reference.resolved.identifiers.length > 0) { checkLocationAndReport(reference, reference.resolved); } else { - var declaration = findDeclaration(reference.identifier.name, scope); + var declaration = astUtils.getVariableByName(scope, reference.identifier.name); // if there're no identifiers, this is a global environment variable if (declaration && declaration.identifiers.length !== 0) { checkLocationAndReport(reference, declaration); } } }); } + + /** + * Validates variables inside of a node's scope. + * @param {ASTNode} node The node to check. + * @returns {void} + * @private + */ + function findVariables() { + var scope = context.getScope(); + findVariablesInScope(scope); + } + + var ruleDefinition = { + "Program": function() { + var scope = context.getScope(); + findVariablesInScope(scope); + + // both Node.js and Modules have an extra scope + if (context.ecmaFeatures.globalReturn || context.ecmaFeatures.modules) { + findVariablesInScope(scope.childScopes[0]); + } + } + }; + + if (context.ecmaFeatures.blockBindings) { + ruleDefinition.BlockStatement = ruleDefinition.SwitchStatement = findVariables; + + ruleDefinition.ArrowFunctionExpression = function(node) { + if (node.body.type !== "BlockStatement") { + findVariables(node); + } + }; + } else { + ruleDefinition.FunctionExpression = ruleDefinition.FunctionDeclaration = ruleDefinition.ArrowFunctionExpression = findVariables; + } + + return ruleDefinition; +}; + +module.exports.schema = [ + { + "enum": ["nofunc"] + } +]; + +},{"../ast-utils":113}],267:[function(require,module,exports){ +/** + * @fileoverview A rule to disallow unnecessary `.call()` and `.apply()`. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + */ + +"use strict"; + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Checks whether or not a node is a `.call()`/`.apply()`. + * @param {ASTNode} node - A CallExpression node to check. + * @returns {boolean} Whether or not the node is a `.call()`/`.apply()`. + */ +function isCallOrNonVariadicApply(node) { + return ( + node.callee.type === "MemberExpression" && + node.callee.property.type === "Identifier" && + node.callee.computed === false && + ( + (node.callee.property.name === "call" && node.arguments.length >= 1) || + (node.callee.property.name === "apply" && node.arguments.length === 2 && node.arguments[1].type === "ArrayExpression") + ) + ); +} + +/** + * Checks whether or not the tokens of two given nodes are same. + * @param {ASTNode} left - A node 1 to compare. + * @param {ASTNode} right - A node 2 to compare. + * @param {RuleContext} context - The ESLint rule context object. + * @returns {boolean} the source code for the given node. + */ +function equalTokens(left, right, context) { + var tokensL = context.getTokens(left); + var tokensR = context.getTokens(right); + + if (tokensL.length !== tokensR.length) { + return false; + } + for (var i = 0; i < tokensL.length; ++i) { + if (tokensL[i].type !== tokensR[i].type || + tokensL[i].value !== tokensR[i].value + ) { + return false; + } + } + + return true; +} + +/** + * Checks whether or not `thisArg` is not changed by `.call()`/`.apply()`. + * @param {ASTNode|null} expectedThis - The node that is the owner of the applied function. + * @param {ASTNode} thisArg - The node that is given to the first argument of the `.call()`/`.apply()`. + * @param {RuleContext} context - The ESLint rule context object. + * @returns {boolean} Whether or not `thisArg` is not changed by `.call()`/`.apply()`. + */ +function isValidThisArg(expectedThis, thisArg, context) { + if (!expectedThis) { + return astUtils.isNullOrUndefined(thisArg); + } + return equalTokens(expectedThis, thisArg, context); +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { return { - "Program": findVariables, - "FunctionExpression": findVariables, - "FunctionDeclaration": findVariables, - "ArrowFunctionExpression": findVariables + "CallExpression": function(node) { + if (!isCallOrNonVariadicApply(node)) { + return; + } + + var applied = node.callee.object; + var expectedThis = (applied.type === "MemberExpression") ? applied.object : null; + var thisArg = node.arguments[0]; + + if (isValidThisArg(expectedThis, thisArg, context)) { + context.report( + node, + "unnecessary \".{{name}}()\".", + {name: node.callee.property.name}); + } + } }; }; -},{}],253:[function(require,module,exports){ +module.exports.schema = []; + +},{"../ast-utils":113}],268:[function(require,module,exports){ /** + * @fileoverview disallow unncessary concatenation of template strings + * @author Henry Zhu + * @copyright 2015 Henry Zhu. All rights reserved. + * See LICENSE file in root directory for full license. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Checks whether or not a given node is a concatenation. + * @param {ASTNode} node - A node to check. + * @returns {boolean} `true` if the node is a concatenation. + */ +function isConcatenation(node) { + return node.type === "BinaryExpression" && node.operator === "+"; +} + +/** + * Get's the right most node on the left side of a BinaryExpression with + operator. + * @param {ASTNode} node - A BinaryExpression node to check. + * @returns {ASTNode} node + */ +function getLeft(node) { + var left = node.left; + while (isConcatenation(left)) { + left = left.right; + } + return left; +} + +/** + * Get's the left most node on the right side of a BinaryExpression with + operator. + * @param {ASTNode} node - A BinaryExpression node to check. + * @returns {ASTNode} node + */ +function getRight(node) { + var right = node.right; + while (isConcatenation(right)) { + right = right.left; + } + return right; +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + return { + BinaryExpression: function(node) { + // check if not concatenation + if (node.operator !== "+") { + return; + } + + // account for the `foo + "a" + "b"` case + var left = getLeft(node); + var right = getRight(node); + + if (astUtils.isStringLiteral(left) && + astUtils.isStringLiteral(right) && + astUtils.isTokenOnSameLine(left, right) + ) { + // move warning location to operator + var operatorToken = context.getTokenAfter(left); + while (operatorToken.value !== "+") { + operatorToken = context.getTokenAfter(operatorToken); + } + + context.report( + node, + operatorToken.loc.start, + "Unexpected string concatenation of literals."); + } + } + }; +}; + +module.exports.schema = []; + +},{"../ast-utils":113}],269:[function(require,module,exports){ +/** * @fileoverview Rule to check for the usage of var. * @author Jamund Ferguson * @copyright 2014 Jamund Ferguson. All rights reserved. */ @@ -26222,21 +37622,23 @@ //------------------------------------------------------------------------------ module.exports = function(context) { return { - "VariableDeclaration": function (node) { + "VariableDeclaration": function(node) { if (node.kind === "var") { context.report(node, "Unexpected var, use let or const instead."); } } }; }; -},{}],254:[function(require,module,exports){ +module.exports.schema = []; + +},{}],270:[function(require,module,exports){ /** * @fileoverview Rule to disallow use of void operator. * @author Mike Sidorov * @copyright 2014 Mike Sidorov. All rights reserved. */ @@ -26260,27 +37662,32 @@ } }; }; -},{}],255:[function(require,module,exports){ +module.exports.schema = []; + +},{}],271:[function(require,module,exports){ /** * @fileoverview Rule that warns about used warning comments * @author Alexander Schmidt <https://github.com/lxanders> */ "use strict"; +var astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = function (context) { +module.exports = function(context) { var configuration = context.options[0] || {}, warningTerms = configuration.terms || ["todo", "fixme", "xxx"], location = configuration.location || "start", + selfConfigRegEx = /\bno-warning-comments\b/, warningRegExps; /** * Convert a warning term into a RegExp which will match a comment containing that whole word in the specified * location ("start" or "anywhere"). If the term starts or ends with non word characters, then the match will not @@ -26317,11 +37724,11 @@ * @returns {Array} All matched warning terms for this comment. */ function commentContainsWarningTerm(comment) { var matches = []; - warningRegExps.forEach(function (regex, index) { + warningRegExps.forEach(function(regex, index) { if (regex.test(comment)) { matches.push(warningTerms[index]); } }); @@ -26332,25 +37739,47 @@ * Checks the specified node for matching warning comments and reports them. * @param {ASTNode} node The AST node being checked. * @returns {void} undefined. */ function checkComment(node) { + if (astUtils.isDirectiveComment(node) && selfConfigRegEx.test(node.value)) { + return; + } + var matches = commentContainsWarningTerm(node.value); - matches.forEach(function (matchedTerm) { - context.report(node, "Unexpected " + matchedTerm + " comment."); + matches.forEach(function(matchedTerm) { + context.report(node, "Unexpected \"" + matchedTerm + "\" comment."); }); } warningRegExps = warningTerms.map(convertToRegExp); return { "BlockComment": checkComment, "LineComment": checkComment }; }; -},{}],256:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "terms": { + "type": "array", + "items": { + "type": "string" + } + }, + "location": { + "enum": ["start", "anywhere"] + } + }, + "additionalProperties": false + } +]; + +},{"../ast-utils":113}],272:[function(require,module,exports){ /** * @fileoverview Rule to flag use of with statement * @author Nicholas C. Zakas */ @@ -26368,55 +37797,362 @@ } }; }; -},{}],257:[function(require,module,exports){ +module.exports.schema = []; + +},{}],273:[function(require,module,exports){ /** - * @fileoverview Rule to flag wrapping non-iife in parens - * @author Ilya Volodin - * @copyright 2013 Ilya Volodin. All rights reserved. + * @fileoverview Disallows or enforces spaces inside of object literals. + * @author Jamund Ferguson + * @copyright 2014 Brandyn Bennett. All rights reserved. + * @copyright 2014 Michael Ficarra. No rights reserved. + * @copyright 2014 Vignesh Anand. All rights reserved. + * @copyright 2015 Jamund Ferguson. All rights reserved. + * @copyright 2015 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. */ - "use strict"; +var astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var spaced = context.options[0] === "always", + sourceCode = context.getSourceCode(); /** - * Checks a function expression to see if its surrounded by parens. - * @param {ASTNode} node The node to check. + * Determines whether an option is set, relative to the spacing option. + * If spaced is "always", then check whether option is set to false. + * If spaced is "never", then check whether option is set to true. + * @param {Object} option - The option to exclude. + * @returns {boolean} Whether or not the property is excluded. + */ + function isOptionSet(option) { + return context.options[1] ? context.options[1][option] === !spaced : false; + } + + var options = { + spaced: spaced, + arraysInObjectsException: isOptionSet("arraysInObjects"), + objectsInObjectsException: isOptionSet("objectsInObjects") + }; + + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + + /** + * Reports that there shouldn't be a space after the first token + * @param {ASTNode} node - The node to report in the event of an error. + * @param {Token} token - The token to use for the report. + * @returns {void} + */ + function reportNoBeginningSpace(node, token) { + context.report({ + node: node, + loc: token.loc.end, + message: "There should be no space after '" + token.value + "'", + fix: function(fixer) { + var nextToken = context.getSourceCode().getTokenAfter(token); + return fixer.removeRange([token.range[1], nextToken.range[0]]); + } + }); + } + + /** + * Reports that there shouldn't be a space before the last token + * @param {ASTNode} node - The node to report in the event of an error. + * @param {Token} token - The token to use for the report. + * @returns {void} + */ + function reportNoEndingSpace(node, token) { + context.report({ + node: node, + loc: token.loc.start, + message: "There should be no space before '" + token.value + "'", + fix: function(fixer) { + var previousToken = context.getSourceCode().getTokenBefore(token); + return fixer.removeRange([previousToken.range[1], token.range[0]]); + } + }); + } + + /** + * Reports that there should be a space after the first token + * @param {ASTNode} node - The node to report in the event of an error. + * @param {Token} token - The token to use for the report. + * @returns {void} + */ + function reportRequiredBeginningSpace(node, token) { + context.report({ + node: node, + loc: token.loc.end, + message: "A space is required after '" + token.value + "'", + fix: function(fixer) { + return fixer.insertTextAfter(token, " "); + } + }); + } + + /** + * Reports that there should be a space before the last token + * @param {ASTNode} node - The node to report in the event of an error. + * @param {Token} token - The token to use for the report. + * @returns {void} + */ + function reportRequiredEndingSpace(node, token) { + context.report({ + node: node, + loc: token.loc.start, + message: "A space is required before '" + token.value + "'", + fix: function(fixer) { + return fixer.insertTextBefore(token, " "); + } + }); + } + + /** + * Determines if spacing in curly braces is valid. + * @param {ASTNode} node The AST node to check. + * @param {Token} first The first token to check (should be the opening brace) + * @param {Token} second The second token to check (should be first after the opening brace) + * @param {Token} penultimate The penultimate token to check (should be last before closing brace) + * @param {Token} last The last token to check (should be closing brace) * @returns {void} - * @private */ - function checkFunction(node) { - var ancestors = context.getAncestors(), - previousToken, nextToken; + function validateBraceSpacing(node, first, second, penultimate, last) { + var closingCurlyBraceMustBeSpaced = + options.arraysInObjectsException && penultimate.value === "]" || + options.objectsInObjectsException && penultimate.value === "}" + ? !options.spaced : options.spaced, + firstSpaced, lastSpaced; - if (!/CallExpression|NewExpression/.test(ancestors.pop().type)) { - previousToken = context.getTokenBefore(node); - nextToken = context.getTokenAfter(node); - if (previousToken.value === "(" && nextToken.value === ")") { - context.report(node, "Wrapping non-IIFE function literals in parens is unnecessary."); + if (astUtils.isTokenOnSameLine(first, second)) { + firstSpaced = sourceCode.isSpaceBetweenTokens(first, second); + if (options.spaced && !firstSpaced) { + reportRequiredBeginningSpace(node, first); } + if (!options.spaced && firstSpaced) { + reportNoBeginningSpace(node, first); + } } + + if (astUtils.isTokenOnSameLine(penultimate, last)) { + lastSpaced = sourceCode.isSpaceBetweenTokens(penultimate, last); + if (closingCurlyBraceMustBeSpaced && !lastSpaced) { + reportRequiredEndingSpace(node, last); + } + if (!closingCurlyBraceMustBeSpaced && lastSpaced) { + reportNoEndingSpace(node, last); + } + } } + /** + * Reports a given object node if spacing in curly braces is invalid. + * @param {ASTNode} node - An ObjectExpression or ObjectPattern node to check. + * @returns {void} + */ + function checkForObject(node) { + if (node.properties.length === 0) { + return; + } + + var first = sourceCode.getFirstToken(node), + last = sourceCode.getLastToken(node), + second = sourceCode.getTokenAfter(first), + penultimate = sourceCode.getTokenBefore(last); + + validateBraceSpacing(node, first, second, penultimate, last); + } + + /** + * Reports a given import node if spacing in curly braces is invalid. + * @param {ASTNode} node - An ImportDeclaration node to check. + * @returns {void} + */ + function checkForImport(node) { + if (node.specifiers.length === 0) { + return; + } + + var firstSpecifier = node.specifiers[0], + lastSpecifier = node.specifiers[node.specifiers.length - 1]; + + if (lastSpecifier.type !== "ImportSpecifier") { + return; + } + if (firstSpecifier.type !== "ImportSpecifier") { + firstSpecifier = node.specifiers[1]; + } + + var first = sourceCode.getTokenBefore(firstSpecifier), + last = sourceCode.getTokenAfter(lastSpecifier); + + // to support a trailing comma. + if (last.value === ",") { + last = sourceCode.getTokenAfter(last); + } + + var second = sourceCode.getTokenAfter(first), + penultimate = sourceCode.getTokenBefore(last); + + validateBraceSpacing(node, first, second, penultimate, last); + } + + /** + * Reports a given export node if spacing in curly braces is invalid. + * @param {ASTNode} node - An ExportNamedDeclaration node to check. + * @returns {void} + */ + function checkForExport(node) { + if (node.specifiers.length === 0) { + return; + } + + var firstSpecifier = node.specifiers[0], + lastSpecifier = node.specifiers[node.specifiers.length - 1], + first = sourceCode.getTokenBefore(firstSpecifier), + last = sourceCode.getTokenAfter(lastSpecifier); + + // to support a trailing comma. + if (last.value === ",") { + last = sourceCode.getTokenAfter(last); + } + + var second = sourceCode.getTokenAfter(first), + penultimate = sourceCode.getTokenBefore(last); + + validateBraceSpacing(node, first, second, penultimate, last); + } + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + return { - "ArrowFunctionExpression": checkFunction, - "FunctionExpression": checkFunction + // var {x} = y; + ObjectPattern: checkForObject, + + // var y = {x: 'y'} + ObjectExpression: checkForObject, + + // import {y} from 'x'; + ImportDeclaration: checkForImport, + + // export {name} from 'yo'; + ExportNamedDeclaration: checkForExport }; }; -},{}],258:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["always", "never"] + }, + { + "type": "object", + "properties": { + "arraysInObjects": { + "type": "boolean" + }, + "objectsInObjects": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{"../ast-utils":113}],274:[function(require,module,exports){ /** - * @fileoverview A rule to ensure the use of a single variable declaration. + * @fileoverview Rule to enforce concise object methods and properties. + * @author Jamund Ferguson + * @copyright 2015 Jamund Ferguson. All rights reserved. + */ + +"use strict"; + +var OPTIONS = { + always: "always", + never: "never", + methods: "methods", + properties: "properties" +}; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + var APPLY = context.options[0] || OPTIONS.always; + var APPLY_TO_METHODS = APPLY === OPTIONS.methods || APPLY === OPTIONS.always; + var APPLY_TO_PROPS = APPLY === OPTIONS.properties || APPLY === OPTIONS.always; + var APPLY_NEVER = APPLY === OPTIONS.never; + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + return { + "Property": function(node) { + var isConciseProperty = node.method || node.shorthand, + type; + + // if we're "never" and concise we should warn now + if (APPLY_NEVER && isConciseProperty) { + type = node.method ? "method" : "property"; + context.report(node, "Expected longform " + type + " syntax."); + } + + // at this point if we're concise or if we're "never" we can leave + if (APPLY_NEVER || isConciseProperty) { + return; + } + + // getters, setters and computed properties are ignored + if (node.kind === "get" || node.kind === "set" || node.computed) { + return; + } + + if (node.value.type === "FunctionExpression" && !node.value.id && APPLY_TO_METHODS) { + + // {x: function(){}} should be written as {x() {}} + context.report(node, "Expected method shorthand."); + } else if (node.value.type === "Identifier" && node.key.name === node.value.name && APPLY_TO_PROPS) { + + // {x: x} should be written as {x} + context.report(node, "Expected property shorthand."); + } else if (node.value.type === "Identifier" && node.key.type === "Literal" && node.key.value === node.value.name && APPLY_TO_PROPS) { + + // {"x": x} should be written as {x} + context.report(node, "Expected property shorthand."); + } + } + }; + +}; + +module.exports.schema = [ + { + "enum": ["always", "methods", "properties", "never"] + } +]; + +},{}],275:[function(require,module,exports){ +/** + * @fileoverview A rule to control the use of single variable declarations. * @author Ian Christian Myers + * @copyright 2015 Ian VanSchooten. All rights reserved. + * @copyright 2015 Joey Baker. All rights reserved. + * @copyright 2015 Danny Fritz. All rights reserved. * @copyright 2013 Ian Christian Myers. All rights reserved. */ "use strict"; @@ -26424,53 +38160,310 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var MODE_ALWAYS = "always", + MODE_NEVER = "never"; + + var mode = context.options[0] || MODE_ALWAYS; + + var options = { + }; + + if (typeof mode === "string") { // simple options configuration with just a string + options.var = { uninitialized: mode, initialized: mode}; + options.let = { uninitialized: mode, initialized: mode}; + options.const = { uninitialized: mode, initialized: mode}; + } else if (typeof mode === "object") { // options configuration is an object + if (mode.hasOwnProperty("var") && typeof mode.var === "string") { + options.var = { uninitialized: mode.var, initialized: mode.var}; + } + if (mode.hasOwnProperty("let") && typeof mode.let === "string") { + options.let = { uninitialized: mode.let, initialized: mode.let}; + } + if (mode.hasOwnProperty("const") && typeof mode.const === "string") { + options.const = { uninitialized: mode.const, initialized: mode.const}; + } + if (mode.hasOwnProperty("uninitialized")) { + if (!options.var) { + options.var = {}; + } + if (!options.let) { + options.let = {}; + } + if (!options.const) { + options.const = {}; + } + options.var.uninitialized = mode.uninitialized; + options.let.uninitialized = mode.uninitialized; + options.const.uninitialized = mode.uninitialized; + } + if (mode.hasOwnProperty("initialized")) { + if (!options.var) { + options.var = {}; + } + if (!options.let) { + options.let = {}; + } + if (!options.const) { + options.const = {}; + } + options.var.initialized = mode.initialized; + options.let.initialized = mode.initialized; + options.const.initialized = mode.initialized; + } + } + //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- var functionStack = []; + var blockStack = []; + /** + * Increments the blockStack counter. + * @returns {void} + * @private + */ + function startBlock() { + blockStack.push({ + let: {initialized: false, uninitialized: false}, + const: {initialized: false, uninitialized: false} + }); + } + + /** + * Increments the functionStack counter. + * @returns {void} + * @private + */ function startFunction() { - functionStack.push(false); + functionStack.push({initialized: false, uninitialized: false}); + startBlock(); } + /** + * Decrements the blockStack counter. + * @returns {void} + * @private + */ + function endBlock() { + blockStack.pop(); + } + + /** + * Decrements the functionStack counter. + * @returns {void} + * @private + */ function endFunction() { functionStack.pop(); + endBlock(); } - function checkDeclarations(node) { - if (functionStack[functionStack.length - 1]) { - context.report(node, "Combine this with the previous 'var' statement."); - } else { - functionStack[functionStack.length - 1] = true; + /** + * Records whether initialized or uninitialized variables are defined in current scope. + * @param {string} statementType node.kind, one of: "var", "let", or "const" + * @param {ASTNode[]} declarations List of declarations + * @param {Object} currentScope The scope being investigated + * @returns {void} + * @private + */ + function recordTypes(statementType, declarations, currentScope) { + for (var i = 0; i < declarations.length; i++) { + if (declarations[i].init === null) { + if (options[statementType] && options[statementType].uninitialized === MODE_ALWAYS) { + currentScope.uninitialized = true; + } + } else { + if (options[statementType] && options[statementType].initialized === MODE_ALWAYS) { + currentScope.initialized = true; + } + } } } + /** + * Determines the current scope (function or block) + * @param {string} statementType node.kind, one of: "var", "let", or "const" + * @returns {Object} The scope associated with statementType + */ + function getCurrentScope(statementType) { + var currentScope; + if (statementType === "var") { + currentScope = functionStack[functionStack.length - 1]; + } else if (statementType === "let") { + currentScope = blockStack[blockStack.length - 1].let; + } else if (statementType === "const") { + currentScope = blockStack[blockStack.length - 1].const; + } + return currentScope; + } + + /** + * Counts the number of initialized and uninitialized declarations in a list of declarations + * @param {ASTNode[]} declarations List of declarations + * @returns {Object} Counts of 'uninitialized' and 'initialized' declarations + * @private + */ + function countDeclarations(declarations) { + var counts = { uninitialized: 0, initialized: 0 }; + for (var i = 0; i < declarations.length; i++) { + if (declarations[i].init === null) { + counts.uninitialized++; + } else { + counts.initialized++; + } + } + return counts; + } + + /** + * Determines if there is more than one var statement in the current scope. + * @param {string} statementType node.kind, one of: "var", "let", or "const" + * @param {ASTNode[]} declarations List of declarations + * @returns {boolean} Returns true if it is the first var declaration, false if not. + * @private + */ + function hasOnlyOneStatement(statementType, declarations) { + + var declarationCounts = countDeclarations(declarations); + var currentOptions = options[statementType] || {}; + var currentScope = getCurrentScope(statementType); + + if (currentOptions.uninitialized === MODE_ALWAYS && currentOptions.initialized === MODE_ALWAYS) { + if (currentScope.uninitialized || currentScope.initialized) { + return false; + } + } + + if (declarationCounts.uninitialized > 0) { + if (currentOptions.uninitialized === MODE_ALWAYS && currentScope.uninitialized) { + return false; + } + } + if (declarationCounts.initialized > 0) { + if (currentOptions.initialized === MODE_ALWAYS && currentScope.initialized) { + return false; + } + } + recordTypes(statementType, declarations, currentScope); + return true; + } + + //-------------------------------------------------------------------------- // Public API //-------------------------------------------------------------------------- return { "Program": startFunction, "FunctionDeclaration": startFunction, "FunctionExpression": startFunction, "ArrowFunctionExpression": startFunction, + "BlockStatement": startBlock, + "ForStatement": startBlock, + "ForInStatement": startBlock, + "ForOfStatement": startBlock, + "SwitchStatement": startBlock, - "VariableDeclaration": checkDeclarations, + "VariableDeclaration": function(node) { + var parent = node.parent, + type, declarations, declarationCounts; + type = node.kind; + if (!options[type]) { + return; + } + + declarations = node.declarations; + declarationCounts = countDeclarations(declarations); + + // always + if (!hasOnlyOneStatement(type, declarations)) { + if (options[type].initialized === MODE_ALWAYS && options[type].uninitialized === MODE_ALWAYS) { + context.report(node, "Combine this with the previous '" + type + "' statement."); + } else { + if (options[type].initialized === MODE_ALWAYS) { + context.report(node, "Combine this with the previous '" + type + "' statement with initialized variables."); + } + if (options[type].uninitialized === MODE_ALWAYS) { + context.report(node, "Combine this with the previous '" + type + "' statement with uninitialized variables."); + } + } + } + // never + if (parent.type !== "ForStatement" || parent.init !== node) { + var totalDeclarations = declarationCounts.uninitialized + declarationCounts.initialized; + if (totalDeclarations > 1) { + // both initialized and uninitialized + if (options[type].initialized === MODE_NEVER && options[type].uninitialized === MODE_NEVER) { + context.report(node, "Split '" + type + "' declarations into multiple statements."); + // initialized + } else if (options[type].initialized === MODE_NEVER && declarationCounts.initialized > 0) { + context.report(node, "Split initialized '" + type + "' declarations into multiple statements."); + // uninitialized + } else if (options[type].uninitialized === MODE_NEVER && declarationCounts.uninitialized > 0) { + context.report(node, "Split uninitialized '" + type + "' declarations into multiple statements."); + } + } + } + }, + + "ForStatement:exit": endBlock, + "ForOfStatement:exit": endBlock, + "ForInStatement:exit": endBlock, + "SwitchStatement:exit": endBlock, + "BlockStatement:exit": endBlock, "Program:exit": endFunction, "FunctionDeclaration:exit": endFunction, "FunctionExpression:exit": endFunction, "ArrowFunctionExpression:exit": endFunction }; }; -},{}],259:[function(require,module,exports){ +module.exports.schema = [ + { + "oneOf": [ + { + "enum": ["always", "never"] + }, + { + "type": "object", + "properties": { + "var": { + "enum": ["always", "never"] + }, + "let": { + "enum": ["always", "never"] + }, + "const": { + "enum": ["always", "never"] + } + }, + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "initialized": { + "enum": ["always", "never"] + }, + "uninitialized": { + "enum": ["always", "never"] + } + }, + "additionalProperties": false + } + ] + } +]; + +},{}],276:[function(require,module,exports){ /** * @fileoverview Rule to replace assignment expressions with operator assignment * @author Brandon Mills * @copyright 2014 Brandon Mills. All rights reserved. */ @@ -26580,12 +38573,167 @@ "AssignmentExpression": context.options[0] !== "never" ? verify : prohibit }; }; -},{}],260:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["always", "never"] + } +]; + +},{}],277:[function(require,module,exports){ /** + * @fileoverview Operator linebreak - enforces operator linebreak style of two types: after and before + * @author Benoît Zugmeyer + * @copyright 2015 Benoît Zugmeyer. All rights reserved. + */ + +"use strict"; + +var assign = require("object-assign"), + astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + var usedDefaultGlobal = !context.options[0]; + var globalStyle = context.options[0] || "after"; + var options = context.options[1] || {}; + var styleOverrides = options.overrides ? assign({}, options.overrides) : {}; + + if (usedDefaultGlobal && !styleOverrides["?"]) { + styleOverrides["?"] = "before"; + } + + if (usedDefaultGlobal && !styleOverrides[":"]) { + styleOverrides[":"] = "before"; + } + + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + + /** + * Checks the operator placement + * @param {ASTNode} node The node to check + * @param {ASTNode} leftSide The node that comes before the operator in `node` + * @private + * @returns {void} + */ + function validateNode(node, leftSide) { + var leftToken = context.getLastToken(leftSide); + var operatorToken = context.getTokenAfter(leftToken); + + // When the left part of a binary expression is a single expression wrapped in + // parentheses (ex: `(a) + b`), leftToken will be the last token of the expression + // and operatorToken will be the closing parenthesis. + // The leftToken should be the last closing parenthesis, and the operatorToken + // should be the token right after that. + while (operatorToken.value === ")") { + leftToken = operatorToken; + operatorToken = context.getTokenAfter(operatorToken); + } + + var rightToken = context.getTokenAfter(operatorToken); + var operator = operatorToken.value; + var style = styleOverrides[operator] || globalStyle; + + // if single line + if (astUtils.isTokenOnSameLine(leftToken, operatorToken) && + astUtils.isTokenOnSameLine(operatorToken, rightToken)) { + + return; + + } else if (!astUtils.isTokenOnSameLine(leftToken, operatorToken) && + !astUtils.isTokenOnSameLine(operatorToken, rightToken)) { + + // lone operator + context.report(node, { + line: operatorToken.loc.end.line, + column: operatorToken.loc.end.column + }, "Bad line breaking before and after '" + operator + "'."); + + } else if (style === "before" && astUtils.isTokenOnSameLine(leftToken, operatorToken)) { + + context.report(node, { + line: operatorToken.loc.end.line, + column: operatorToken.loc.end.column + }, "'" + operator + "' should be placed at the beginning of the line."); + + } else if (style === "after" && astUtils.isTokenOnSameLine(operatorToken, rightToken)) { + + context.report(node, { + line: operatorToken.loc.end.line, + column: operatorToken.loc.end.column + }, "'" + operator + "' should be placed at the end of the line."); + + } else if (style === "none") { + + context.report(node, { + line: operatorToken.loc.end.line, + column: operatorToken.loc.end.column + }, "There should be no line break before or after '" + operator + "'"); + + } + } + + /** + * Validates a binary expression using `validateNode` + * @param {BinaryExpression|LogicalExpression|AssignmentExpression} node node to be validated + * @returns {void} + */ + function validateBinaryExpression(node) { + validateNode(node, node.left); + } + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + return { + "BinaryExpression": validateBinaryExpression, + "LogicalExpression": validateBinaryExpression, + "AssignmentExpression": validateBinaryExpression, + "VariableDeclarator": function(node) { + if (node.init) { + validateNode(node, node.id); + } + }, + "ConditionalExpression": function(node) { + validateNode(node, node.test); + validateNode(node, node.consequent); + } + }; +}; + +module.exports.schema = [ + { + "enum": ["after", "before", "none", null] + }, + { + "type": "object", + "properties": { + "overrides": { + "type": "object", + "properties": { + "anyOf": { + "type": "string", + "enum": ["after", "before", "none"] + } + } + } + }, + "additionalProperties": false + } +]; + +},{"../ast-utils":113,"object-assign":108}],278:[function(require,module,exports){ +/** * @fileoverview A rule to ensure blank lines within blocks. * @author Mathias Schreck <https://github.com/lo1tuma> * @copyright 2014 Mathias Schreck. All rights reserved. */ @@ -26593,171 +38741,966 @@ //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = function (context) { +module.exports = function(context) { var requirePadding = context.options[0] !== "never"; + var ALWAYS_MESSAGE = "Block must be padded by blank lines.", + NEVER_MESSAGE = "Block must not be padded by blank lines."; + /** + * Retrieves an array of all comments defined inside the given node. + * @param {ASTNode} node The AST node. + * @returns {ASTNode[]} An array of comment nodes. + */ + function getCommentsInNode(node) { + var allComments = context.getAllComments(); + + return allComments.filter(function(comment) { + return node.range[0] < comment.range[0] && + node.range[1] > comment.range[1]; + }); + } + + /** + * Checks if the location of a node or token is before the location of another node or token + * @param {ASTNode|Token} a The node or token to check if its location is before b. + * @param {ASTNode|Token} b The node or token which will be compared with a. + * @returns {boolean} True if a is located before b. + */ + function isLocatedBefore(a, b) { + return a.range[1] < b.range[0]; + } + + /** * Checks if the given non empty block node has a blank line before its first child node. * @param {ASTNode} node The AST node of a BlockStatement. * @returns {boolean} Whether or not the block starts with a blank line. */ - function isNonEmptyBlockTopPadded(node) { + function isBlockTopPadded(node) { var blockStart = node.loc.start.line, first = node.body[0], firstLine = first.loc.start.line, expectedFirstLine = blockStart + 2, - leadingComments = context.getComments(first).leading; + comments = getCommentsInNode(node), + firstComment = comments[0]; - if (leadingComments.length > 0) { - firstLine = leadingComments[0].loc.start.line; + if (firstComment && isLocatedBefore(firstComment, first)) { + firstLine = firstComment.loc.start.line; } return expectedFirstLine <= firstLine; } /** * Checks if the given non empty block node has a blank line after its last child node. * @param {ASTNode} node The AST node of a BlockStatement. * @returns {boolean} Whether or not the block ends with a blank line. */ - function isNonEmptyBlockBottomPadded(node) { + function isBlockBottomPadded(node) { var blockEnd = node.loc.end.line, last = node.body[node.body.length - 1], - lastLine = last.loc.end.line, + lastToken = context.getLastToken(last), + lastLine = lastToken.loc.end.line, expectedLastLine = blockEnd - 2, - trailingComments = context.getComments(last).trailing; + comments = getCommentsInNode(node), + lastComment = comments[comments.length - 1]; - if (trailingComments.length > 0) { - lastLine = trailingComments[trailingComments.length - 1].loc.end.line; + if (lastComment && isLocatedBefore(lastToken, lastComment)) { + lastLine = lastComment.loc.end.line; } return lastLine <= expectedLastLine; } /** - * Checks if the given non empty block node starts AND ends with a blank line. - * @param {ASTNode} node The AST node of a BlockStatement. - * @returns {boolean} Whether or not the block starts and ends with a blank line. - */ - function isNonEmptyBlockPadded(node) { - return isNonEmptyBlockTopPadded(node) && isNonEmptyBlockBottomPadded(node); - } - - /** - * Checks if the given non empty block node starts OR ends with a blank line. - * @param {ASTNode} node The AST node of a BlockStatement. - * @returns {boolean} Whether or not the block starts and ends with a blank line. - */ - function hasNonEmptyBlockExtraPadding(node) { - return isNonEmptyBlockTopPadded(node) || isNonEmptyBlockBottomPadded(node); - } - - /** * Checks the given BlockStatement node to be padded if the block is not empty. * @param {ASTNode} node The AST node of a BlockStatement. * @returns {void} undefined. */ function checkPadding(node) { if (node.body.length > 0) { + + var blockHasTopPadding = isBlockTopPadded(node), + blockHasBottomPadding = isBlockBottomPadded(node); + if (requirePadding) { - if (!isNonEmptyBlockPadded(node)) { - context.report(node, "Block must be padded by blank lines."); + if (!blockHasTopPadding) { + context.report(node, ALWAYS_MESSAGE); } + + if (!blockHasBottomPadding) { + context.report(node, node.loc.end, ALWAYS_MESSAGE); + } } else { - if (hasNonEmptyBlockExtraPadding(node)) { - context.report(node, "Block must not be padded by blank lines."); + if (blockHasTopPadding) { + context.report(node, NEVER_MESSAGE); } + + if (blockHasBottomPadding) { + context.report(node, node.loc.end, NEVER_MESSAGE); + } } } } return { "BlockStatement": checkPadding }; }; -},{}],261:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["always", "never"] + } +]; + +},{}],279:[function(require,module,exports){ /** + * @fileoverview A rule to suggest using arrow functions as callbacks. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Checks whether or not a given variable is a function name. + * @param {escope.Variable} variable - A variable to check. + * @returns {boolean} `true` if the variable is a function name. + */ +function isFunctionName(variable) { + return variable && variable.defs[0].type === "FunctionName"; +} + +/** + * Checks whether or not a given MetaProperty node equals to a given value. + * @param {ASTNode} node - A MetaProperty node to check. + * @param {string} metaName - The name of `MetaProperty.meta`. + * @param {string} propertyName - The name of `MetaProperty.property`. + * @returns {boolean} `true` if the node is the specific value. + */ +function checkMetaProperty(node, metaName, propertyName) { + // TODO: Remove this if block after https://github.com/eslint/espree/issues/206 was fixed. + if (typeof node.meta === "string") { + return node.meta === metaName && node.property === propertyName; + } + return node.meta.name === metaName && node.property.name === propertyName; +} + +/** + * Gets the variable object of `arguments` which is defined implicitly. + * @param {escope.Scope} scope - A scope to get. + * @returns {escope.Variable} The found variable object. + */ +function getVariableOfArguments(scope) { + var variables = scope.variables; + for (var i = 0; i < variables.length; ++i) { + var variable = variables[i]; + if (variable.name === "arguments") { + // If there was a parameter which is named "arguments", the implicit "arguments" is not defined. + // So does fast return with null. + return (variable.identifiers.length === 0) ? variable : null; + } + } + + /* istanbul ignore next */ + return null; +} + +/** + * Checkes whether or not a given node is a callback. + * @param {ASTNode} node - A node to check. + * @returns {object} + * {boolean} retv.isCallback - `true` if the node is a callback. + * {boolean} retv.isLexicalThis - `true` if the node is with `.bind(this)`. + */ +function getCallbackInfo(node) { + var retv = {isCallback: false, isLexicalThis: false}; + var parent = node.parent; + while (node) { + switch (parent.type) { + // Checks parents recursively. + case "LogicalExpression": + case "ConditionalExpression": + break; + + // Checks whether the parent node is `.bind(this)` call. + case "MemberExpression": + if (parent.object === node && + !parent.property.computed && + parent.property.type === "Identifier" && + parent.property.name === "bind" && + parent.parent.type === "CallExpression" && + parent.parent.callee === parent + ) { + retv.isLexicalThis = ( + parent.parent.arguments.length === 1 && + parent.parent.arguments[0].type === "ThisExpression" + ); + node = parent; + parent = parent.parent; + } else { + return retv; + } + break; + + // Checks whether the node is a callback. + case "CallExpression": + case "NewExpression": + if (parent.callee !== node) { + retv.isCallback = true; + } + return retv; + + default: + return retv; + } + + node = parent; + parent = parent.parent; + } + + /* istanbul ignore next */ + throw new Error("unreachable"); +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + // {Array<{this: boolean, super: boolean, meta: boolean}>} + // - this - A flag which shows there are one or more ThisExpression. + // - super - A flag which shows there are one or more Super. + // - meta - A flag which shows there are one or more MethProperty. + var stack = []; + + /** + * Pushes new function scope with all `false` flags. + * @returns {void} + */ + function enterScope() { + stack.push({this: false, super: false, meta: false}); + } + + /** + * Pops a function scope from the stack. + * @returns {{this: boolean, super: boolean, meta: boolean}} The information of the last scope. + */ + function exitScope() { + return stack.pop(); + } + + return { + // Reset internal state. + Program: function() { + stack = []; + }, + + // If there are below, it cannot replace with arrow functions merely. + ThisExpression: function() { + var info = stack[stack.length - 1]; + if (info) { + info.this = true; + } + }, + Super: function() { + var info = stack[stack.length - 1]; + if (info) { + info.super = true; + } + }, + MetaProperty: function(node) { + var info = stack[stack.length - 1]; + if (info && checkMetaProperty(node, "new", "target")) { + info.meta = true; + } + }, + + // To skip nested scopes. + FunctionDeclaration: enterScope, + "FunctionDeclaration:exit": exitScope, + + // Main. + FunctionExpression: enterScope, + "FunctionExpression:exit": function(node) { + var scopeInfo = exitScope(); + + // Skip generators. + if (node.generator) { + return; + } + + // Skip recursive functions. + var nameVar = context.getDeclaredVariables(node)[0]; + if (isFunctionName(nameVar) && nameVar.references.length > 0) { + return; + } + + // Skip if it's using arguments. + var variable = getVariableOfArguments(context.getScope()); + if (variable && variable.references.length > 0) { + return; + } + + // Reports if it's a callback which can replace with arrows. + var callbackInfo = getCallbackInfo(node); + if (callbackInfo.isCallback && + (!scopeInfo.this || callbackInfo.isLexicalThis) && + !scopeInfo.super && + !scopeInfo.meta + ) { + context.report(node, "Unexpected function expression."); + } + } + }; +}; + +module.exports.schema = []; + +},{}],280:[function(require,module,exports){ +/** + * @fileoverview A rule to suggest using of const declaration for variables that are never modified after declared. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + /** + * Checks whether a reference is the initializer. + * @param {Reference} reference - A reference to check. + * @returns {boolean} Whether or not the reference is the initializer. + */ + function isInitializer(reference) { + return reference.init === true; + } + + /** + * Checks whether a reference is read-only or the initializer. + * @param {Reference} reference - A reference to check. + * @returns {boolean} Whether or not the reference is read-only or the initializer. + */ + function isReadOnlyOrInitializer(reference) { + return reference.isReadOnly() || reference.init === true; + } + + /** + * Searches and reports variables that are never modified after declared. + * @param {Scope} scope - A scope of the search domain. + * @returns {void} + */ + function checkForVariables(scope) { + // Skip the TDZ type. + if (scope.type === "TDZ") { + return; + } + + var variables = scope.variables; + for (var i = 0, end = variables.length; i < end; ++i) { + var variable = variables[i]; + var def = variable.defs[0]; + var declaration = def && def.parent; + var statement = declaration && declaration.parent; + var references = variable.references; + var identifier = variable.identifiers[0]; + + if (statement && + identifier && + declaration.type === "VariableDeclaration" && + declaration.kind === "let" && + (statement.type !== "ForStatement" || statement.init !== declaration) && + references.some(isInitializer) && + references.every(isReadOnlyOrInitializer) + ) { + context.report( + identifier, + "`{{name}}` is never modified, use `const` instead.", + {name: identifier.name}); + } + } + } + + /** + * Adds multiple items to the tail of an array. + * @param {any[]} array - A destination to add. + * @param {any[]} values - Items to be added. + * @returns {void} + */ + var pushAll = Function.apply.bind(Array.prototype.push); + + return { + "Program:exit": function() { + var stack = [context.getScope()]; + while (stack.length) { + var scope = stack.pop(); + pushAll(stack, scope.childScopes); + + checkForVariables(scope); + } + } + }; + +}; + +module.exports.schema = []; + +},{}],281:[function(require,module,exports){ +/** + * @fileoverview Rule to suggest using "Reflect" api over Function/Object methods + * @author Keith Cirkel <http://keithcirkel.co.uk> + * @copyright 2015 Keith Cirkel. All rights reserved. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var existingNames = { + "apply": "Function.prototype.apply", + "call": "Function.prototype.call", + "defineProperty": "Object.defineProperty", + "getOwnPropertyDescriptor": "Object.getOwnPropertyDescriptor", + "getPrototypeOf": "Object.getPrototypeOf", + "setPrototypeOf": "Object.setPrototypeOf", + "isExtensible": "Object.isExtensible", + "getOwnPropertyNames": "Object.getOwnPropertyNames", + "preventExtensions": "Object.preventExtensions" + }; + + var reflectSubsitutes = { + "apply": "Reflect.apply", + "call": "Reflect.apply", + "defineProperty": "Reflect.defineProperty", + "getOwnPropertyDescriptor": "Reflect.getOwnPropertyDescriptor", + "getPrototypeOf": "Reflect.getPrototypeOf", + "setPrototypeOf": "Reflect.setPrototypeOf", + "isExtensible": "Reflect.isExtensible", + "getOwnPropertyNames": "Reflect.getOwnPropertyNames", + "preventExtensions": "Reflect.preventExtensions" + }; + + var exceptions = (context.options[0] || {}).exceptions || []; + + /** + * Reports the Reflect violation based on the `existing` and `substitute` + * @param {Object} node The node that violates the rule. + * @param {string} existing The existing method name that has been used. + * @param {string} substitute The Reflect substitute that should be used. + * @returns {void} + */ + function report(node, existing, substitute) { + context.report(node, "Avoid using {{existing}}, instead use {{substitute}}", { + existing: existing, + substitute: substitute + }); + } + + return { + "CallExpression": function(node) { + var methodName = (node.callee.property || {}).name; + var isReflectCall = (node.callee.object || {}).name === "Reflect"; + var hasReflectSubsitute = reflectSubsitutes.hasOwnProperty(methodName); + var userConfiguredException = exceptions.indexOf(methodName) !== -1; + if (hasReflectSubsitute && !isReflectCall && !userConfiguredException) { + report(node, existingNames[methodName], reflectSubsitutes[methodName]); + } + }, + "UnaryExpression": function(node) { + var isDeleteOperator = node.operator === "delete"; + var targetsIdentifier = node.argument.type === "Identifier"; + var userConfiguredException = exceptions.indexOf("delete") !== -1; + if (isDeleteOperator && !targetsIdentifier && !userConfiguredException) { + report(node, "the delete keyword", "Reflect.deleteProperty"); + } + } + }; + +}; + +module.exports.schema = [ + { + "type": "object", + "properties": { + "exceptions": { + "type": "array", + "items": { + "enum": [ + "apply", + "call", + "delete", + "defineProperty", + "getOwnPropertyDescriptor", + "getPrototypeOf", + "setPrototypeOf", + "isExtensible", + "getOwnPropertyNames", + "preventExtensions" + ] + }, + "uniqueItems": true + } + }, + "additionalProperties": false + } +]; + +},{}],282:[function(require,module,exports){ +/** + * @fileoverview A rule to suggest using of the spread operator instead of `.apply()`. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + */ + +"use strict"; + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Checks whether or not a node is a `.apply()` for variadic. + * @param {ASTNode} node - A CallExpression node to check. + * @returns {boolean} Whether or not the node is a `.apply()` for variadic. + */ +function isVariadicApplyCalling(node) { + return ( + node.callee.type === "MemberExpression" && + node.callee.property.type === "Identifier" && + node.callee.property.name === "apply" && + node.callee.computed === false && + node.arguments.length === 2 && + node.arguments[1].type !== "ArrayExpression" + ); +} + +/** + * Checks whether or not the tokens of two given nodes are same. + * @param {ASTNode} left - A node 1 to compare. + * @param {ASTNode} right - A node 2 to compare. + * @param {RuleContext} context - The ESLint rule context object. + * @returns {boolean} the source code for the given node. + */ +function equalTokens(left, right, context) { + var tokensL = context.getTokens(left); + var tokensR = context.getTokens(right); + + if (tokensL.length !== tokensR.length) { + return false; + } + for (var i = 0; i < tokensL.length; ++i) { + if (tokensL[i].type !== tokensR[i].type || + tokensL[i].value !== tokensR[i].value + ) { + return false; + } + } + + return true; +} + +/** + * Checks whether or not `thisArg` is not changed by `.apply()`. + * @param {ASTNode|null} expectedThis - The node that is the owner of the applied function. + * @param {ASTNode} thisArg - The node that is given to the first argument of the `.apply()`. + * @param {RuleContext} context - The ESLint rule context object. + * @returns {boolean} Whether or not `thisArg` is not changed by `.apply()`. + */ +function isValidThisArg(expectedThis, thisArg, context) { + if (!expectedThis) { + return astUtils.isNullOrUndefined(thisArg); + } + return equalTokens(expectedThis, thisArg, context); +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + return { + "CallExpression": function(node) { + if (!isVariadicApplyCalling(node)) { + return; + } + + var applied = node.callee.object; + var expectedThis = (applied.type === "MemberExpression") ? applied.object : null; + var thisArg = node.arguments[0]; + + if (isValidThisArg(expectedThis, thisArg, context)) { + context.report(node, "use the spread operator instead of the \".apply()\"."); + } + } + }; +}; + +module.exports.schema = []; + +},{"../ast-utils":113}],283:[function(require,module,exports){ +/** + * @fileoverview A rule to suggest using template literals instead of string concatenation. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Checks whether or not a given node is a concatenation. + * @param {ASTNode} node - A node to check. + * @returns {boolean} `true` if the node is a concatenation. + */ +function isConcatenation(node) { + return node.type === "BinaryExpression" && node.operator === "+"; +} + +/** + * Gets the top binary expression node for concatenation in parents of a given node. + * @param {ASTNode} node - A node to get. + * @returns {ASTNode} the top binary expression node in parents of a given node. + */ +function getTopConcatBinaryExpression(node) { + while (isConcatenation(node.parent)) { + node = node.parent; + } + return node; +} + +/** + * Checks whether or not a given binary expression has non string literals. + * @param {ASTNode} node - A node to check. + * @returns {boolean} `true` if the node has non string literals. + */ +function hasNonStringLiteral(node) { + if (isConcatenation(node)) { + // `left` is deeper than `right` normally. + return hasNonStringLiteral(node.right) || hasNonStringLiteral(node.left); + } + return !astUtils.isStringLiteral(node); +} + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var done = Object.create(null); + + /** + * Reports if a given node is string concatenation with non string literals. + * + * @param {ASTNode} node - A node to check. + * @returns {void} + */ + function checkForStringConcat(node) { + if (!astUtils.isStringLiteral(node) || !isConcatenation(node.parent)) { + return; + } + + var topBinaryExpr = getTopConcatBinaryExpression(node.parent); + + // Checks whether or not this node had been checked already. + if (done[topBinaryExpr.range[0]]) { + return; + } + done[topBinaryExpr.range[0]] = true; + + if (hasNonStringLiteral(topBinaryExpr)) { + context.report( + topBinaryExpr, + "Unexpected string concatenation."); + } + } + + return { + Program: function() { + done = Object.create(null); + }, + + Literal: checkForStringConcat, + TemplateLiteral: checkForStringConcat + }; +}; + +module.exports.schema = []; + +},{"../ast-utils":113}],284:[function(require,module,exports){ +/** * @fileoverview Rule to flag non-quoted property names in object literals. * @author Mathias Bynens <http://mathiasbynens.be/> * @copyright 2014 Brandon Mills. All rights reserved. + * @copyright 2015 Tomasz Olędzki. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -var espree = require("espree"); +var espree = require("espree"), + keywords = require("../util/keywords"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var MODE = context.options[0]; + var MODE = context.options[0], + KEYWORDS = context.options[1] && context.options[1].keywords, + CHECK_UNNECESSARY = !context.options[1] || context.options[1].unnecessary !== false, + NUMBERS = context.options[1] && context.options[1].numbers, + MESSAGE_UNNECESSARY = "Unnecessarily quoted property `{{property}}` found.", + MESSAGE_UNQUOTED = "Unquoted property `{{property}}` found.", + MESSAGE_NUMERIC = "Unquoted number literal `{{property}}` used as key.", + MESSAGE_RESERVED = "Unquoted reserved word `{{property}}` used as key."; + + /** + * Checks whether a certain string constitutes an ES3 token + * @param {string} tokenStr - The string to be checked. + * @returns {boolean} `true` if it is an ES3 token. + */ + function isKeyword(tokenStr) { + return keywords.indexOf(tokenStr) >= 0; + } + + /** + * Checks if an espree-tokenized key has redundant quotes (i.e. whether quotes are unnecessary) + * @param {espreeTokens} tokens The espree-tokenized node key + * @param {boolean} [skipNumberLiterals=false] Indicates whether number literals should be checked + * @returns {boolean} Whether or not a key has redundant quotes. + * @private + */ + function areQuotesRedundant(tokens, skipNumberLiterals) { + return tokens.length === 1 && + (["Identifier", "Keyword", "Null", "Boolean"].indexOf(tokens[0].type) >= 0 || + (tokens[0].type === "Numeric" && !skipNumberLiterals && "" + +tokens[0].value === tokens[0].value)); + } + + /** * Ensures that a property's key is quoted only when necessary * @param {ASTNode} node Property AST node * @returns {void} */ - function asNeeded(node) { + function checkUnnecessaryQuotes(node) { var key = node.key, + isKeywordToken, tokens; + if (node.method || node.computed || node.shorthand) { + return; + } + if (key.type === "Literal" && typeof key.value === "string") { try { tokens = espree.tokenize(key.value); } catch (e) { return; } - if (tokens.length === 1 && - (["Identifier", "Null", "Boolean"].indexOf(tokens[0].type) >= 0 || - (tokens[0].type === "Numeric" && "" + +tokens[0].value === tokens[0].value)) - ) { - context.report(node, "Unnecessarily quoted property `{{value}}` found.", key); + if (tokens.length !== 1) { + return; } + + isKeywordToken = isKeyword(tokens[0].value); + + if (isKeywordToken && KEYWORDS) { + return; + } + + if (CHECK_UNNECESSARY && areQuotesRedundant(tokens, NUMBERS)) { + context.report(node, MESSAGE_UNNECESSARY, {property: key.value}); + } + } else if (KEYWORDS && key.type === "Identifier" && isKeyword(key.name)) { + context.report(node, MESSAGE_RESERVED, {property: key.name}); + } else if (NUMBERS && key.type === "Literal" && typeof key.value === "number") { + context.report(node, MESSAGE_NUMERIC, {property: key.value}); } } /** * Ensures that a property's key is quoted * @param {ASTNode} node Property AST node * @returns {void} */ - function always(node) { + function checkOmittedQuotes(node) { var key = node.key; - if (!(key.type === "Literal" && typeof key.value === "string")) { - context.report(node, "Unquoted property `{{key}}` found.", { - key: key.name || key.value + if (!node.method && !node.computed && !node.shorthand && !(key.type === "Literal" && typeof key.value === "string")) { + context.report(node, MESSAGE_UNQUOTED, { + property: key.name || key.value }); } } + /** + * Ensures that an object's keys are consistently quoted, optionally checks for redundancy of quotes + * @param {ASTNode} node Property AST node + * @param {boolean} checkQuotesRedundancy Whether to check quotes' redundancy + * @returns {void} + */ + function checkConsistency(node, checkQuotesRedundancy) { + var quotes = false, + lackOfQuotes = false, + necessaryQuotes = false; + + node.properties.forEach(function(property) { + var key = property.key, + tokens; + + if (!key || property.method || property.computed || property.shorthand) { + return; + } + + if (key.type === "Literal" && typeof key.value === "string") { + + quotes = true; + + if (checkQuotesRedundancy) { + try { + tokens = espree.tokenize(key.value); + } catch (e) { + necessaryQuotes = true; + return; + } + + necessaryQuotes = necessaryQuotes || !areQuotesRedundant(tokens) || KEYWORDS && isKeyword(tokens[0].value); + } + } else if (KEYWORDS && checkQuotesRedundancy && key.type === "Identifier" && isKeyword(key.name)) { + necessaryQuotes = true; + context.report(node, "Properties should be quoted as `{{property}}` is a reserved word.", {property: key.name}); + } else { + lackOfQuotes = true; + } + + if (quotes && lackOfQuotes) { + context.report(node, "Inconsistently quoted property `{{key}}` found.", { + key: key.name || key.value + }); + } + }); + + if (checkQuotesRedundancy && quotes && !necessaryQuotes) { + context.report(node, "Properties shouldn't be quoted as all quotes are redundant."); + } + } + return { - "Property": MODE === "as-needed" ? asNeeded : always + "Property": function(node) { + if (MODE === "always" || !MODE) { + checkOmittedQuotes(node); + } + if (MODE === "as-needed") { + checkUnnecessaryQuotes(node); + } + }, + "ObjectExpression": function(node) { + if (MODE === "consistent") { + checkConsistency(node, false); + } + if (MODE === "consistent-as-needed") { + checkConsistency(node, true); + } + } }; }; -},{"espree":"espree"}],262:[function(require,module,exports){ +module.exports.schema = { + "anyOf": [ + { + "type": "array", + "items": [ + { + "enum": [0, 1, 2] + }, + { + "enum": ["always", "as-needed", "consistent", "consistent-as-needed"] + } + ], + "minItems": 1, + "maxItems": 2 + }, + { + "type": "array", + "items": [ + { + "enum": [0, 1, 2] + }, + { + "enum": ["always", "as-needed", "consistent", "consistent-as-needed"] + }, + { + "type": "object", + "properties": { + "keywords": { + "type": "boolean" + }, + "unnecessary": { + "type": "boolean" + }, + "numbers": { + "type": "boolean" + } + }, + "additionalProperties": false + } + ], + "minItems": 1, + "maxItems": 3 + } + ] +}; + +},{"../util/keywords":313,"espree":"espree"}],285:[function(require,module,exports){ /** * @fileoverview A rule to choose between single and double quote marks * @author Matt DuVall <http://www.mattduvall.com/>, Brandon Payton + * @copyright 2013 Matt DuVall. All rights reserved. + * See LICENSE file in root directory for full license. */ "use strict"; //------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var astUtils = require("../ast-utils"); + +//------------------------------------------------------------------------------ // Constants //------------------------------------------------------------------------------ var QUOTE_SETTINGS = { "double": { @@ -26767,69 +39710,181 @@ }, "single": { quote: "'", alternateQuote: "\"", description: "singlequote" + }, + "backtick": { + quote: "`", + alternateQuote: "\"", + description: "backtick" } }; +/** + * Switches quoting of javascript string between ' " and ` + * escaping and unescaping as necessary. + * Only escaping of the minimal set of characters is changed. + * Note: escaping of newlines when switching from backtick to other quotes is not handled. + * @param {string} str - A string to convert. + * @returns {string} The string with changed quotes. + * @private + */ +QUOTE_SETTINGS.double.convert = +QUOTE_SETTINGS.single.convert = +QUOTE_SETTINGS.backtick.convert = function(str) { + var newQuote = this.quote; + var oldQuote = str[0]; + if (newQuote === oldQuote) { + return str; + } + return newQuote + str.slice(1, -1).replace(/\\(\${|\r\n?|\n|.)|["'`]|\${|(\r\n?|\n)/g, function(match, escaped, newline) { + if (escaped === oldQuote || oldQuote === "`" && escaped === "${") { + return escaped; // unescape + } + if (match === newQuote || newQuote === "`" && match === "${") { + return "\\" + match; // escape + } + if (newline && oldQuote === "`") { + return "\\n"; // escape newlines + } + return match; + }) + newQuote; +}; -var AVOID_ESCAPE = "avoid-escape"; +var AVOID_ESCAPE = "avoid-escape", + FUNCTION_TYPE = /^(?:Arrow)?Function(?:Declaration|Expression)$/; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + /** + * Determines if a given node is part of JSX syntax. + * @param {ASTNode} node The node to check. + * @returns {boolean} True if the node is a JSX node, false if not. + * @private + */ + function isJSXElement(node) { + return node.type.indexOf("JSX") === 0; + } /** - * Validate that a string passed in is surrounded by the specified character - * @param {string} val The text to check. - * @param {string} character The character to see if it's surrounded by. - * @returns {boolean} True if the text is surrounded by the character, false if not. + * Checks whether or not a given node is a directive. + * The directive is a `ExpressionStatement` which has only a string literal. + * @param {ASTNode} node - A node to check. + * @returns {boolean} Whether or not the node is a directive. * @private */ - function isSurroundedBy(val, character) { - return val[0] === character && val[val.length - 1] === character; + function isDirective(node) { + return ( + node.type === "ExpressionStatement" && + node.expression.type === "Literal" && + typeof node.expression.value === "string" + ); } /** - * Determines if a given node is part of JSX syntax. - * @param {ASTNode} node The node to check. - * @returns {boolean} True if the node is a JSX node, false if not. + * Checks whether or not a given node is a part of directive prologues. + * See also: http://www.ecma-international.org/ecma-262/6.0/#sec-directive-prologues-and-the-use-strict-directive + * @param {ASTNode} node - A node to check. + * @returns {boolean} Whether or not the node is a part of directive prologues. * @private */ - function isJSXElement(node) { - return node.type.indexOf("JSX") === 0; + function isPartOfDirectivePrologue(node) { + var block = node.parent.parent; + if (block.type !== "Program" && (block.type !== "BlockStatement" || !FUNCTION_TYPE.test(block.parent.type))) { + return false; + } + + // Check the node is at a prologue. + for (var i = 0; i < block.body.length; ++i) { + var statement = block.body[i]; + + if (statement === node.parent) { + return true; + } + if (!isDirective(statement)) { + break; + } + } + + return false; } + /** + * Checks whether or not a given node is allowed as non backtick. + * @param {ASTNode} node - A node to check. + * @returns {boolean} Whether or not the node is allowed as non backtick. + * @private + */ + function isAllowedAsNonBacktick(node) { + var parent = node.parent; + + switch (parent.type) { + // Directive Prologues. + case "ExpressionStatement": + return isPartOfDirectivePrologue(node); + + // LiteralPropertyName. + case "Property": + return parent.key === node && !parent.computed; + + // ModuleSpecifier. + case "ImportDeclaration": + case "ExportNamedDeclaration": + case "ExportAllDeclaration": + return parent.source === node; + + // Others don't allow. + default: + return false; + } + } + return { "Literal": function(node) { var val = node.value, rawVal = node.raw, quoteOption = context.options[0], - settings = QUOTE_SETTINGS[quoteOption], + settings = QUOTE_SETTINGS[quoteOption || "double"], avoidEscape = context.options[1] === AVOID_ESCAPE, isValid; if (settings && typeof val === "string") { - isValid = isJSXElement(node.parent) || isSurroundedBy(rawVal, settings.quote); + isValid = (quoteOption === "backtick" && isAllowedAsNonBacktick(node)) || isJSXElement(node.parent) || astUtils.isSurroundedBy(rawVal, settings.quote); if (!isValid && avoidEscape) { - isValid = isSurroundedBy(rawVal, settings.alternateQuote) && rawVal.indexOf(settings.quote) >= 0; + isValid = astUtils.isSurroundedBy(rawVal, settings.alternateQuote) && rawVal.indexOf(settings.quote) >= 0; } if (!isValid) { - context.report(node, "Strings must use " + settings.description + "."); + context.report({ + node: node, + message: "Strings must use " + settings.description + ".", + fix: function(fixer) { + return fixer.replaceText(node, settings.convert(node.raw)); + } + }); } } } }; }; -},{}],263:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["single", "double", "backtick"] + }, + { + "enum": ["avoid-escape"] + } +]; + +},{"../ast-utils":113}],286:[function(require,module,exports){ /** * @fileoverview Rule to flag use of parseInt without a radix argument * @author James Allardice */ @@ -26839,55 +39894,259 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var MODE_ALWAYS = "always", + MODE_AS_NEEDED = "as-needed"; + + var mode = context.options[0] || MODE_ALWAYS; + return { "CallExpression": function(node) { var radix; - if (node.callee.name === "parseInt") { + if (!(node.callee.name === "parseInt" || ( + node.callee.type === "MemberExpression" && + node.callee.object.name === "Number" && + node.callee.property.name === "parseInt" + ) + )) { + return; + } - if (node.arguments.length < 2) { - context.report(node, "Missing radix parameter."); - } else { + if (node.arguments.length === 0) { + context.report({ + node: node, + message: "Missing parameters." + }); + } else if (node.arguments.length < 2 && mode === MODE_ALWAYS) { + context.report({ + node: node, + message: "Missing radix parameter." + }); + } else if (node.arguments.length > 1 && mode === MODE_AS_NEEDED && + (node.arguments[1] && node.arguments[1].type === "Literal" && + node.arguments[1].value === 10) + ) { + context.report({ + node: node, + message: "Redundant radix parameter." + }); + } else { - radix = node.arguments[1]; + radix = node.arguments[1]; - // don't allow non-numeric literals or undefined - if ((radix.type === "Literal" && typeof radix.value !== "number") || - (radix.type === "Identifier" && radix.name === "undefined") - ) { - context.report(node, "Invalid radix parameter."); - } + // don't allow non-numeric literals or undefined + if (radix && + ((radix.type === "Literal" && typeof radix.value !== "number") || + (radix.type === "Identifier" && radix.name === "undefined")) + ) { + context.report({ + node: node, + message: "Invalid radix parameter." + }); } + } + } + }; + +}; + +module.exports.schema = [ + { + "enum": ["always", "as-needed"] + } +]; + + +},{}],287:[function(require,module,exports){ +/** + * @fileoverview Rule to check for jsdoc presence. + * @author Gyandeep Singh + * @copyright 2015 Gyandeep Singh. All rights reserved. + */ +"use strict"; + +var assign = require("object-assign"); + +module.exports = function(context) { + var source = context.getSourceCode(); + var DEFAULT_OPTIONS = { + "FunctionDeclaration": true, + "MethodDefinition": false, + "ClassDeclaration": false + }; + var options = assign(DEFAULT_OPTIONS, context.options[0] && context.options[0].require || {}); + + /** + * Report the error message + * @param {ASTNode} node node to report + * @returns {void} + */ + function report(node) { + context.report(node, "Missing JSDoc comment."); + } + + /** + * Check if the jsdoc comment is present for class methods + * @param {ASTNode} node node to examine + * @returns {void} + */ + function checkClassMethodJsDoc(node) { + if (node.parent.type === "MethodDefinition") { + var jsdocComment = source.getJSDocComment(node); + + if (!jsdocComment) { + report(node); } } + } + + /** + * Check if the jsdoc comment is present or not. + * @param {ASTNode} node node to examine + * @returns {void} + */ + function checkJsDoc(node) { + var jsdocComment = source.getJSDocComment(node); + + if (!jsdocComment) { + report(node); + } + } + + return { + "FunctionDeclaration": function(node) { + if (options.FunctionDeclaration) { + checkJsDoc(node); + } + }, + "FunctionExpression": function(node) { + if (options.MethodDefinition) { + checkClassMethodJsDoc(node); + } + }, + "ClassDeclaration": function(node) { + if (options.ClassDeclaration) { + checkJsDoc(node); + } + } }; +}; +module.exports.schema = [ + { + "type": "object", + "properties": { + "require": { + "type": "object", + "properties": { + "ClassDeclaration": { + "type": "boolean" + }, + "MethodDefinition": { + "type": "boolean" + }, + "FunctionDeclaration": { + "type": "boolean" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } +]; + +},{"object-assign":108}],288:[function(require,module,exports){ +/** + * @fileoverview Rule to flag the generator functions that does not have yield. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var stack = []; + + /** + * If the node is a generator function, start counting `yield` keywords. + * @param {Node} node - A function node to check. + * @returns {void} + */ + function beginChecking(node) { + if (node.generator) { + stack.push(0); + } + } + + /** + * If the node is a generator function, end counting `yield` keywords, then + * reports result. + * @param {Node} node - A function node to check. + * @returns {void} + */ + function endChecking(node) { + if (!node.generator) { + return; + } + + var countYield = stack.pop(); + if (countYield === 0 && node.body.body.length > 0) { + context.report( + node, + "This generator function does not have `yield`."); + } + } + + return { + "FunctionDeclaration": beginChecking, + "FunctionDeclaration:exit": endChecking, + "FunctionExpression": beginChecking, + "FunctionExpression:exit": endChecking, + + // Increases the count of `yield` keyword. + "YieldExpression": function() { + /* istanbul ignore else */ + if (stack.length > 0) { + stack[stack.length - 1] += 1; + } + } + }; }; -},{}],264:[function(require,module,exports){ +module.exports.schema = []; + +},{}],289:[function(require,module,exports){ /** * @fileoverview Validates spacing before and after semicolon * @author Mathias Schreck * @copyright 2015 Mathias Schreck */ "use strict"; +var astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = function (context) { +module.exports = function(context) { var config = context.options[0], requireSpaceBefore = false, - requireSpaceAfter = true; + requireSpaceAfter = true, + sourceCode = context.getSourceCode(); if (typeof config === "object") { if (config.hasOwnProperty("before")) { requireSpaceBefore = config.before; } @@ -26895,61 +40154,64 @@ requireSpaceAfter = config.after; } } /** - * Determines whether two adjacent tokens are have whitespace between them. - * @param {Object} left - The left token object. - * @param {Object} right - The right token object. - * @returns {boolean} Whether or not there is space between the tokens. - */ - function isSpaced(left, right) { - return left.range[1] < right.range[0]; - } - - /** - * Checks whether two tokens are on the same line. - * @param {Object} left The leftmost token. - * @param {Object} right The rightmost token. - * @returns {boolean} True if the tokens are on the same line, false if not. - * @private - */ - function isSameLine(left, right) { - return left.loc.end.line === right.loc.start.line; - } - - /** * Checks if a given token has leading whitespace. * @param {Object} token The token to check. * @returns {boolean} True if the given token has leading space, false if not. */ function hasLeadingSpace(token) { var tokenBefore = context.getTokenBefore(token); - return tokenBefore && isSameLine(tokenBefore, token) && isSpaced(tokenBefore, token); + return tokenBefore && astUtils.isTokenOnSameLine(tokenBefore, token) && sourceCode.isSpaceBetweenTokens(tokenBefore, token); } /** * Checks if a given token has trailing whitespace. * @param {Object} token The token to check. * @returns {boolean} True if the given token has trailing space, false if not. */ function hasTrailingSpace(token) { var tokenAfter = context.getTokenAfter(token); - return tokenAfter && isSameLine(token, tokenAfter) && isSpaced(token, tokenAfter); + return tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter) && sourceCode.isSpaceBetweenTokens(token, tokenAfter); } /** * Checks if the given token is the last token in its line. * @param {Token} token The token to check. * @returns {boolean} Whether or not the token is the last in its line. */ function isLastTokenInCurrentLine(token) { var tokenAfter = context.getTokenAfter(token); - return !(tokenAfter && isSameLine(token, tokenAfter)); + return !(tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter)); } /** + * Checks if the given token is the first token in its line + * @param {Token} token The token to check. + * @returns {boolean} Whether or not the token is the first in its line. + */ + function isFirstTokenInCurrentLine(token) { + var tokenBefore = context.getTokenBefore(token); + return !(tokenBefore && astUtils.isTokenOnSameLine(token, tokenBefore)); + } + + /** + * Checks if the next token of a given token is a closing parenthesis. + * @param {Token} token The token to check. + * @returns {boolean} Whether or not the next token of a given token is a closing parenthesis. + */ + function isBeforeClosingParen(token) { + var nextToken = context.getTokenAfter(token); + return ( + nextToken && + nextToken.type === "Punctuator" && + (nextToken.value === "}" || nextToken.value === ")") + ); + } + + /** * Checks if the given token is a semicolon. * @param {Token} token The token to check. * @returns {boolean} Whether or not the given token is a semicolon. */ function isSemicolon(token) { @@ -26976,11 +40238,11 @@ if (requireSpaceBefore) { context.report(node, location, "Missing whitespace before semicolon."); } } - if (!isLastTokenInCurrentLine(token)) { + if (!isFirstTokenInCurrentLine(token) && !isLastTokenInCurrentLine(token) && !isBeforeClosingParen(token)) { if (hasTrailingSpace(token)) { if (!requireSpaceAfter) { context.report(node, location, "Unexpected whitespace after semicolon."); } } else { @@ -27008,11 +40270,11 @@ "BreakStatement": checkNode, "ContinueStatement": checkNode, "DebuggerStatement": checkNode, "ReturnStatement": checkNode, "ThrowStatement": checkNode, - "ForStatement": function (node) { + "ForStatement": function(node) { if (node.init) { checkSemicolonSpacing(context.getTokenAfter(node.init), node); } if (node.test) { @@ -27020,78 +40282,145 @@ } } }; }; -},{}],265:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "before": { + "type": "boolean" + }, + "after": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{"../ast-utils":113}],290:[function(require,module,exports){ /** * @fileoverview Rule to flag missing semicolons. * @author Nicholas C. Zakas + * @copyright 2013 Nicholas C. Zakas. All rights reserved. + * See LICENSE file in root directory for full license. */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ + module.exports = function(context) { - var OPT_OUT_PATTERN = /[\[\(\/\+\-]/; + var OPT_OUT_PATTERN = /[\[\(\/\+\-]/; // One of [(/+- - var always = context.options[0] !== "never"; + var always = context.options[0] !== "never", + sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- /** + * Reports a semicolon error with appropriate location and message. + * @param {ASTNode} node The node with an extra or missing semicolon. + * @returns {void} + */ + function report(node) { + var message, + fix, + lastToken = sourceCode.getLastToken(node), + loc = lastToken.loc; + + if (always) { + message = "Missing semicolon."; + loc = loc.end; + fix = function(fixer) { + return fixer.insertTextAfter(lastToken, ";"); + }; + } else { + message = "Extra semicolon."; + loc = loc.start; + fix = function(fixer) { + return fixer.remove(lastToken); + }; + } + + context.report({ + node: node, + loc: loc, + message: message, + fix: fix + }); + + } + + /** + * Checks whether a token is a semicolon punctuator. + * @param {Token} token The token. + * @returns {boolean} True if token is a semicolon punctuator. + */ + function isSemicolon(token) { + return (token.type === "Punctuator" && token.value === ";"); + } + + /** * Check if a semicolon is unnecessary, only true if: * - next token is on a new line and is not one of the opt-out tokens * - next token is a valid statement divider * @param {Token} lastToken last token of current node. - * @param {Token} nextToken next token after current node. * @returns {boolean} whether the semicolon is unnecessary. */ - function isUnnecessarySemicolon(lastToken, nextToken) { + function isUnnecessarySemicolon(lastToken) { + var isDivider, isOptOutToken, lastTokenLine, nextToken, nextTokenLine; - var lastTokenLine = lastToken.loc.end.line, - nextTokenLine = nextToken && nextToken.loc.start.line, - isOptOutToken = nextToken && OPT_OUT_PATTERN.test(nextToken.value), - isDivider = nextToken && (nextToken.value === "}" || nextToken.value === ";"); + if (!isSemicolon(lastToken)) { + return false; + } + nextToken = context.getTokenAfter(lastToken); + + if (!nextToken) { + return true; + } + + lastTokenLine = lastToken.loc.end.line; + nextTokenLine = nextToken.loc.start.line; + isOptOutToken = OPT_OUT_PATTERN.test(nextToken.value); + isDivider = (nextToken.value === "}" || nextToken.value === ";"); + return (lastTokenLine !== nextTokenLine && !isOptOutToken) || isDivider; } /** * Checks a node to see if it's followed by a semicolon. * @param {ASTNode} node The node to check. * @returns {void} */ function checkForSemicolon(node) { - var lastToken = context.getLastToken(node), - nextToken = context.getTokenAfter(node); + var lastToken = context.getLastToken(node); if (always) { - if (lastToken.type !== "Punctuator" || lastToken.value !== ";") { - context.report(node, lastToken.loc.end, "Missing semicolon."); + if (!isSemicolon(lastToken)) { + report(node); } } else { - if (lastToken.type === "Punctuator" && - lastToken.value === ";" && - isUnnecessarySemicolon(lastToken, nextToken) - ) { - context.report(node, node.loc.end, "Extra semicolon."); + if (isUnnecessarySemicolon(lastToken)) { + report(node); } } } /** * Checks to see if there's a semicolon after a variable declaration. * @param {ASTNode} node The node to check. * @returns {void} */ function checkForSemicolonForVariableDeclaration(node) { - var ancestors = context.getAncestors(), parentIndex = ancestors.length - 1, parent = ancestors[parentIndex]; if ((parent.type !== "ForStatement" || parent.init !== node) && @@ -27109,32 +40438,37 @@ "VariableDeclaration": checkForSemicolonForVariableDeclaration, "ExpressionStatement": checkForSemicolon, "ReturnStatement": checkForSemicolon, "ThrowStatement": checkForSemicolon, + "DoWhileStatement": checkForSemicolon, "DebuggerStatement": checkForSemicolon, "BreakStatement": checkForSemicolon, "ContinueStatement": checkForSemicolon, - "EmptyStatement": function (node) { - var lastToken, nextToken; - - if (!always) { - lastToken = context.getLastToken(node); - nextToken = context.getTokenAfter(node) || context.getLastToken(node); - - if (isUnnecessarySemicolon(lastToken, nextToken)) { - context.report(node, "Extra semicolon."); - } + "ImportDeclaration": checkForSemicolon, + "ExportAllDeclaration": checkForSemicolon, + "ExportNamedDeclaration": function(node) { + if (!node.declaration) { + checkForSemicolon(node); } - - + }, + "ExportDefaultDeclaration": function(node) { + if (!/(?:Class|Function)Declaration/.test(node.declaration.type)) { + checkForSemicolon(node); + } } }; }; -},{}],266:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["always", "never"] + } +]; + +},{}],291:[function(require,module,exports){ /** * @fileoverview Rule to require sorting of variables within a single Variable Declaration block * @author Ilya Volodin */ @@ -27150,10 +40484,14 @@ ignoreCase = configuration.ignoreCase || false; return { "VariableDeclaration": function(node) { node.declarations.reduce(function(memo, decl) { + if (decl.id.type === "ObjectPattern" || decl.id.type === "ArrayPattern") { + return memo; + } + var lastVariableName = memo.id.name, currenVariableName = decl.id.name; if (ignoreCase) { lastVariableName = lastVariableName.toLowerCase(); @@ -27169,56 +40507,23 @@ }, node.declarations[0]); } }; }; -},{}],267:[function(require,module,exports){ -/** - * @fileoverview Rule to enforce consistent spacing after function names - * @author Roberto Vidal - * @copyright 2014 Roberto Vidal. All rights reserved. - */ -"use strict"; - -//------------------------------------------------------------------------------ -// Rule Definition -//------------------------------------------------------------------------------ - -module.exports = function(context) { - - var requiresSpace = context.options[0] === "always"; - - /** - * Reports if the give named function node has the correct spacing after its name - * - * @param {ASTNode} node The node to which the potential problem belongs. - * @returns {void} - */ - function check(node) { - var tokens = context.getFirstTokens(node, 3), - hasSpace = tokens[1].range[1] < tokens[2].range[0]; - - if (hasSpace !== requiresSpace) { - context.report(node, "Function name \"{{name}}\" must {{not}}be followed by whitespace.", { - name: node.id.name, - not: requiresSpace ? "" : "not " - }); - } +module.exports.schema = [ + { + "type": "object", + "properties": { + "ignoreCase": { + "type": "boolean" + } + }, + "additionalProperties": false } +]; - return { - "FunctionDeclaration": check, - "FunctionExpression": function (node) { - if (node.id) { - check(node); - } - } - }; - -}; - -},{}],268:[function(require,module,exports){ +},{}],292:[function(require,module,exports){ /** * @fileoverview Rule to enforce the number of spaces after certain keywords * @author Nick Fisher * @copyright 2014 Nick Fisher. All rights reserved. */ @@ -27240,18 +40545,50 @@ * @param {Token} left The first token. * @param {Token} right The second token * @returns {void} */ function checkTokens(node, left, right) { + if (right.type !== "Punctuator") { + return; + } + var hasSpace = left.range[1] < right.range[0], value = left.value; if (hasSpace !== requiresSpace) { - context.report(node, "Keyword \"{{value}}\" must {{not}}be followed by whitespace.", { - value: value, - not: requiresSpace ? "" : "not " + context.report({ + node: node, + loc: left.loc.end, + message: "Keyword \"{{value}}\" must {{not}}be followed by whitespace.", + data: { + value: value, + not: requiresSpace ? "" : "not " + }, + fix: function(fixer) { + if (requiresSpace) { + return fixer.insertTextAfter(left, " "); + } else { + return fixer.removeRange([left.range[1], right.range[0]]); + } + } }); + } else if (left.loc.end.line !== right.loc.start.line) { + context.report({ + node: node, + loc: left.loc.end, + message: "Keyword \"{{value}}\" must not be followed by a newline.", + data: { + value: value + }, + fix: function(fixer) { + var text = ""; + if (requiresSpace) { + text = " "; + } + return fixer.replaceTextRange([left.range[1], right.range[0]], text); + } + }); } } /** * Check if the given node (`if`, `for`, `while`, etc), has the correct spacing after it. @@ -27262,95 +40599,124 @@ var tokens = context.getFirstTokens(node, 2); checkTokens(node, tokens[0], tokens[1]); } return { - "IfStatement": function (node) { + "IfStatement": function(node) { check(node); // check the `else` if (node.alternate && node.alternate.type !== "IfStatement") { checkTokens(node.alternate, context.getTokenBefore(node.alternate), context.getFirstToken(node.alternate)); } }, "ForStatement": check, "ForOfStatement": check, "ForInStatement": check, "WhileStatement": check, - "DoWhileStatement": function (node) { + "DoWhileStatement": function(node) { check(node); // check the `while` - var whileTokens = context.getTokensBefore(node.test, 2); + var whileTokens = context.getTokensAfter(node.body, 2); checkTokens(node, whileTokens[0], whileTokens[1]); }, "SwitchStatement": check, - "TryStatement": function (node) { + "TryStatement": function(node) { check(node); // check the `finally` if (node.finalizer) { checkTokens(node.finalizer, context.getTokenBefore(node.finalizer), context.getFirstToken(node.finalizer)); } }, - "CatchStatement": check, + "CatchClause": check, "WithStatement": check }; }; -},{}],269:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["always", "never"] + } +]; + +},{}],293:[function(require,module,exports){ /** * @fileoverview A rule to ensure whitespace before blocks. * @author Mathias Schreck <https://github.com/lo1tuma> * @copyright 2014 Mathias Schreck. All rights reserved. */ "use strict"; +var astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = function (context) { - var requireSpace = context.options[0] !== "never"; +module.exports = function(context) { + var config = context.options[0], + sourceCode = context.getSourceCode(), + checkFunctions = true, + checkKeywords = true; - /** - * Determines whether two adjacent tokens are have whitespace between them. - * @param {Object} left - The left token object. - * @param {Object} right - The right token object. - * @returns {boolean} Whether or not there is space between the tokens. - */ - function isSpaced(left, right) { - return left.range[1] < right.range[0]; + if (typeof config === "object") { + checkFunctions = config.functions !== "never"; + checkKeywords = config.keywords !== "never"; + } else if (config === "never") { + checkFunctions = false; + checkKeywords = false; } /** - * Determines whether two adjacent tokens are on the same line. - * @param {Object} left - The left token object. - * @param {Object} right - The right token object. - * @returns {boolean} Whether or not the tokens are on the same line. + * Checks whether or not a given token is an arrow operator (=>). + * + * @param {Token} token - A token to check. + * @returns {boolean} `true` if the token is an arrow operator. */ - function isSameLine(left, right) { - return left.loc.start.line === right.loc.start.line; + function isArrow(token) { + return token.type === "Punctuator" && token.value === "=>"; } /** * Checks the given BlockStatement node has a preceding space if it doesn’t start on a new line. * @param {ASTNode|Token} node The AST node of a BlockStatement. * @returns {void} undefined. */ function checkPrecedingSpace(node) { var precedingToken = context.getTokenBefore(node), - hasSpace; + hasSpace, + parent, + requireSpace; - if (precedingToken && isSameLine(precedingToken, node)) { - hasSpace = isSpaced(precedingToken, node); + if (precedingToken && !isArrow(precedingToken) && astUtils.isTokenOnSameLine(precedingToken, node)) { + hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node); + parent = context.getAncestors().pop(); + if (parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") { + requireSpace = checkFunctions; + } else { + requireSpace = checkKeywords; + } if (requireSpace) { if (!hasSpace) { - context.report(node, "Missing space before opening brace."); + context.report({ + node: node, + message: "Missing space before opening brace.", + fix: function(fixer) { + return fixer.insertTextBefore(node, " "); + } + }); } } else { if (hasSpace) { - context.report(node, "Unexpected space before opening brace."); + context.report({ + node: node, + message: "Unexpected space before opening brace.", + fix: function(fixer) { + return fixer.removeRange([precedingToken.range[1], node.range[0]]); + } + }); } } } } @@ -27374,30 +40740,55 @@ checkPrecedingSpace(openingBrace); } return { "BlockStatement": checkPrecedingSpace, + "ClassBody": checkPrecedingSpace, "SwitchStatement": checkSpaceBeforeCaseBlock }; }; -},{}],270:[function(require,module,exports){ +module.exports.schema = [ + { + "oneOf": [ + { + "enum": ["always", "never"] + }, + { + "type": "object", + "properties": { + "keywords": { + "enum": ["always", "never"] + }, + "functions": { + "enum": ["always", "never"] + } + }, + "additionalProperties": false + } + ] + } +]; + +},{"../ast-utils":113}],294:[function(require,module,exports){ /** - * @fileoverview Rule to validate spacing before function parentheses. + * @fileoverview Rule to validate spacing before function paren. * @author Mathias Schreck <https://github.com/lo1tuma> * @copyright 2015 Mathias Schreck + * See LICENSE in root directory for full license. */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { var configuration = context.options[0], + sourceCode = context.getSourceCode(), requireAnonymousFunctionSpacing = true, requireNamedFunctionSpacing = true; if (typeof configuration === "object") { requireAnonymousFunctionSpacing = configuration.anonymous !== "never"; @@ -27406,20 +40797,10 @@ requireAnonymousFunctionSpacing = false; requireNamedFunctionSpacing = false; } /** - * Determines whether two adjacent tokens are have whitespace between them. - * @param {Object} left - The left token object. - * @param {Object} right - The right token object. - * @returns {boolean} Whether or not there is space between the tokens. - */ - function isSpaced(left, right) { - return left.range[1] < right.range[0]; - } - - /** * Determines whether a function has a name. * @param {ASTNode} node The function node. * @returns {boolean} Whether the function has a name. */ function isNamedFunction(node) { @@ -27427,568 +40808,554 @@ if (node.id) { return true; } - parent = context.getAncestors().pop(); - return parent.type === "Property" && ( - parent.kind === "get" || - parent.kind === "set" || - parent.method - ); + parent = node.parent; + return parent.type === "MethodDefinition" || + (parent.type === "Property" && + ( + parent.kind === "get" || + parent.kind === "set" || + parent.method + ) + ); } /** * Validates the spacing before function parentheses. * @param {ASTNode} node The node to be validated. * @returns {void} */ function validateSpacingBeforeParentheses(node) { var isNamed = isNamedFunction(node), - tokens, leftToken, rightToken, location; if (node.generator && !isNamed) { return; } - tokens = context.getTokens(node); - - if (node.generator) { - leftToken = tokens[2]; - rightToken = tokens[3]; - } else if (isNamed) { - if (node.id) { - leftToken = tokens[1]; - rightToken = tokens[2]; - } else { - // Object methods are named but don't have an id - leftToken = context.getTokenBefore(node); - rightToken = tokens[0]; - } - } else { - leftToken = tokens[0]; - rightToken = tokens[1]; + rightToken = sourceCode.getFirstToken(node); + while (rightToken.value !== "(") { + rightToken = sourceCode.getTokenAfter(rightToken); } - + leftToken = context.getTokenBefore(rightToken); location = leftToken.loc.end; - if (isSpaced(leftToken, rightToken)) { + if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken)) { if ((isNamed && !requireNamedFunctionSpacing) || (!isNamed && !requireAnonymousFunctionSpacing)) { - context.report(node, location, "Unexpected space before function parentheses."); + context.report({ + node: node, + loc: location, + message: "Unexpected space before function parentheses.", + fix: function(fixer) { + return fixer.removeRange([leftToken.range[1], rightToken.range[0]]); + } + }); } } else { if ((isNamed && requireNamedFunctionSpacing) || (!isNamed && requireAnonymousFunctionSpacing)) { - context.report(node, location, "Missing space before function parentheses."); + context.report({ + node: node, + loc: location, + message: "Missing space before function parentheses.", + fix: function(fixer) { + return fixer.insertTextAfter(leftToken, " "); + } + }); } } } return { "FunctionDeclaration": validateSpacingBeforeParentheses, "FunctionExpression": validateSpacingBeforeParentheses }; }; -},{}],271:[function(require,module,exports){ +module.exports.schema = [ + { + "oneOf": [ + { + "enum": ["always", "never"] + }, + { + "type": "object", + "properties": { + "anonymous": { + "enum": ["always", "never"] + }, + "named": { + "enum": ["always", "never"] + } + }, + "additionalProperties": false + } + ] + } +]; + +},{}],295:[function(require,module,exports){ /** - * @fileoverview Disallows or enforces spaces inside of brackets. - * @author Ian Christian Myers - * @copyright 2014 Brandyn Bennett. All rights reserved. - * @copyright 2014 Michael Ficarra. No rights reserved. - * @copyright 2014 Vignesh Anand. All rights reserved. + * @fileoverview Require or disallow spaces before keywords + * @author Marko Raatikka + * @copyright 2015 Marko Raatikka. All rights reserved. + * See LICENSE file in root directory for full license. */ "use strict"; +var astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ +var ERROR_MSG_SPACE_EXPECTED = "Missing space before keyword \"{{keyword}}\"."; +var ERROR_MSG_NO_SPACE_EXPECTED = "Unexpected space before keyword \"{{keyword}}\"."; + module.exports = function(context) { - var spaced = context.options[0] === "always"; - /** - * Determines whether an option is set, relative to the spacing option. - * If spaced is "always", then check whether option is set to false. - * If spaced is "never", then check whether option is set to true. - * @param {Object} option - The option to exclude. - * @returns {boolean} Whether or not the property is excluded. - */ - function isOptionSet(option) { - return context.options[1] != null ? context.options[1][option] === !spaced : false; - } + var sourceCode = context.getSourceCode(); - var options = { - spaced: spaced, - singleElementException: isOptionSet("singleValue"), - objectsInArraysException: isOptionSet("objectsInArrays"), - arraysInArraysException: isOptionSet("arraysInArrays"), - arraysInObjectsException: isOptionSet("arraysInObjects"), - objectsInObjectsException: isOptionSet("objectsInObjects"), - propertyNameException: isOptionSet("propertyName") - }; + var SPACE_REQUIRED = context.options[0] !== "never"; //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- /** - * Determines whether two adjacent tokens are have whitespace between them. - * @param {Object} left - The left token object. - * @param {Object} right - The right token object. - * @returns {boolean} Whether or not there is space between the tokens. + * Report the error message + * @param {ASTNode} node node to report + * @param {string} message Error message to be displayed + * @param {object} data Data object for the rule message + * @returns {void} */ - function isSpaced(left, right) { - return left.range[1] < right.range[0]; + function report(node, message, data) { + context.report({ + node: node, + message: message, + data: data, + fix: function(fixer) { + if (SPACE_REQUIRED) { + return fixer.insertTextBefore(node, " "); + } else { + var tokenBefore = context.getTokenBefore(node); + return fixer.removeRange([tokenBefore.range[1], node.range[0]]); + } + } + }); } /** - * Determines whether two adjacent tokens are on the same line. - * @param {Object} left - The left token object. - * @param {Object} right - The right token object. - * @returns {boolean} Whether or not the tokens are on the same line. + * Check if a token meets the criteria + * + * @param {ASTNode} node The node to check + * @param {Object} left The left-hand side token of the node + * @param {Object} right The right-hand side token of the node + * @param {Object} options See check() + * @returns {void} */ - function isSameLine(left, right) { - return left.loc.start.line === right.loc.start.line; - } + function checkTokens(node, left, right, options) { - /** - * Reports that there shouldn't be a space after the first token - * @param {ASTNode} node - The node to report in the event of an error. - * @param {Token} token - The token to use for the report. - * @returns {void} - */ - function reportNoBeginningSpace(node, token) { - context.report(node, token.loc.start, - "There should be no space after '" + token.value + "'"); - } + if (!left) { + return; + } - /** - * Reports that there shouldn't be a space before the last token - * @param {ASTNode} node - The node to report in the event of an error. - * @param {Token} token - The token to use for the report. - * @returns {void} - */ - function reportNoEndingSpace(node, token) { - context.report(node, token.loc.start, - "There should be no space before '" + token.value + "'"); - } + if (left.type === "Keyword") { + return; + } - /** - * Reports that there should be a space after the first token - * @param {ASTNode} node - The node to report in the event of an error. - * @param {Token} token - The token to use for the report. - * @returns {void} - */ - function reportRequiredBeginningSpace(node, token) { - context.report(node, token.loc.start, - "A space is required after '" + token.value + "'"); - } + if (!SPACE_REQUIRED && typeof options.requireSpace === "undefined") { + return; + } - /** - * Reports that there should be a space before the last token - * @param {ASTNode} node - The node to report in the event of an error. - * @param {Token} token - The token to use for the report. - * @returns {void} - */ - function reportRequiredEndingSpace(node, token) { - context.report(node, token.loc.start, - "A space is required before '" + token.value + "'"); - } + options = options || {}; + options.allowedPrecedingChars = options.allowedPrecedingChars || [ "{" ]; + options.requireSpace = typeof options.requireSpace === "undefined" ? SPACE_REQUIRED : options.requireSpace; + var hasSpace = sourceCode.isSpaceBetweenTokens(left, right); + var spaceOk = hasSpace === options.requireSpace; - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + if (spaceOk) { + return; + } - return { - - MemberExpression: function(node) { - if (!node.computed) { - return; + if (!astUtils.isTokenOnSameLine(left, right)) { + if (!options.requireSpace) { + report(node, ERROR_MSG_NO_SPACE_EXPECTED, { keyword: right.value }); } + return; + } - var property = node.property, - before = context.getTokenBefore(property), - first = context.getFirstToken(property), - last = context.getLastToken(property), - after = context.getTokenAfter(property); + if (!options.requireSpace) { + report(node, ERROR_MSG_NO_SPACE_EXPECTED, { keyword: right.value }); + return; + } - var propertyNameMustBeSpaced = options.propertyNameException ? - !options.spaced : options.spaced; + if (options.allowedPrecedingChars.indexOf(left.value) !== -1) { + return; + } - if (isSameLine(before, first)) { - if (propertyNameMustBeSpaced) { - if (!isSpaced(before, first) && isSameLine(before, first)) { - reportRequiredBeginningSpace(node, before); - } - } else { - if (isSpaced(before, first)) { - reportNoBeginningSpace(node, before); - } - } - } + report(node, ERROR_MSG_SPACE_EXPECTED, { keyword: right.value }); - if (isSameLine(last, after)) { - if (propertyNameMustBeSpaced) { - if (!isSpaced(last, after) && isSameLine(last, after)) { - reportRequiredEndingSpace(node, after); - } - } else { - if (isSpaced(last, after)) { - reportNoEndingSpace(node, after); - } - } - } - }, + } - ArrayExpression: function(node) { - if (node.elements.length === 0) { - return; - } + /** + * Get right and left tokens of a node and check to see if they meet the given criteria + * + * @param {ASTNode} node The node to check + * @param {Object} options Options to validate the node against + * @param {Array} options.allowedPrecedingChars Characters that can precede the right token + * @param {Boolean} options.requireSpace Whether or not the right token needs to be + * preceded by a space + * @returns {void} + */ + function check(node, options) { - var first = context.getFirstToken(node), - second = context.getFirstToken(node, 1), - penultimate = context.getLastToken(node, 1), - last = context.getLastToken(node); + options = options || {}; - var openingBracketMustBeSpaced = - options.objectsInArraysException && second.value === "{" || - options.arraysInArraysException && second.value === "[" || - options.singleElementException && node.elements.length === 1 - ? !options.spaced : options.spaced; + var left = context.getTokenBefore(node); + var right = context.getFirstToken(node); - var closingBracketMustBeSpaced = - options.objectsInArraysException && penultimate.value === "}" || - options.arraysInArraysException && penultimate.value === "]" || - options.singleElementException && node.elements.length === 1 - ? !options.spaced : options.spaced; + checkTokens(node, left, right, options); - if (isSameLine(first, second)) { - if (openingBracketMustBeSpaced && !isSpaced(first, second)) { - reportRequiredBeginningSpace(node, first); - } - if (!openingBracketMustBeSpaced && isSpaced(first, second)) { - reportNoBeginningSpace(node, first); - } - } + } - if (isSameLine(penultimate, last)) { - if (closingBracketMustBeSpaced && !isSpaced(penultimate, last)) { - reportRequiredEndingSpace(node, last); + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + return { + + "IfStatement": function(node) { + // if + check(node); + // else + if (node.alternate) { + var tokens = context.getTokensBefore(node.alternate, 2); + if (tokens[0].value === "}") { + check(tokens[1], { requireSpace: SPACE_REQUIRED }); } - if (!closingBracketMustBeSpaced && isSpaced(penultimate, last)) { - reportNoEndingSpace(node, last); - } } }, + "ForStatement": check, + "ForInStatement": check, + "WhileStatement": check, + "DoWhileStatement": function(node) { + var whileNode = context.getTokenAfter(node.body); + // do + check(node); + // while + check(whileNode, { requireSpace: SPACE_REQUIRED }); + }, + "SwitchStatement": function(node) { + // switch + check(node); + // case/default + node.cases.forEach(function(caseNode) { + check(caseNode); + }); + }, + "ThrowStatement": check, + "TryStatement": function(node) { + // try + check(node); + // finally + if (node.finalizer) { + check(context.getTokenBefore(node.finalizer), { requireSpace: SPACE_REQUIRED }); + } + }, + "CatchClause": function(node) { + check(node, { requireSpace: SPACE_REQUIRED }); + }, + "WithStatement": check, + "VariableDeclaration": function(node) { + check(node, { allowedPrecedingChars: [ "(", "{" ] }); + }, + "ReturnStatement": check, + "BreakStatement": check, + "LabeledStatement": check, + "ContinueStatement": check, + "FunctionDeclaration": check, + "FunctionExpression": function(node) { + var left = context.getTokenBefore(node); + var right = context.getFirstToken(node); - ObjectExpression: function(node) { - if (node.properties.length === 0) { + // If it's a method, a getter, or a setter, the first token is not the `function` keyword. + if (right.type !== "Keyword") { return; } - var first = context.getFirstToken(node), - second = context.getFirstToken(node, 1), - penultimate = context.getLastToken(node, 1), - last = context.getLastToken(node); + checkTokens(node, left, right, { allowedPrecedingChars: [ "(", "{" ] }); + }, + "YieldExpression": function(node) { + check(node, { allowedPrecedingChars: [ "(", "{" ] }); + }, + "ForOfStatement": check, + "ClassBody": function(node) { - var closingCurlyBraceMustBeSpaced = - options.arraysInObjectsException && penultimate.value === "]" || - options.objectsInObjectsException && penultimate.value === "}" - ? !options.spaced : options.spaced; - - if (isSameLine(first, second)) { - if (options.spaced && !isSpaced(first, second)) { - reportRequiredBeginningSpace(node, first); - } - if (!options.spaced && isSpaced(first, second)) { - reportNoBeginningSpace(node, first); - } + // Find the 'class' token + while (node.value !== "class") { + node = context.getTokenBefore(node); } - if (isSameLine(penultimate, last)) { - if (closingCurlyBraceMustBeSpaced && !isSpaced(penultimate, last)) { - reportRequiredEndingSpace(node, last); - } - if (!closingCurlyBraceMustBeSpaced && isSpaced(penultimate, last)) { - reportNoEndingSpace(node, last); - } - } + check(node); } - }; }; -},{}],272:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["always", "never"] + } +]; + +},{"../ast-utils":113}],296:[function(require,module,exports){ /** * @fileoverview Disallows or enforces spaces inside of parentheses. * @author Jonathan Rajavuori * @copyright 2014 David Clark. All rights reserved. * @copyright 2014 Jonathan Rajavuori. All rights reserved. */ "use strict"; +var astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { var MISSING_SPACE_MESSAGE = "There must be a space inside this paren.", REJECTED_SPACE_MESSAGE = "There should be no spaces inside this paren.", - exceptionsArray = (context.options.length === 2) ? context.options[1].exceptions : [], + ALWAYS = context.options[0] === "always", + + exceptionsArrayOptions = (context.options.length === 2) ? context.options[1].exceptions : [], options = {}, - rejectedSpaceRegExp, - missingSpaceRegExp, - spaceChecks; + exceptions; - if (exceptionsArray && exceptionsArray.length) { - options.braceException = exceptionsArray.indexOf("{}") !== -1 || false; - options.bracketException = exceptionsArray.indexOf("[]") !== -1 || false; - options.parenException = exceptionsArray.indexOf("()") !== -1 || false; - options.empty = exceptionsArray.indexOf("empty") !== -1 || false; + if (exceptionsArrayOptions.length) { + options.braceException = exceptionsArrayOptions.indexOf("{}") !== -1; + options.bracketException = exceptionsArrayOptions.indexOf("[]") !== -1; + options.parenException = exceptionsArrayOptions.indexOf("()") !== -1; + options.empty = exceptionsArrayOptions.indexOf("empty") !== -1; } /** - * Used with the `never` option to produce, given the exception options, - * two regular expressions to check for missing and rejected spaces. + * Produces an object with the opener and closer exception values * @param {Object} opts The exception options - * @returns {Object} `missingSpace` and `rejectedSpace` regular expressions + * @returns {Object} `openers` and `closers` exception values * @private */ - function getNeverChecks(opts) { - var missingSpaceOpeners = [], - missingSpaceClosers = [], - rejectedSpaceOpeners = [" ", "\\n", "\\r"], - rejectedSpaceClosers = [" ", "\\n", "\\r"], - missingSpaceCheck, - rejectedSpaceCheck; - - // Populate openers and closers - if (opts.braceException) { - missingSpaceOpeners.push("\\{"); - missingSpaceClosers.push("\\}"); - rejectedSpaceOpeners.push("\\{"); - rejectedSpaceClosers.push("\\}"); + function getExceptions() { + var openers = [], + closers = []; + if (options.braceException) { + openers.push("{"); + closers.push("}"); } - if (opts.bracketException) { - missingSpaceOpeners.push("\\["); - missingSpaceClosers.push("\\]"); - rejectedSpaceOpeners.push("\\["); - rejectedSpaceClosers.push("\\]"); - } - if (opts.parenException) { - missingSpaceOpeners.push("\\("); - missingSpaceClosers.push("\\)"); - rejectedSpaceOpeners.push("\\("); - rejectedSpaceClosers.push("\\)"); - } - if (opts.empty) { - missingSpaceOpeners.push("\\)"); - missingSpaceClosers.push("\\("); - rejectedSpaceOpeners.push("\\)"); - rejectedSpaceClosers.push("\\("); - } - if (missingSpaceOpeners.length) { - missingSpaceCheck = "\\((" + missingSpaceOpeners.join("|") + ")"; - if (missingSpaceClosers.length) { - missingSpaceCheck += "|"; - } + if (options.bracketException) { + openers.push("["); + closers.push("]"); } - if (missingSpaceClosers.length) { - missingSpaceCheck += "(" + missingSpaceClosers.join("|") + ")\\)"; - } - // compose the rejected regexp - rejectedSpaceCheck = "\\( +[^" + rejectedSpaceOpeners.join("") + "]"; - rejectedSpaceCheck += "|[^" + rejectedSpaceClosers.join("") + "] +\\)"; - - return { - // e.g. \((\{)|(\})\) --- where {} is an exception - missingSpace: missingSpaceCheck || ".^", - // e.g. \( +[^ \n\r\{]|[^ \n\r\}] +\) --- where {} is an exception - rejectedSpace: rejectedSpaceCheck - }; - } - - /** - * Used with the `always` option to produce, given the exception options, - * two regular expressions to check for missing and rejected spaces. - * @param {Object} opts The exception options - * @returns {Object} `missingSpace` and `rejectedSpace` regular expressions - * @private - */ - function getAlwaysChecks(opts) { - var missingSpaceOpeners = [" ", "\\)", "\\r", "\\n"], - missingSpaceClosers = [" ", "\\(", "\\r", "\\n"], - rejectedSpaceOpeners = [], - rejectedSpaceClosers = [], - missingSpaceCheck, - rejectedSpaceCheck; - - // Populate openers and closers - if (opts.braceException) { - missingSpaceOpeners.push("\\{"); - missingSpaceClosers.push("\\}"); - rejectedSpaceOpeners.push(" \\{"); - rejectedSpaceClosers.push("\\} "); + if (options.parenException) { + openers.push("("); + closers.push(")"); } - if (opts.bracketException) { - missingSpaceOpeners.push("\\["); - missingSpaceClosers.push("\\]"); - rejectedSpaceOpeners.push(" \\["); - rejectedSpaceClosers.push("\\] "); - } - if (opts.parenException) { - missingSpaceOpeners.push("\\("); - missingSpaceClosers.push("\\)"); - rejectedSpaceOpeners.push(" \\("); - rejectedSpaceClosers.push("\\) "); - } - if (opts.empty) { - rejectedSpaceOpeners.push(" \\)"); - rejectedSpaceClosers.push("\\( "); - } - // compose the allowed regexp - missingSpaceCheck = "\\([^" + missingSpaceOpeners.join("") + "]"; - missingSpaceCheck += "|[^" + missingSpaceClosers.join("") + "]\\)"; - - // compose the rejected regexp - if (rejectedSpaceOpeners.length) { - rejectedSpaceCheck = "\\((" + rejectedSpaceOpeners.join("|") + ")"; - if (rejectedSpaceClosers.length) { - rejectedSpaceCheck += "|"; - } + if (options.empty) { + openers.push(")"); + closers.push("("); } - if (rejectedSpaceClosers.length) { - rejectedSpaceCheck += "(" + rejectedSpaceClosers.join("|") + ")\\)"; - } return { - // e.g. \([^ \)\r\n\{]|[^ \(\r\n\}]\) --- where {} is an exception - missingSpace: missingSpaceCheck, - // e.g. \(( \{})|(\} )\) --- where {} is an excpetion - rejectedSpace: rejectedSpaceCheck || ".^" + openers: openers, + closers: closers }; } - spaceChecks = (context.options[0] === "always") ? getAlwaysChecks(options) : getNeverChecks(options); - missingSpaceRegExp = new RegExp(spaceChecks.missingSpace, "mg"); - rejectedSpaceRegExp = new RegExp(spaceChecks.rejectedSpace, "mg"); - - //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- + var sourceCode = context.getSourceCode(); - var skipRanges = []; - /** - * Adds the range of a node to the set to be skipped when checking parens - * @param {ASTNode} node The node to skip - * @returns {void} - * @private + * Determines if a token is one of the exceptions for the opener paren + * @param {Object} token The token to check + * @returns {boolean} True if the token is one of the exceptions for the opener paren */ - function addSkipRange(node) { - skipRanges.push(node.range); + function isOpenerException(token) { + return token.type === "Punctuator" && exceptions.openers.indexOf(token.value) >= 0; } /** - * Sorts the skipRanges array. Must be called before shouldSkip - * @returns {void} - * @private + * Determines if a token is one of the exceptions for the closer paren + * @param {Object} token The token to check + * @returns {boolean} True if the token is one of the exceptions for the closer paren */ - function sortSkipRanges() { - skipRanges.sort(function (a, b) { - return a[0] - b[0]; - }); + function isCloserException(token) { + return token.type === "Punctuator" && exceptions.closers.indexOf(token.value) >= 0; } /** - * Checks if a certain position in the source should be skipped - * @param {Number} pos The 0-based index in the source - * @returns {boolean} whether the position should be skipped - * @private + * Determines if an opener paren should have a missing space after it + * @param {Object} left The paren token + * @param {Object} right The token after it + * @returns {boolean} True if the paren should have a space */ - function shouldSkip(pos) { - var i, len, range; - for (i = 0, len = skipRanges.length; i < len; i += 1) { - range = skipRanges[i]; - if (pos < range[0]) { - break; - } else if (pos < range[1]) { - return true; + function shouldOpenerHaveSpace(left, right) { + if (sourceCode.isSpaceBetweenTokens(left, right)) { + return false; + } + + if (ALWAYS) { + if (right.type === "Punctuator" && right.value === ")") { + return false; } + return !isOpenerException(right); + } else { + return isOpenerException(right); } - return false; } + /** + * Determines if an closer paren should have a missing space after it + * @param {Object} left The token before the paren + * @param {Object} right The paren token + * @returns {boolean} True if the paren should have a space + */ + function shouldCloserHaveSpace(left, right) { + if (left.type === "Punctuator" && left.value === "(") { + return false; + } - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- + if (sourceCode.isSpaceBetweenTokens(left, right)) { + return false; + } - return { + if (ALWAYS) { + return !isCloserException(left); + } else { + return isCloserException(left); + } + } - "Program:exit": function checkParenSpaces(node) { + /** + * Determines if an opener paren should not have an existing space after it + * @param {Object} left The paren token + * @param {Object} right The token after it + * @returns {boolean} True if the paren should reject the space + */ + function shouldOpenerRejectSpace(left, right) { + if (right.type === "Line") { + return false; + } - var nextMatch, - nextLine, - column, - line = 1, - source = context.getSource(), - pos = 0; + if (!astUtils.isTokenOnSameLine(left, right)) { + return false; + } - function checkMatch(match, message) { - if (source.charAt(match.index) !== "(") { - // Matched a closing paren pattern - match.index += 1; - } + if (!sourceCode.isSpaceBetweenTokens(left, right)) { + return false; + } - if (!shouldSkip(match.index)) { - while ((nextLine = source.indexOf("\n", pos)) !== -1 && nextLine < match.index) { - pos = nextLine + 1; - line += 1; - } - column = match.index - pos; + if (ALWAYS) { + return isOpenerException(right); + } else { + return !isOpenerException(right); + } + } - context.report(node, { line: line, column: column }, message); - } - } + /** + * Determines if an closer paren should not have an existing space after it + * @param {Object} left The token before the paren + * @param {Object} right The paren token + * @returns {boolean} True if the paren should reject the space + */ + function shouldCloserRejectSpace(left, right) { + if (left.type === "Punctuator" && left.value === "(") { + return false; + } - sortSkipRanges(); + if (!astUtils.isTokenOnSameLine(left, right)) { + return false; + } - while ((nextMatch = rejectedSpaceRegExp.exec(source)) !== null) { - checkMatch(nextMatch, REJECTED_SPACE_MESSAGE); - } + if (!sourceCode.isSpaceBetweenTokens(left, right)) { + return false; + } - while ((nextMatch = missingSpaceRegExp.exec(source)) !== null) { - checkMatch(nextMatch, MISSING_SPACE_MESSAGE); - } + if (ALWAYS) { + return isCloserException(left); + } else { + return !isCloserException(left); + } + } - }, + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + return { + "Program": function checkParenSpaces(node) { + var tokens, prevToken, nextToken; + exceptions = getExceptions(); + tokens = sourceCode.tokensAndComments; - // These nodes can contain parentheses that this rule doesn't care about + tokens.forEach(function(token, i) { + prevToken = tokens[i - 1]; + nextToken = tokens[i + 1]; - LineComment: addSkipRange, + if (token.type !== "Punctuator") { + return; + } - BlockComment: addSkipRange, + if (token.value !== "(" && token.value !== ")") { + return; + } - Literal: addSkipRange - + if (token.value === "(" && shouldOpenerHaveSpace(token, nextToken)) { + context.report(node, token.loc.end, MISSING_SPACE_MESSAGE); + } else if (token.value === "(" && shouldOpenerRejectSpace(token, nextToken)) { + context.report(node, token.loc.end, REJECTED_SPACE_MESSAGE); + } else if (token.value === ")" && shouldCloserHaveSpace(prevToken, token)) { + context.report(node, token.loc.end, MISSING_SPACE_MESSAGE); + } else if (token.value === ")" && shouldCloserRejectSpace(prevToken, token)) { + context.report(node, token.loc.end, REJECTED_SPACE_MESSAGE); + } + }); + } }; }; -},{}],273:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["always", "never"] + }, + { + "type": "object", + "properties": { + "exceptions": { + "type": "array", + "items": { + "enum": ["{}", "[]", "()", "empty"] + }, + "uniqueItems": true + } + }, + "additionalProperties": false + } +]; + +},{"../ast-utils":113}],297:[function(require,module,exports){ /** * @fileoverview Require spaces around infix operators * @author Michael Ficarra */ "use strict"; @@ -27996,66 +41363,147 @@ //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + var int32Hint = context.options[0] ? context.options[0].int32Hint === true : false; var OPERATORS = [ "*", "/", "%", "+", "-", "<<", ">>", ">>>", "<", "<=", ">", ">=", "in", "instanceof", "==", "!=", "===", "!==", "&", "^", "|", "&&", "||", "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "&=", "^=", "|=", "?", ":", "," ]; - function isSpaced(left, right) { + /** + * Returns the first token which violates the rule + * @param {ASTNode} left - The left node of the main node + * @param {ASTNode} right - The right node of the main node + * @returns {object} The violator token or null + * @private + */ + function getFirstNonSpacedToken(left, right) { var op, tokens = context.getTokensBetween(left, right, 1); for (var i = 1, l = tokens.length - 1; i < l; ++i) { op = tokens[i]; if ( op.type === "Punctuator" && OPERATORS.indexOf(op.value) >= 0 && (tokens[i - 1].range[1] >= op.range[0] || op.range[1] >= tokens[i + 1].range[0]) ) { - return false; + return op; } } - return true; + return null; } - function report(node) { - context.report(node, "Infix operators must be spaced."); + /** + * Reports an AST node as a rule violation + * @param {ASTNode} mainNode - The node to report + * @param {object} culpritToken - The token which has a problem + * @returns {void} + * @private + */ + function report(mainNode, culpritToken) { + context.report({ + node: mainNode, + loc: culpritToken.loc.start, + message: "Infix operators must be spaced.", + fix: function(fixer) { + var previousToken = context.getTokenBefore(culpritToken); + var afterToken = context.getTokenAfter(culpritToken); + var fixString = ""; + + if (culpritToken.range[0] - previousToken.range[1] === 0) { + fixString = " "; + } + + fixString += culpritToken.value; + + if (afterToken.range[0] - culpritToken.range[1] === 0) { + fixString += " "; + } + + return fixer.replaceText(culpritToken, fixString); + } + }); } + /** + * Check if the node is binary then report + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function checkBinary(node) { - if (!isSpaced(node.left, node.right)) { - report(node); + var nonSpacedNode = getFirstNonSpacedToken(node.left, node.right); + + if (nonSpacedNode) { + if (!(int32Hint && context.getSource(node).substr(-2) === "|0")) { + report(node, nonSpacedNode); + } } } + /** + * Check if the node is conditional + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function checkConditional(node) { - if (!isSpaced(node.test, node.consequent) || !isSpaced(node.consequent, node.alternate)) { - report(node); + var nonSpacedConsequesntNode = getFirstNonSpacedToken(node.test, node.consequent); + var nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate); + + if (nonSpacedConsequesntNode) { + report(node, nonSpacedConsequesntNode); + } else if (nonSpacedAlternateNode) { + report(node, nonSpacedAlternateNode); } } + /** + * Check if the node is a variable + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function checkVar(node) { - if (node.init && !isSpaced(node.id, node.init)) { - report(node); + var nonSpacedNode; + + if (node.init) { + nonSpacedNode = getFirstNonSpacedToken(node.id, node.init); + if (nonSpacedNode) { + report(node, nonSpacedNode); + } } } return { "AssignmentExpression": checkBinary, + "AssignmentPattern": checkBinary, "BinaryExpression": checkBinary, "LogicalExpression": checkBinary, "ConditionalExpression": checkConditional, "VariableDeclarator": checkVar }; }; -},{}],274:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "int32Hint": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{}],298:[function(require,module,exports){ /** * @fileoverview Require spaces following return, throw, and case * @author Michael Ficarra */ "use strict"; @@ -28064,16 +41512,28 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { + /** + * Check if the node for spaces + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ function check(node) { var tokens = context.getFirstTokens(node, 2), value = tokens[0].value; if (tokens[0].range[1] >= tokens[1].range[0]) { - context.report(node, "Keyword \"" + value + "\" must be followed by whitespace."); + context.report({ + node: node, + message: "Keyword \"" + value + "\" must be followed by whitespace.", + fix: function(fixer) { + return fixer.insertTextAfterRange(tokens[0].range, " "); + } + }); } } return { "ReturnStatement": function(node) { @@ -28089,11 +41549,13 @@ "ThrowStatement": check }; }; -},{}],275:[function(require,module,exports){ +module.exports.schema = []; + +},{}],299:[function(require,module,exports){ /** * @fileoverview This rule shoud require or disallow spaces before or after unary operations. * @author Marcin Kumorek * @copyright 2014 Marcin Kumorek. All rights reserved. */ @@ -28109,28 +41571,20 @@ //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- /** - * Check if the parent unary operator is "!" in order to know if it's "!!" convert to Boolean or just "!" negation + * Check if the node is the first "!" in a "!!" convert to Boolean expression * @param {ASTnode} node AST node - * @returns {boolean} Whether or not the parent is unary "!" operator + * @returns {boolean} Whether or not the node is first "!" in "!!" */ - function isParentUnaryBangExpression(node) { - return node && node.parent && node.parent.type === "UnaryExpression" && node.parent.operator === "!"; + function isFirstBangInBangBangExpression(node) { + return node && node.type === "UnaryExpression" && node.argument.operator === "!" && + node.argument && node.argument.type === "UnaryExpression" && node.argument.operator === "!"; } /** - * Checks if the type is a unary word expression - * @param {string} type value of AST token - * @returns {boolean} Whether the word is in the list of known words - */ - function isWordExpression(type) { - return ["delete", "new", "typeof", "void"].indexOf(type) !== -1; - } - - /** * Check if the node's child argument is an "ObjectExpression" * @param {ASTnode} node AST node * @returns {boolean} Whether or not the argument's type is "ObjectExpression" */ function isArgumentObjectExpression(node) { @@ -28140,22 +41594,37 @@ /** * Check Unary Word Operators for spaces after the word operator * @param {ASTnode} node AST node * @param {object} firstToken first token from the AST node * @param {object} secondToken second token from the AST node + * @param {string} word The word to be used for reporting * @returns {void} */ - function checkUnaryWordOperatorForSpaces(node, firstToken, secondToken) { + function checkUnaryWordOperatorForSpaces(node, firstToken, secondToken, word) { + word = word || firstToken.value; + if (options.words) { if (secondToken.range[0] === firstToken.range[1]) { - context.report(node, "Unary word operator \"" + firstToken.value + "\" must be followed by whitespace."); + context.report({ + node: node, + message: "Unary word operator \"" + word + "\" must be followed by whitespace.", + fix: function(fixer) { + return fixer.insertTextAfter(firstToken, " "); + } + }); } } if (!options.words && isArgumentObjectExpression(node)) { if (secondToken.range[0] > firstToken.range[1]) { - context.report(node, "Unexpected space after unary word operator \"" + firstToken.value + "\"."); + context.report({ + node: node, + message: "Unexpected space after unary word operator \"" + word + "\".", + fix: function(fixer) { + return fixer.removeRange([firstToken.range[1], secondToken.range[0]]); + } + }); } } } /** @@ -28166,36 +41635,60 @@ function checkForSpaces(node) { var tokens = context.getFirstTokens(node, 2), firstToken = tokens[0], secondToken = tokens[1]; - if (isWordExpression(firstToken.value)) { + if ((node.type === "NewExpression" || node.prefix) && firstToken.type === "Keyword") { checkUnaryWordOperatorForSpaces(node, firstToken, secondToken); return void 0; } if (options.nonwords) { if (node.prefix) { - if (isParentUnaryBangExpression(node)) { + if (isFirstBangInBangBangExpression(node)) { return void 0; } if (firstToken.range[1] === secondToken.range[0]) { - context.report(node, "Unary operator \"" + firstToken.value + "\" must be followed by whitespace."); + context.report({ + node: node, + message: "Unary operator \"" + firstToken.value + "\" must be followed by whitespace.", + fix: function(fixer) { + return fixer.insertTextAfter(firstToken, " "); + } + }); } } else { if (firstToken.range[1] === secondToken.range[0]) { - context.report(node, "Space is required before unary expressions \"" + secondToken.value + "\"."); + context.report({ + node: node, + message: "Space is required before unary expressions \"" + secondToken.value + "\".", + fix: function(fixer) { + return fixer.insertTextBefore(secondToken, " "); + } + }); } } } else { if (node.prefix) { if (secondToken.range[0] > firstToken.range[1]) { - context.report(node, "Unexpected space after unary operator \"" + firstToken.value + "\"."); + context.report({ + node: node, + message: "Unexpected space after unary operator \"" + firstToken.value + "\".", + fix: function(fixer) { + return fixer.removeRange([firstToken.range[1], secondToken.range[0]]); + } + }); } } else { if (secondToken.range[0] > firstToken.range[1]) { - context.report(node, "Unexpected space before unary operator \"" + secondToken.value + "\"."); + context.report({ + node: node, + message: "Unexpected space before unary operator \"" + secondToken.value + "\".", + fix: function(fixer) { + return fixer.removeRange([firstToken.range[1], secondToken.range[0]]); + } + }); } } } } @@ -28204,89 +41697,297 @@ //-------------------------------------------------------------------------- return { "UnaryExpression": checkForSpaces, "UpdateExpression": checkForSpaces, - "NewExpression": checkForSpaces + "NewExpression": checkForSpaces, + "YieldExpression": function(node) { + var tokens = context.getFirstTokens(node, 3), + word = "yield"; + + if (!node.argument) { + return; + } + + if (node.delegate) { + word += "*"; + checkUnaryWordOperatorForSpaces(node, tokens[1], tokens[2], word); + } else { + checkUnaryWordOperatorForSpaces(node, tokens[0], tokens[1], word); + } + } }; }; -},{}],276:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "words": { + "type": "boolean" + }, + "nonwords": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{}],300:[function(require,module,exports){ /** - * @fileoverview Enforces or disallows a space beginning a single-line comment. - * @author Greg Cochard + * @fileoverview Source code for spaced-comments rule + * @author Gyandeep Singh + * @copyright 2015 Toru Nagashima. All rights reserved. + * @copyright 2015 Gyandeep Singh. All rights reserved. * @copyright 2014 Greg Cochard. All rights reserved. */ "use strict"; +var escapeStringRegexp = require("escape-string-regexp"); + //------------------------------------------------------------------------------ -// Rule Definition +// Helpers //------------------------------------------------------------------------------ -module.exports = function(context) { +/** + * Escapes the control characters of a given string. + * @param {string} s - A string to escape. + * @returns {string} An escaped string. + */ +function escape(s) { + var isOneChar = s.length === 1; + s = escapeStringRegexp(s); + return isOneChar ? s : "(?:" + s + ")"; +} - // Unless the first option is never, require a space - var requireSpace = context.options[0] !== "never"; +/** + * Escapes the control characters of a given string. + * And adds a repeat flag. + * @param {string} s - A string to escape. + * @returns {string} An escaped string. + */ +function escapeAndRepeat(s) { + return escape(s) + "+"; +} - // Default to match anything, so all will fail if there are no exceptions - var exceptionMatcher = new RegExp(" "); +/** + * Parses `markers` option. + * If markers don't include `"*"`, this adds `"*"` to allow JSDoc comments. + * @param {string[]} [markers] - A marker list. + * @returns {string[]} A marker list. + */ +function parseMarkersOption(markers) { + markers = markers ? markers.slice(0) : []; - // Grab the exceptions array and build a RegExp matcher for it - var hasExceptions = context.options.length === 2; - var unescapedExceptions = hasExceptions ? context.options[1].exceptions : []; - var exceptions; + // `*` is a marker for JSDoc comments. + if (markers.indexOf("*") === -1) { + markers.push("*"); + } - if (unescapedExceptions.length) { - exceptions = unescapedExceptions.map(function(s) { - return s.replace(/([.*+?${}()|\^\[\]\/\\])/g, "\\$1"); - }); - exceptionMatcher = new RegExp("(^(" + exceptions.join(")+$)|(^(") + ")+$)"); + return markers; +} + +/** + * Creates RegExp object for `always` mode. + * Generated pattern is below: + * + * 1. First, a marker or nothing. + * 2. Next, a space or an exception pattern sequence. + * + * @param {string[]} markers - A marker list. + * @param {string[]} exceptions - A exception pattern list. + * @returns {RegExp} A RegExp object for `always` mode. + */ +function createAlwaysStylePattern(markers, exceptions) { + var pattern = "^"; + + // A marker or nothing. + // ["*"] ==> "\*?" + // ["*", "!"] ==> "(?:\*|!)?" + // ["*", "/", "!<"] ==> "(?:\*|\/|(?:!<))?" ==> https://jex.im/regulex/#!embed=false&flags=&re=(%3F%3A%5C*%7C%5C%2F%7C(%3F%3A!%3C))%3F + if (markers.length === 1) { + // the marker. + pattern += escape(markers[0]); + } else { + // one of markers. + pattern += "(?:"; + pattern += markers.map(escape).join("|"); + pattern += ")"; } + pattern += "?"; // or nothing. + // A space or an exception pattern sequence. + // [] ==> "\s" + // ["-"] ==> "(?:\s|\-+$)" + // ["-", "="] ==> "(?:\s|(?:\-+|=+)$)" + // ["-", "=", "--=="] ==> "(?:\s|(?:\-+|=+|(?:\-\-==)+)$)" ==> https://jex.im/regulex/#!embed=false&flags=&re=(%3F%3A%5Cs%7C(%3F%3A%5C-%2B%7C%3D%2B%7C(%3F%3A%5C-%5C-%3D%3D)%2B)%24) + if (exceptions.length === 0) { + // a space. + pattern += "\\s"; + } else { + // a space or... + pattern += "(?:\\s|"; + if (exceptions.length === 1) { + // a sequence of the exception pattern. + pattern += escapeAndRepeat(exceptions[0]); + } else { + // a sequence of one of exception patterns. + pattern += "(?:"; + pattern += exceptions.map(escapeAndRepeat).join("|"); + pattern += ")"; + } + pattern += "(?:$|[\n\r]))"; // the sequence continues until the end. + } + return new RegExp(pattern); +} - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- +/** + * Creates RegExp object for `never` mode. + * Generated pattern is below: + * + * 1. First, a marker or nothing (captured). + * 2. Next, a space or a tab. + * + * @param {string[]} markers - A marker list. + * @returns {RegExp} A RegExp object for `never` mode. + */ +function createNeverStylePattern(markers) { + var pattern = "^(" + markers.map(escape).join("|") + ")?[ \t]"; + return new RegExp(pattern); +} - return { +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ - "LineComment": function checkCommentForSpace(node) { +module.exports = function(context) { + // Unless the first option is never, require a space + var requireSpace = context.options[0] !== "never"; - if (requireSpace) { + // Parse the second options. + // If markers don't include `"*"`, it's added automatically for JSDoc comments. + var config = context.options[1] || {}; + var styleRules = ["block", "line"].reduce(function(rule, type) { + var markers = parseMarkersOption(config[type] && config[type].markers || config.markers); + var exceptions = config[type] && config[type].exceptions || config.exceptions || []; - // If length is zero, ignore it - if (node.value.length === 0) { - return; - } + // Create RegExp object for valid patterns. + rule[type] = { + regex: requireSpace ? createAlwaysStylePattern(markers, exceptions) : createNeverStylePattern(markers), + hasExceptions: exceptions.length > 0 + }; - // Space expected and not found - if (node.value.indexOf(" ") !== 0 && node.value.indexOf("\t") !== 0) { + return rule; + }, {}); - /* - * Do two tests; one for space starting the line, - * and one for a comment comprised only of exceptions - */ - if (hasExceptions && !exceptionMatcher.test(node.value)) { - context.report(node, "Expected exception block, space or tab after // in comment."); - } else if (!hasExceptions) { - context.report(node, "Expected space or tab after // in comment."); - } - } + /** + * Reports a given comment if it's invalid. + * @param {ASTNode} node - a comment node to check. + * @returns {void} + */ + function checkCommentForSpace(node) { + var type = node.type.toLowerCase(), + rule = styleRules[type], + commentIdentifier = type === "block" ? "/*" : "//"; - } else { + // Ignores empty comments. + if (node.value.length === 0) { + return; + } - if (node.value.indexOf(" ") === 0 || node.value.indexOf("\t") === 0) { - context.report(node, "Unexpected space or tab after // in comment."); + // Checks. + if (requireSpace) { + if (!rule.regex.test(node.value)) { + if (rule.hasExceptions) { + context.report(node, "Expected exception block, space or tab after \"" + commentIdentifier + "\" in comment."); + } else { + context.report(node, "Expected space or tab after \"" + commentIdentifier + "\" in comment."); } } + } else { + var matched = rule.regex.exec(node.value); + if (matched) { + if (!matched[1]) { + context.report(node, "Unexpected space or tab after \"" + commentIdentifier + "\" in comment."); + } else { + context.report(node, "Unexpected space or tab after marker (" + matched[1] + ") in comment."); + } + } } + } + return { + + "LineComment": checkCommentForSpace, + "BlockComment": checkCommentForSpace + }; }; -},{}],277:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["always", "never"] + }, + { + "type": "object", + "properties": { + "exceptions": { + "type": "array", + "items": { + "type": "string" + } + }, + "markers": { + "type": "array", + "items": { + "type": "string" + } + }, + "line": { + "type": "object", + "properties": { + "exceptions": { + "type": "array", + "items": { + "type": "string" + } + }, + "markers": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "block": { + "type": "object", + "properties": { + "exceptions": { + "type": "array", + "items": { + "type": "string" + } + }, + "markers": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } +]; + +},{"escape-string-regexp":74}],301:[function(require,module,exports){ /** * @fileoverview Rule to control usage of strict mode directives. * @author Brandon Mills * @copyright 2015 Brandon Mills. All rights reserved. * @copyright 2013-2014 Nicholas C. Zakas. All rights reserved. @@ -28302,11 +42003,13 @@ var messages = { function: "Use the function form of \"use strict\".", global: "Use the global form of \"use strict\".", multiple: "Multiple \"use strict\" directives.", never: "Strict mode is not permitted.", - unnecessary: "Unnecessary \"use strict\" directive." + unnecessary: "Unnecessary \"use strict\" directive.", + unnecessaryInModules: "\"use strict\" is unnecessary inside of modules.", + unnecessaryInClasses: "\"use strict\" is unnecessary inside of classes." }; /** * Gets all of the Use Strict Directives in the Directive Prologue of a group of * statements. @@ -28338,14 +42041,11 @@ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { - var mode = context.options[0], - isModule = context.ecmaFeatures.modules, - modes = {}, - scopes = []; + var mode = context.options[0]; /** * Report a node or array of nodes with a given message. * @param {(ASTNode|ASTNode[])} nodes Node or nodes to report. * @param {string} message Message to display. @@ -28362,140 +42062,114 @@ context.report(nodes, message); } } //-------------------------------------------------------------------------- - // "deprecated" mode (default) + // "never" mode //-------------------------------------------------------------------------- - /** - * Determines if a given node is "use strict". - * @param {ASTNode} node The node to check. - * @returns {boolean} True if the node is a strict pragma, false if not. - * @void - */ - function isStrictPragma(node) { - return (node && node.type === "ExpressionStatement" && - node.expression.value === "use strict"); + if (mode === "never") { + return { + "Program": function(node) { + report(getUseStrictDirectives(node.body), messages.never); + }, + "FunctionDeclaration": function(node) { + report(getUseStrictDirectives(node.body.body), messages.never); + }, + "FunctionExpression": function(node) { + report(getUseStrictDirectives(node.body.body), messages.never); + }, + "ArrowFunctionExpression": function(node) { + if (node.body.type === "BlockStatement") { + report(getUseStrictDirectives(node.body.body), messages.never); + } + } + }; } - /** - * When you enter a scope, push the strict value from the previous scope - * onto the stack. - * @param {ASTNode} node The AST node being checked. - * @returns {void} - * @private - */ - function enterScope(node) { - - var isStrict = false, - isProgram = (node.type === "Program"), - isParentGlobal = scopes.length === 1, - isParentStrict = scopes.length ? scopes[scopes.length - 1] : false; - - // look for the "use strict" pragma - if (isModule) { - isStrict = true; - } else if (isProgram) { - isStrict = isStrictPragma(node.body[0]) || isParentStrict; - } else { - isStrict = node.body.body && isStrictPragma(node.body.body[0]) || isParentStrict; - } - - scopes.push(isStrict); - - // never warn if the parent is strict or the function is strict - if (!isParentStrict && !isStrict && isParentGlobal) { - context.report(node, "Missing \"use strict\" statement."); - } - } - - /** - * When you exit a scope, pop off the top scope and see if it's true or - * false. - * @returns {void} - * @private - */ - function exitScope() { - scopes.pop(); - } - - modes.deprecated = { - "Program": enterScope, - "FunctionDeclaration": enterScope, - "FunctionExpression": enterScope, - "ArrowFunctionExpression": enterScope, - - "Program:exit": exitScope, - "FunctionDeclaration:exit": exitScope, - "FunctionExpression:exit": exitScope, - "ArrowFunctionExpression:exit": exitScope - }; - //-------------------------------------------------------------------------- - // "never" mode + // If this is modules, all "use strict" directives are unnecessary. //-------------------------------------------------------------------------- - modes.never = { - "Program": function(node) { - report(getUseStrictDirectives(node.body), messages.never); - }, - "FunctionDeclaration": function(node) { - report(getUseStrictDirectives(node.body.body), messages.never); - }, - "FunctionExpression": function(node) { - report(getUseStrictDirectives(node.body.body), messages.never); - } - }; + if (context.ecmaFeatures.modules) { + return { + "Program": function(node) { + report(getUseStrictDirectives(node.body), messages.unnecessaryInModules); + }, + "FunctionDeclaration": function(node) { + report(getUseStrictDirectives(node.body.body), messages.unnecessaryInModules); + }, + "FunctionExpression": function(node) { + report(getUseStrictDirectives(node.body.body), messages.unnecessaryInModules); + }, + "ArrowFunctionExpression": function(node) { + if (node.body.type === "BlockStatement") { + report(getUseStrictDirectives(node.body.body), messages.unnecessaryInModules); + } + } + }; + } //-------------------------------------------------------------------------- // "global" mode //-------------------------------------------------------------------------- - modes.global = { - "Program": function(node) { - var useStrictDirectives = getUseStrictDirectives(node.body); + if (mode === "global") { + return { + "Program": function(node) { + var useStrictDirectives = getUseStrictDirectives(node.body); - if (!isModule && node.body.length && useStrictDirectives.length < 1) { - report(node, messages.global); - } else if (isModule) { - report(useStrictDirectives, messages.unnecessary); - } else { - report(useStrictDirectives.slice(1), messages.multiple); + if (node.body.length > 0 && useStrictDirectives.length === 0) { + report(node, messages.global); + } else { + report(useStrictDirectives.slice(1), messages.multiple); + } + }, + "FunctionDeclaration": function(node) { + report(getUseStrictDirectives(node.body.body), messages.global); + }, + "FunctionExpression": function(node) { + report(getUseStrictDirectives(node.body.body), messages.global); + }, + "ArrowFunctionExpression": function(node) { + if (node.body.type === "BlockStatement") { + report(getUseStrictDirectives(node.body.body), messages.global); + } } - }, - "FunctionDeclaration": function(node) { - report(getUseStrictDirectives(node.body.body), messages.global); - }, - "FunctionExpression": function(node) { - report(getUseStrictDirectives(node.body.body), messages.global); - } - }; + }; + } //-------------------------------------------------------------------------- - // "function" mode + // "function" mode (Default) //-------------------------------------------------------------------------- + var scopes = [], + classScopes = []; + /** * Entering a function pushes a new nested scope onto the stack. The new * scope is true if the nested function is strict mode code. * @param {ASTNode} node The function declaration or expression. * @returns {void} */ function enterFunction(node) { - var useStrictDirectives = getUseStrictDirectives(node.body.body), - isParentGlobal = scopes.length === 0, - isParentStrict = isModule || (scopes.length && scopes[scopes.length - 1]), - isStrict = useStrictDirectives.length > 0 || isModule; + var isInClass = classScopes.length > 0, + isParentGlobal = scopes.length === 0 && classScopes.length === 0, + isParentStrict = scopes.length > 0 && scopes[scopes.length - 1], + isNotBlock = node.body.type !== "BlockStatement", + useStrictDirectives = isNotBlock ? [] : getUseStrictDirectives(node.body.body), + isStrict = useStrictDirectives.length > 0; if (isStrict) { - if (isParentStrict && useStrictDirectives.length) { + if (isParentStrict) { report(useStrictDirectives[0], messages.unnecessary); + } else if (isInClass) { + report(useStrictDirectives[0], messages.unnecessaryInClasses); } report(useStrictDirectives.slice(1), messages.multiple); - } else if (isParentGlobal && !isModule) { + } else if (isParentGlobal) { report(node, messages.function); } scopes.push(isParentStrict || isStrict); } @@ -28506,25 +42180,40 @@ */ function exitFunction() { scopes.pop(); } - modes.function = { + return { "Program": function(node) { report(getUseStrictDirectives(node.body), messages.function); }, + + // Inside of class bodies are always strict mode. + "ClassBody": function() { + classScopes.push(true); + }, + "ClassBody:exit": function() { + classScopes.pop(); + }, + "FunctionDeclaration": enterFunction, "FunctionExpression": enterFunction, + "ArrowFunctionExpression": enterFunction, + "FunctionDeclaration:exit": exitFunction, - "FunctionExpression:exit": exitFunction + "FunctionExpression:exit": exitFunction, + "ArrowFunctionExpression:exit": exitFunction }; - - return modes[mode || "deprecated"]; - }; -},{}],278:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["never", "global", "function"] + } +]; + +},{}],302:[function(require,module,exports){ /** * @fileoverview Rule to flag comparisons to the value NaN * @author James Allardice * @copyright 2014 Jordan Harband. All rights reserved. * @copyright 2013 James Allardice. All rights reserved. @@ -28534,23 +42223,25 @@ //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = function (context) { +module.exports = function(context) { return { - "BinaryExpression": function (node) { + "BinaryExpression": function(node) { if (/^(?:[<>]|[!=]=)=?$/.test(node.operator) && (node.left.name === "NaN" || node.right.name === "NaN")) { context.report(node, "Use the isNaN function to compare with NaN."); } } }; }; -},{}],279:[function(require,module,exports){ +module.exports.schema = []; + +},{}],303:[function(require,module,exports){ /** * @fileoverview Validates JSDoc comments are syntactically correct * @author Nicholas C. Zakas * @copyright 2014 Nicholas C. Zakas. All rights reserved. */ @@ -28568,30 +42259,46 @@ module.exports = function(context) { var options = context.options[0] || {}, prefer = options.prefer || {}, + sourceCode = context.getSourceCode(), // these both default to true, so you have to explicitly make them false - requireReturn = options.requireReturn === false ? false : true, + requireReturn = options.requireReturn !== false, requireParamDescription = options.requireParamDescription !== false, - requireReturnDescription = options.requireReturnDescription !== false; + requireReturnDescription = options.requireReturnDescription !== false, + requireReturnType = options.requireReturnType !== false; //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- // Using a stack to store if a function returns or not (handling nested functions) var fns = []; /** + * Check if node type is a Class + * @param {ASTNode} node node to check. + * @returns {boolean} True is its a class + * @private + */ + function isTypeClass(node) { + return node.type === "ClassExpression" || node.type === "ClassDeclaration"; + } + + /** * When parsing a new function, store it in our function stack. + * @param {ASTNode} node A function node to check. * @returns {void} * @private */ - function startFunction() { - fns.push({returnPresent: false}); + function startFunction(node) { + fns.push({ + returnPresent: (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") || + isTypeClass(node) + }); } /** * Indicate that return has been found in the current function. * @param {ASTNode} node The return node. @@ -28605,20 +42312,31 @@ functionState.returnPresent = true; } } /** + * Check if return tag type is void or undefined + * @param {Object} tag JSDoc tag + * @returns {boolean} True if its of type void or undefined + * @private + */ + function isValidReturnType(tag) { + return tag.type === null || tag.type.name === "void" || tag.type.type === "UndefinedLiteral"; + } + + /** * Validate the JSDoc node and output warnings if anything is wrong. * @param {ASTNode} node The AST node to check. * @returns {void} * @private */ function checkJSDoc(node) { - var jsdocNode = context.getJSDocComment(node), + var jsdocNode = sourceCode.getJSDocComment(node), functionData = fns.pop(), hasReturns = false, hasConstructor = false, + isOverride = false, params = Object.create(null), jsdoc; // make sure only to validate JSDoc comments if (jsdocNode) { @@ -28643,10 +42361,12 @@ jsdoc.tags.forEach(function(tag) { switch (tag.title) { case "param": + case "arg": + case "argument": if (!tag.type) { context.report(jsdocNode, "Missing JSDoc parameter type for '{{name}}'.", { name: tag.name }); } if (!tag.description && requireParamDescription) { @@ -28665,15 +42385,15 @@ hasReturns = true; if (!requireReturn && !functionData.returnPresent && tag.type.name !== "void" && tag.type.name !== "undefined") { context.report(jsdocNode, "Unexpected @" + tag.title + " tag; function has no return statement."); } else { - if (!tag.type) { + if (requireReturnType && !tag.type) { context.report(jsdocNode, "Missing JSDoc return type."); } - if (tag.type.name !== "void" && !tag.description && requireReturnDescription) { + if (!isValidReturnType(tag) && !tag.description && requireReturnDescription) { context.report(jsdocNode, "Missing JSDoc return description."); } } break; @@ -28681,44 +42401,62 @@ case "constructor": case "class": hasConstructor = true; break; + case "override": + case "inheritdoc": + isOverride = true; + break; + // no default } // check tag preferences - if (prefer.hasOwnProperty(tag.title)) { + if (prefer.hasOwnProperty(tag.title) && tag.title !== prefer[tag.title]) { context.report(jsdocNode, "Use @{{name}} instead.", { name: prefer[tag.title] }); } }); // check for functions missing @returns - if (!hasReturns && !hasConstructor) { + if (!isOverride && !hasReturns && !hasConstructor && node.parent.kind !== "get" && !isTypeClass(node)) { if (requireReturn || functionData.returnPresent) { - context.report(jsdocNode, "Missing JSDoc @returns for function."); + context.report(jsdocNode, "Missing JSDoc @" + (prefer.returns || "returns") + " for function."); } } // check the parameters var jsdocParams = Object.keys(params); - node.params.forEach(function(param, i) { - var name = param.name; + if (node.params) { + node.params.forEach(function(param, i) { + var name = param.name; - if (jsdocParams[i] && (name !== jsdocParams[i])) { - context.report(jsdocNode, "Expected JSDoc for '{{name}}' but found '{{jsdocName}}'.", { - name: name, - jsdocName: jsdocParams[i] - }); - } else if (!params[name]) { - context.report(jsdocNode, "Missing JSDoc for parameter '{{name}}'.", { - name: name - }); + // TODO(nzakas): Figure out logical things to do with destructured, default, rest params + if (param.type === "Identifier") { + if (jsdocParams[i] && (name !== jsdocParams[i])) { + context.report(jsdocNode, "Expected JSDoc for '{{name}}' but found '{{jsdocName}}'.", { + name: name, + jsdocName: jsdocParams[i] + }); + } else if (!params[name] && !isOverride) { + context.report(jsdocNode, "Missing JSDoc for parameter '{{name}}'.", { + name: name + }); + } + } + }); + } + + if (options.matchDescription) { + var regex = new RegExp(options.matchDescription); + + if (!regex.test(jsdoc.description)) { + context.report(jsdocNode, "JSDoc description does not satisfy the regex pattern."); } - }); + } } } @@ -28728,19 +42466,53 @@ return { "ArrowFunctionExpression": startFunction, "FunctionExpression": startFunction, "FunctionDeclaration": startFunction, + "ClassExpression": startFunction, + "ClassDeclaration": startFunction, "ArrowFunctionExpression:exit": checkJSDoc, "FunctionExpression:exit": checkJSDoc, "FunctionDeclaration:exit": checkJSDoc, + "ClassExpression:exit": checkJSDoc, + "ClassDeclaration:exit": checkJSDoc, "ReturnStatement": addReturn }; }; -},{"doctrine":9}],280:[function(require,module,exports){ +module.exports.schema = [ + { + "type": "object", + "properties": { + "prefer": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "requireReturn": { + "type": "boolean" + }, + "requireParamDescription": { + "type": "boolean" + }, + "requireReturnDescription": { + "type": "boolean" + }, + "matchDescription": { + "type": "string" + }, + "requireReturnType": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{"doctrine":10}],304:[function(require,module,exports){ /** * @fileoverview Ensures that the results of typeof are compared against a valid string * @author Ian Christian Myers */ "use strict"; @@ -28758,11 +42530,11 @@ // Public //-------------------------------------------------------------------------- return { - "UnaryExpression": function (node) { + "UnaryExpression": function(node) { var parent, sibling; if (node.operator === "typeof") { parent = context.getAncestors().pop(); @@ -28778,11 +42550,13 @@ }; }; -},{}],281:[function(require,module,exports){ +module.exports.schema = []; + +},{}],305:[function(require,module,exports){ /** * @fileoverview Rule to enforce var declarations are only at the top of a function. * @author Danny Fritz * @author Gyandeep Singh * @copyright 2014 Danny Fritz. All rights reserved. @@ -28792,11 +42566,11 @@ //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = function (context) { +module.exports = function(context) { var errorMessage = "All \"var\" declarations must be at the top of the function scope."; //-------------------------------------------------------------------------- // Helpers //-------------------------------------------------------------------------- @@ -28809,21 +42583,31 @@ return node.type === "ExpressionStatement" && node.expression.type === "Literal" && typeof node.expression.value === "string"; } /** + * Check to see if its a ES6 import declaration + * @param {ASTNode} node - any node + * @returns {Boolean} whether the given node represents a import declaration + */ + function looksLikeImport(node) { + return node.type === "ImportDeclaration" || node.type === "ImportSpecifier" || + node.type === "ImportDefaultSpecifier" || node.type === "ImportNamespaceSpecifier"; + } + + /** * Checks whether this variable is on top of the block body * @param {ASTNode} node - The node to check * @param {ASTNode[]} statements - collection of ASTNodes for the parent node block * @returns {Boolean} True if var is on top otherwise false */ function isVarOnTop(node, statements) { var i = 0, l = statements.length; // skip over directives for (; i < l; ++i) { - if (!looksLikeDirective(statements[i])) { + if (!looksLikeDirective(statements[i]) && !looksLikeImport(statements[i])) { break; } } for (; i < l; ++i) { @@ -28866,28 +42650,30 @@ //-------------------------------------------------------------------------- // Public API //-------------------------------------------------------------------------- return { - "VariableDeclaration": function (node) { + "VariableDeclaration": function(node) { var ancestors = context.getAncestors(); var parent = ancestors.pop(); var grandParent = ancestors.pop(); - if (node.kind === "var") {// check variable is `var` type and not `let` or `const` - if (parent.type === "Program") {// That means its a global variable + if (node.kind === "var") { // check variable is `var` type and not `let` or `const` + if (parent.type === "Program") { // That means its a global variable globalVarCheck(node, parent); } else { blockScopeVarCheck(node, parent, grandParent); } } } }; }; -},{}],282:[function(require,module,exports){ +module.exports.schema = []; + +},{}],306:[function(require,module,exports){ /** * @fileoverview Rule to flag when IIFE is not wrapped in parens * @author Ilya Volodin * @copyright 2013 Ilya Volodin. All rights reserved. */ @@ -28900,10 +42686,16 @@ module.exports = function(context) { var style = context.options[0] || "outside"; + /** + * Check if the node is wrapped in () + * @param {ASTNode} node node to evaluate + * @returns {boolean} True if it is wrapped + * @private + */ function wrapped(node) { var previousToken = context.getTokenBefore(node), nextToken = context.getTokenAfter(node); return previousToken && previousToken.value === "(" && nextToken && nextToken.value === ")"; @@ -28927,11 +42719,17 @@ } }; }; -},{}],283:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["outside", "inside", "any"] + } +]; + +},{}],307:[function(require,module,exports){ /** * @fileoverview Rule to flag when regex literals are not wrapped in parens * @author Matt DuVall <http://www.mattduvall.com> */ @@ -28965,11 +42763,13 @@ } }; }; -},{}],284:[function(require,module,exports){ +module.exports.schema = []; + +},{}],308:[function(require,module,exports){ /** * @fileoverview Rule to require or disallow yoda comparisons * @author Nicholas C. Zakas * @copyright 2014 Nicholas C. Zakas. All rights reserved. * @copyright 2014 Brandon Mills. All rights reserved. @@ -28988,10 +42788,19 @@ function isComparisonOperator(operator) { return (/^(==|===|!=|!==|<|>|<=|>=)$/).test(operator); } /** + * Determines whether an operator is an equality operator. + * @param {String} operator The operator to check. + * @returns {boolean} Whether or not it is an equality operator. + */ +function isEqualityOperator(operator) { + return (/^(==|===)$/).test(operator); +} + +/** * Determines whether an operator is one used in a range test. * Allowed operators are `<` and `<=`. * @param {String} operator The operator to check. * @returns {boolean} Whether the operator is used in range tests. */ @@ -29062,24 +42871,27 @@ case "MemberExpression": // x[0] = x[0] // x[y] = x[y] // x.y = x.y return same(a.object, b.object) && same(a.property, b.property); + case "ThisExpression": + return true; default: return false; } } //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ -module.exports = function (context) { +module.exports = function(context) { // Default to "never" (!always) if no option var always = (context.options[0] === "always"); var exceptRange = (context.options[1] && context.options[1].exceptRange); + var onlyEquality = (context.options[1] && context.options[1].onlyEquality); /** * Determines whether node represents a range test. * A range test is a "between" test like `(0 <= x && x < 1)` or an "outside" * test like `(x < 0 || 1 <= x)`. It must be wrapped in parentheses, and @@ -29153,10 +42965,12 @@ "BinaryExpression": always ? function(node) { // Comparisons must always be yoda-style: if ("blue" === color) if ( (node.right.type === "Literal" || looksLikeLiteral(node.right)) && + !(node.left.type === "Literal" || looksLikeLiteral(node.left)) && + !(!isEqualityOperator(node.operator) && onlyEquality) && isComparisonOperator(node.operator) && !(exceptRange && isRangeTest(context.getAncestors().pop())) ) { context.report(node, "Expected literal to be on the left side of " + node.operator + "."); } @@ -29164,10 +42978,12 @@ } : function(node) { // Comparisons must never be yoda-style (default) if ( (node.left.type === "Literal" || looksLikeLiteral(node.left)) && + !(node.right.type === "Literal" || looksLikeLiteral(node.right)) && + !(!isEqualityOperator(node.operator) && onlyEquality) && isComparisonOperator(node.operator) && !(exceptRange && isRangeTest(context.getAncestors().pop())) ) { context.report(node, "Expected literal to be on the right side of " + node.operator + "."); } @@ -29175,11 +42991,29 @@ } }; }; -},{}],285:[function(require,module,exports){ +module.exports.schema = [ + { + "enum": ["always", "never"] + }, + { + "type": "object", + "properties": { + "exceptRange": { + "type": "boolean" + }, + "onlyEquality": { + "type": "boolean" + } + }, + "additionalProperties": false + } +]; + +},{}],309:[function(require,module,exports){ (function (process){ /** * @fileoverview Tracks performance of individual rules. * @author Brandon Mills * @copyright 2014 Brandon Mills. All rights reserved. @@ -29190,15 +43024,31 @@ //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ /* istanbul ignore next */ +/** + * Align the string to left + * @param {string} str string to evaluate + * @param {int} len length of the string + * @param {string} ch delimiter character + * @returns {string} modified string + * @private + */ function alignLeft(str, len, ch) { return str + new Array(len - str.length + 1).join(ch || " "); } /* istanbul ignore next */ +/** + * Align the string to right + * @param {string} str string to evaluate + * @param {int} len length of the string + * @param {string} ch delimiter character + * @returns {string} modified string + * @private + */ function alignRight(str, len, ch) { return new Array(len - str.length + 1).join(ch || " ") + str; } //------------------------------------------------------------------------------ @@ -29209,10 +43059,16 @@ var HEADERS = ["Rule", "Time (ms)", "Relative"]; var ALIGN = [alignLeft, alignRight, alignRight]; /* istanbul ignore next */ +/** + * display the data + * @param {object} data Data object to be displayed + * @returns {string} modified string + * @private + */ function display(data) { var total = 0; var rows = Object.keys(data) .map(function(key) { var time = data[key]; @@ -29261,10 +43117,17 @@ /* istanbul ignore next */ module.exports = (function() { var data = Object.create(null); + /** + * Time the run + * @param {*} key key from the data object + * @param {Function} fn function to be called + * @returns {Function} function to be executed + * @private + */ function time(key, fn) { if (typeof data[key] === "undefined") { data[key] = 0; } @@ -29288,11 +43151,11 @@ }; }()); }).call(this,require('_process')) -},{"_process":6}],286:[function(require,module,exports){ +},{"_process":109}],310:[function(require,module,exports){ /** * @fileoverview Object to handle access and retrieval of tokens. * @author Brandon Mills * @copyright 2014 Nicholas C. Zakas. All rights reserved. * @copyright 2014 Brandon Mills. All rights reserved. @@ -29491,87 +43354,747 @@ }; return api; }; -},{}],287:[function(require,module,exports){ +},{}],311:[function(require,module,exports){ /** - * @fileoverview Common utilities. + * @fileoverview The event generator for comments. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. */ + "use strict"; //------------------------------------------------------------------------------ -// Constants +// Helpers //------------------------------------------------------------------------------ -var PLUGIN_NAME_PREFIX = "eslint-plugin-"; +/** + * Check collection of comments to prevent double event for comment as + * leading and trailing, then emit event if passing + * @param {ASTNode[]} comments - Collection of comment nodes + * @param {EventEmitter} emitter - The event emitter which is the destination of events. + * @param {Object[]} locs - List of locations of previous comment nodes + * @param {string} eventName - Event name postfix + * @returns {void} + */ +function emitComments(comments, emitter, locs, eventName) { + if (comments.length > 0) { + comments.forEach(function(node) { + var index = locs.indexOf(node.loc); + if (index >= 0) { + locs.splice(index, 1); + } else { + locs.push(node.loc); + emitter.emit(node.type + eventName, node); + } + }); + } +} +/** + * Shortcut to check and emit enter of comment nodes + * @param {CommentEventGenerator} generator - A generator to emit. + * @param {ASTNode[]} comments - Collection of comment nodes + * @returns {void} + */ +function emitCommentsEnter(generator, comments) { + emitComments( + comments, + generator.emitter, + generator.commentLocsEnter, + "Comment"); +} + +/** + * Shortcut to check and emit exit of comment nodes + * @param {CommentEventGenerator} generator - A generator to emit. + * @param {ASTNode[]} comments Collection of comment nodes + * @returns {void} + */ +function emitCommentsExit(generator, comments) { + emitComments( + comments, + generator.emitter, + generator.commentLocsExit, + "Comment:exit"); +} + //------------------------------------------------------------------------------ // Public Interface //------------------------------------------------------------------------------ + /** - * Merges two objects together and assigns the result to the initial object. Can be used for shallow cloning. - * @param {Object} target of the cloning operation - * @param {Object} source object - * @returns {void} + * The event generator for comments. + * This is the decorator pattern. + * This generates events of comments before/after events which are generated the original generator. + * + * @param {EventGenerator} originalEventGenerator - An event generator which is the decoration target. + * @param {SourceCode} sourceCode - A source code which has comments. + * @returns {CommentEventGenerator} new instance. */ -exports.mixin = function(target, source) { - Object.keys(source).forEach(function(key) { - target[key] = source[key]; - }); +function CommentEventGenerator(originalEventGenerator, sourceCode) { + this.original = originalEventGenerator; + this.emitter = originalEventGenerator.emitter; + this.sourceCode = sourceCode; + this.commentLocsEnter = []; + this.commentLocsExit = []; +} + +CommentEventGenerator.prototype = { + constructor: CommentEventGenerator, + + /** + * Emits an event of entering comments. + * @param {ASTNode} node - A node which was entered. + * @returns {void} + */ + enterNode: function enterNode(node) { + var comments = this.sourceCode.getComments(node); + + emitCommentsEnter(this, comments.leading); + this.original.enterNode(node); + emitCommentsEnter(this, comments.trailing); + }, + + /** + * Emits an event of leaving comments. + * @param {ASTNode} node - A node which was left. + * @returns {void} + */ + leaveNode: function leaveNode(node) { + var comments = this.sourceCode.getComments(node); + + emitCommentsExit(this, comments.trailing); + this.original.leaveNode(node); + emitCommentsExit(this, comments.leading); + } }; +module.exports = CommentEventGenerator; + +},{}],312:[function(require,module,exports){ /** - * Merges two config objects. This will not only add missing keys, but will also modify values to match. - * @param {Object} base config object - * @param {Object} custom config object. Overrides in this config object will take priority over base. - * @returns {Object} merged config object. + * @fileoverview Patch for estraverse + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. */ -exports.mergeConfigs = function mergeConfigs(base, custom) { +"use strict"; - Object.keys(custom).forEach(function (key) { - var property = custom[key]; +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ - if (key === "plugins") { - if (!base[key]) { - base[key] = []; +var estraverse = require("estraverse"), + jsxKeys = require("estraverse-fb/keys"); + +//------------------------------------------------------------------------------ +// Helers +//------------------------------------------------------------------------------ + +var experimentalKeys = { + ExperimentalRestProperty: ["argument"], + ExperimentalSpreadProperty: ["argument"] +}; + +/** + * Adds a given keys to Syntax and VisitorKeys of estraverse. + * + * @param {object} keys - Key definitions to add. + * This is an object as map. + * Keys are the node type. + * Values are an array of property names to visit. + * @returns {void} + */ +function installKeys(keys) { + for (var key in keys) { + if (keys.hasOwnProperty(key)) { + estraverse.Syntax[key] = key; + if (keys[key]) { + estraverse.VisitorKeys[key] = keys[key]; } + } + } +} - property.forEach(function (plugin) { - // skip duplicates - if (base[key].indexOf(plugin) === -1) { - base[key].push(plugin); +// Add JSX node types. +installKeys(jsxKeys); +// Add Experimental node types. +installKeys(experimentalKeys); + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +module.exports = estraverse; + +},{"estraverse":89,"estraverse-fb/keys":88}],313:[function(require,module,exports){ +/** + * @fileoverview A shared list of ES3 keywords. + * @author Josh Perez + * @copyright 2015 Jose Roberto Vidal. All rights reserved. + */ +"use strict"; + +module.exports = [ + "abstract", + "boolean", + "break", + "byte", + "case", + "catch", + "char", + "class", + "const", + "continue", + "debugger", + "default", + "delete", + "do", + "double", + "else", + "enum", + "export", + "extends", + "false", + "final", + "finally", + "float", + "for", + "function", + "goto", + "if", + "implements", + "import", + "in", + "instanceof", + "int", + "interface", + "long", + "native", + "new", + "null", + "package", + "private", + "protected", + "public", + "return", + "short", + "static", + "super", + "switch", + "synchronized", + "this", + "throw", + "throws", + "transient", + "true", + "try", + "typeof", + "var", + "void", + "volatile", + "while", + "with" +]; + +},{}],314:[function(require,module,exports){ +/** + * @fileoverview The event generator for AST nodes. + * @author Toru Nagashima + * @copyright 2015 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +/** + * The event generator for AST nodes. + * This implements below interface. + * + * ```ts + * interface EventGenerator { + * emitter: EventEmitter; + * enterNode(node: ASTNode): void; + * leaveNode(node: ASTNode): void; + * } + * ``` + * + * @param {EventEmitter} emitter - An event emitter which is the destination of events. + * @returns {NodeEventGenerator} new instance. + */ +function NodeEventGenerator(emitter) { + this.emitter = emitter; +} + +NodeEventGenerator.prototype = { + constructor: NodeEventGenerator, + + /** + * Emits an event of entering AST node. + * @param {ASTNode} node - A node which was entered. + * @returns {void} + */ + enterNode: function enterNode(node) { + this.emitter.emit(node.type, node); + }, + + /** + * Emits an event of leaving AST node. + * @param {ASTNode} node - A node which was left. + * @returns {void} + */ + leaveNode: function leaveNode(node) { + this.emitter.emit(node.type + ":exit", node); + } +}; + +module.exports = NodeEventGenerator; + +},{}],315:[function(require,module,exports){ +/** + * @fileoverview An object that creates fix commands for rules. + * @author Nicholas C. Zakas + * @copyright 2015 Nicholas C. Zakas. All rights reserved. + * See LICENSE file in root directory for full license. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +// none! + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Creates a fix command that inserts text at the specified index in the source text. + * @param {int} index The 0-based index at which to insert the new text. + * @param {string} text The text to insert. + * @returns {Object} The fix command. + * @private + */ +function insertTextAt(index, text) { + return { + range: [index, index], + text: text + }; +} + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +/** + * Creates code fixing commands for rules. + * @constructor + */ +function RuleFixer() { + Object.freeze(this); +} + +RuleFixer.prototype = { + constructor: RuleFixer, + + /** + * Creates a fix command that inserts text after the given node or token. + * The fix is not applied until applyFixes() is called. + * @param {ASTNode|Token} nodeOrToken The node or token to insert after. + * @param {string} text The text to insert. + * @returns {Object} The fix command. + */ + insertTextAfter: function(nodeOrToken, text) { + return this.insertTextAfterRange(nodeOrToken.range, text); + }, + + /** + * Creates a fix command that inserts text after the specified range in the source text. + * The fix is not applied until applyFixes() is called. + * @param {int[]} range The range to replace, first item is start of range, second + * is end of range. + * @param {string} text The text to insert. + * @returns {Object} The fix command. + */ + insertTextAfterRange: function(range, text) { + return insertTextAt(range[1], text); + }, + + /** + * Creates a fix command that inserts text before the given node or token. + * The fix is not applied until applyFixes() is called. + * @param {ASTNode|Token} nodeOrToken The node or token to insert before. + * @param {string} text The text to insert. + * @returns {Object} The fix command. + */ + insertTextBefore: function(nodeOrToken, text) { + return this.insertTextBeforeRange(nodeOrToken.range, text); + }, + + /** + * Creates a fix command that inserts text before the specified range in the source text. + * The fix is not applied until applyFixes() is called. + * @param {int[]} range The range to replace, first item is start of range, second + * is end of range. + * @param {string} text The text to insert. + * @returns {Object} The fix command. + */ + insertTextBeforeRange: function(range, text) { + return insertTextAt(range[0], text); + }, + + /** + * Creates a fix command that replaces text at the node or token. + * The fix is not applied until applyFixes() is called. + * @param {ASTNode|Token} nodeOrToken The node or token to remove. + * @param {string} text The text to insert. + * @returns {Object} The fix command. + */ + replaceText: function(nodeOrToken, text) { + return this.replaceTextRange(nodeOrToken.range, text); + }, + + /** + * Creates a fix command that replaces text at the specified range in the source text. + * The fix is not applied until applyFixes() is called. + * @param {int[]} range The range to replace, first item is start of range, second + * is end of range. + * @param {string} text The text to insert. + * @returns {Object} The fix command. + */ + replaceTextRange: function(range, text) { + return { + range: range, + text: text + }; + }, + + /** + * Creates a fix command that removes the node or token from the source. + * The fix is not applied until applyFixes() is called. + * @param {ASTNode|Token} nodeOrToken The node or token to remove. + * @returns {Object} The fix command. + */ + remove: function(nodeOrToken) { + return this.removeRange(nodeOrToken.range); + }, + + /** + * Creates a fix command that removes the specified range of text from the source. + * The fix is not applied until applyFixes() is called. + * @param {int[]} range The range to remove, first item is start of range, second + * is end of range. + * @returns {Object} The fix command. + */ + removeRange: function(range) { + return { + range: range, + text: "" + }; + } + +}; + + +module.exports = RuleFixer; + +},{}],316:[function(require,module,exports){ +/** + * @fileoverview Abstraction of JavaScript source code. + * @author Nicholas C. Zakas + * @copyright 2015 Nicholas C. Zakas. All rights reserved. + * See LICENSE file in root directory for full license. + */ +"use strict"; +/* eslint no-underscore-dangle: 0*/ + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var createTokenStore = require("../token-store.js"), + estraverse = require("./estraverse"), + assign = require("object-assign"); + +//------------------------------------------------------------------------------ +// Private +//------------------------------------------------------------------------------ + +/** + * Validates that the given AST has the required information. + * @param {ASTNode} ast The Program node of the AST to check. + * @throws {Error} If the AST doesn't contain the correct information. + * @returns {void} + * @private + */ +function validate(ast) { + + if (!ast.tokens) { + throw new Error("AST is missing the tokens array."); + } + + if (!ast.comments) { + throw new Error("AST is missing the comments array."); + } + + if (!ast.loc) { + throw new Error("AST is missing location information."); + } + + if (!ast.range) { + throw new Error("AST is missing range information"); + } +} + +/** + * Finds a JSDoc comment node in an array of comment nodes. + * @param {ASTNode[]} comments The array of comment nodes to search. + * @param {int} line Line number to look around + * @returns {ASTNode} The node if found, null if not. + * @private + */ +function findJSDocComment(comments, line) { + + if (comments) { + for (var i = comments.length - 1; i >= 0; i--) { + if (comments[i].type === "Block" && comments[i].value.charAt(0) === "*") { + + if (line - comments[i].loc.end.line <= 1) { + return comments[i]; + } else { + break; } - }); - return; + } } + } - if (Array.isArray(base[key]) && !Array.isArray(property) && typeof property === "number") { - // assume that we are just overriding first attribute - base[key][0] = custom[key]; - return; - } + return null; +} - if (typeof property === "object" && !Array.isArray(property) && property !== null) { - // base[key] might not exist, so be careful with recursion here - base[key] = mergeConfigs(base[key] || {}, custom[key]); - } else { - base[key] = custom[key]; - } - }); +/** + * Check to see if its a ES6 export declaration + * @param {ASTNode} astNode - any node + * @returns {boolean} whether the given node represents a export declaration + * @private + */ +function looksLikeExport(astNode) { + return astNode.type === "ExportDefaultDeclaration" || astNode.type === "ExportNamedDeclaration" || + astNode.type === "ExportAllDeclaration" || astNode.type === "ExportSpecifier"; +} - return base; -}; +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + /** - * Removes the prefix `eslint-plugin-` from a plugin name. - * @param {string} pluginName The name of the plugin which may have the prefix. - * @returns {string} The name of the plugin without prefix. + * Represents parsed source code. + * @param {string} text The source code text. + * @param {ASTNode} ast The Program node of the AST representing the code. + * @constructor */ -exports.removePluginPrefix = function removePluginPrefix(pluginName) { - return pluginName.indexOf(PLUGIN_NAME_PREFIX) === 0 ? pluginName.substring(PLUGIN_NAME_PREFIX.length) : pluginName; +function SourceCode(text, ast) { + + validate(ast); + + /** + * The original text source code. + * @type string + */ + this.text = text; + + /** + * The parsed AST for the source code. + * @type ASTNode + */ + this.ast = ast; + + /** + * The source code split into lines according to ECMA-262 specification. + * This is done to avoid each rule needing to do so separately. + * @type string[] + */ + this.lines = text.split(/\r\n|\r|\n|\u2028|\u2029/g); + + this.tokensAndComments = ast.tokens.concat(ast.comments).sort(function(left, right) { + return left.range[0] - right.range[0]; + }); + + // create token store methods + var tokenStore = createTokenStore(ast.tokens); + Object.keys(tokenStore).forEach(function(methodName) { + this[methodName] = tokenStore[methodName]; + }, this); + + var tokensAndCommentsStore = createTokenStore(this.tokensAndComments); + this.getTokenOrCommentBefore = tokensAndCommentsStore.getTokenBefore; + this.getTokenOrCommentAfter = tokensAndCommentsStore.getTokenAfter; + + // don't allow modification of this object + Object.freeze(this); + Object.freeze(this.lines); +} + +SourceCode.prototype = { + constructor: SourceCode, + + /** + * Gets the source code for the given node. + * @param {ASTNode=} node The AST node to get the text for. + * @param {int=} beforeCount The number of characters before the node to retrieve. + * @param {int=} afterCount The number of characters after the node to retrieve. + * @returns {string} The text representing the AST node. + */ + getText: function(node, beforeCount, afterCount) { + if (node) { + return (this.text !== null) ? this.text.slice(Math.max(node.range[0] - (beforeCount || 0), 0), + node.range[1] + (afterCount || 0)) : null; + } else { + return this.text; + } + + }, + + /** + * Gets the entire source text split into an array of lines. + * @returns {Array} The source text as an array of lines. + */ + getLines: function() { + return this.lines; + }, + + /** + * Retrieves an array containing all comments in the source code. + * @returns {ASTNode[]} An array of comment nodes. + */ + getAllComments: function() { + return this.ast.comments; + }, + + /** + * Gets all comments for the given node. + * @param {ASTNode} node The AST node to get the comments for. + * @returns {Object} The list of comments indexed by their position. + * @public + */ + getComments: function(node) { + + var leadingComments = node.leadingComments || [], + trailingComments = node.trailingComments || []; + + /* + * espree adds a "comments" array on Program nodes rather than + * leadingComments/trailingComments. Comments are only left in the + * Program node comments array if there is no executable code. + */ + if (node.type === "Program") { + if (node.body.length === 0) { + leadingComments = node.comments; + } + } + + return { + leading: leadingComments, + trailing: trailingComments + }; + }, + + /** + * Retrieves the JSDoc comment for a given node. + * @param {ASTNode} node The AST node to get the comment for. + * @returns {ASTNode} The BlockComment node containing the JSDoc for the + * given node or null if not found. + * @public + */ + getJSDocComment: function(node) { + + var parent = node.parent, + line = node.loc.start.line; + + switch (node.type) { + case "FunctionDeclaration": + if (looksLikeExport(parent)) { + return findJSDocComment(parent.leadingComments, line); + } else { + return findJSDocComment(node.leadingComments, line); + } + break; + + case "ClassDeclaration": + return findJSDocComment(node.leadingComments, line); + + case "ClassExpression": + return findJSDocComment(parent.parent.leadingComments, line); + + case "ArrowFunctionExpression": + case "FunctionExpression": + + if (parent.type !== "CallExpression" && parent.type !== "NewExpression") { + while (parent && !parent.leadingComments && !/Function/.test(parent.type)) { + parent = parent.parent; + } + + return parent && (parent.type !== "FunctionDeclaration") ? findJSDocComment(parent.leadingComments, line) : null; + } + + // falls through + + default: + return null; + } + }, + + /** + * Gets the deepest node containing a range index. + * @param {int} index Range index of the desired node. + * @returns {ASTNode} The node if found or null if not found. + */ + getNodeByRangeIndex: function(index) { + var result = null; + + estraverse.traverse(this.ast, { + enter: function(node, parent) { + if (node.range[0] <= index && index < node.range[1]) { + result = assign({ parent: parent }, node); + } else { + this.skip(); + } + }, + leave: function(node) { + if (node === result) { + this.break(); + } + } + }); + + return result; + }, + + /** + * Determines if two tokens have at least one whitespace character + * between them. This completely disregards comments in making the + * determination, so comments count as zero-length substrings. + * @param {Token} first The token to check after. + * @param {Token} second The token to check before. + * @returns {boolean} True if there is only space between tokens, false + * if there is anything other than whitespace between tokens. + */ + isSpaceBetweenTokens: function(first, second) { + var text = this.text.slice(first.range[1], second.range[0]); + return /\s/.test(text.replace(/\/\*.*?\*\//g, "")); + } }; -exports.PLUGIN_NAME_PREFIX = PLUGIN_NAME_PREFIX; -},{}]},{},[132])(132) +module.exports = SourceCode; + +},{"../token-store.js":310,"./estraverse":312,"object-assign":108}]},{},[116])(116) }); \ No newline at end of file