2020-10-30 20:34:04 +00:00
// Copyright 2015-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
2015-01-14 01:04:21 +00:00
/*! blanket - v1.1.5 */
( function ( define ) {
/ *
Copyright ( C ) 2013 Ariya Hidayat < ariya . hidayat @ gmail . com >
Copyright ( C ) 2013 Thaddee Tyl < thaddee . tyl @ gmail . com >
Copyright ( C ) 2013 Mathias Bynens < mathias @ qiwi . be >
Copyright ( C ) 2012 Ariya Hidayat < ariya . hidayat @ gmail . com >
Copyright ( C ) 2012 Mathias Bynens < mathias @ qiwi . be >
Copyright ( C ) 2012 Joost - Wim Boekesteijn < joost - wim @ boekesteijn . nl >
Copyright ( C ) 2012 Kris Kowal < kris . kowal @ cixar . com >
Copyright ( C ) 2012 Yusuke Suzuki < utatane . tea @ gmail . com >
Copyright ( C ) 2012 Arpad Borsos < arpad . borsos @ googlemail . com >
Copyright ( C ) 2011 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 bitwise:true plusplus:true */
/ * g l o b a l e s p r i m a : t r u e , d e f i n e : t r u e , e x p o r t s : t r u e , w i n d o w : t r u e ,
throwErrorTolerant : true ,
throwError : true , generateStatement : true , peek : true ,
parseAssignmentExpression : true , parseBlock : true , parseExpression : true ,
parseFunctionDeclaration : true , parseFunctionExpression : true ,
parseFunctionSourceElements : true , parseVariableIdentifier : true ,
parseLeftHandSideExpression : true ,
parseUnaryExpression : true ,
parseStatement : true , parseSourceElement : true * /
( function ( root , factory ) {
'use strict' ;
// Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
// Rhino, and plain browser loading.
/* istanbul ignore next */
if ( typeof define === 'function' && define . amd ) {
define ( [ 'exports' ] , factory ) ;
} else if ( typeof exports !== 'undefined' ) {
factory ( exports ) ;
} else {
factory ( ( root . esprima = { } ) ) ;
}
} ( this , function ( exports ) {
'use strict' ;
var Token ,
TokenName ,
FnExprTokens ,
Syntax ,
PropertyKind ,
Messages ,
Regex ,
SyntaxTreeDelegate ,
source ,
strict ,
index ,
lineNumber ,
lineStart ,
length ,
delegate ,
lookahead ,
state ,
extra ;
Token = {
BooleanLiteral : 1 ,
EOF : 2 ,
Identifier : 3 ,
Keyword : 4 ,
NullLiteral : 5 ,
NumericLiteral : 6 ,
Punctuator : 7 ,
StringLiteral : 8 ,
RegularExpression : 9
} ;
TokenName = { } ;
TokenName [ Token . BooleanLiteral ] = 'Boolean' ;
TokenName [ Token . EOF ] = '<end>' ;
TokenName [ Token . Identifier ] = 'Identifier' ;
TokenName [ Token . Keyword ] = 'Keyword' ;
TokenName [ Token . NullLiteral ] = 'Null' ;
TokenName [ Token . NumericLiteral ] = 'Numeric' ;
TokenName [ Token . Punctuator ] = 'Punctuator' ;
TokenName [ Token . StringLiteral ] = 'String' ;
TokenName [ Token . RegularExpression ] = 'RegularExpression' ;
// A function following one of those tokens is an expression.
FnExprTokens = [ '(' , '{' , '[' , 'in' , 'typeof' , 'instanceof' , 'new' ,
'return' , 'case' , 'delete' , 'throw' , 'void' ,
// assignment operators
'=' , '+=' , '-=' , '*=' , '/=' , '%=' , '<<=' , '>>=' , '>>>=' ,
'&=' , '|=' , '^=' , ',' ,
// binary/unary operators
'+' , '-' , '*' , '/' , '%' , '++' , '--' , '<<' , '>>' , '>>>' , '&' ,
'|' , '^' , '!' , '~' , '&&' , '||' , '?' , ':' , '===' , '==' , '>=' ,
'<=' , '<' , '>' , '!=' , '!==' ] ;
Syntax = {
AssignmentExpression : 'AssignmentExpression' ,
ArrayExpression : 'ArrayExpression' ,
BlockStatement : 'BlockStatement' ,
BinaryExpression : 'BinaryExpression' ,
BreakStatement : 'BreakStatement' ,
CallExpression : 'CallExpression' ,
CatchClause : 'CatchClause' ,
ConditionalExpression : 'ConditionalExpression' ,
ContinueStatement : 'ContinueStatement' ,
DoWhileStatement : 'DoWhileStatement' ,
DebuggerStatement : 'DebuggerStatement' ,
EmptyStatement : 'EmptyStatement' ,
ExpressionStatement : 'ExpressionStatement' ,
ForStatement : 'ForStatement' ,
ForInStatement : 'ForInStatement' ,
FunctionDeclaration : 'FunctionDeclaration' ,
FunctionExpression : 'FunctionExpression' ,
Identifier : 'Identifier' ,
IfStatement : 'IfStatement' ,
Literal : 'Literal' ,
LabeledStatement : 'LabeledStatement' ,
LogicalExpression : 'LogicalExpression' ,
MemberExpression : 'MemberExpression' ,
NewExpression : 'NewExpression' ,
ObjectExpression : 'ObjectExpression' ,
Program : 'Program' ,
Property : 'Property' ,
ReturnStatement : 'ReturnStatement' ,
SequenceExpression : 'SequenceExpression' ,
SwitchStatement : 'SwitchStatement' ,
SwitchCase : 'SwitchCase' ,
ThisExpression : 'ThisExpression' ,
ThrowStatement : 'ThrowStatement' ,
TryStatement : 'TryStatement' ,
UnaryExpression : 'UnaryExpression' ,
UpdateExpression : 'UpdateExpression' ,
VariableDeclaration : 'VariableDeclaration' ,
VariableDeclarator : 'VariableDeclarator' ,
WhileStatement : 'WhileStatement' ,
WithStatement : 'WithStatement'
} ;
PropertyKind = {
Data : 1 ,
Get : 2 ,
Set : 4
} ;
// Error messages should be identical to V8.
Messages = {
UnexpectedToken : 'Unexpected token %0' ,
UnexpectedNumber : 'Unexpected number' ,
UnexpectedString : 'Unexpected string' ,
UnexpectedIdentifier : 'Unexpected identifier' ,
UnexpectedReserved : 'Unexpected reserved word' ,
UnexpectedEOS : 'Unexpected end of input' ,
NewlineAfterThrow : 'Illegal newline after throw' ,
InvalidRegExp : 'Invalid regular expression' ,
UnterminatedRegExp : 'Invalid regular expression: missing /' ,
InvalidLHSInAssignment : 'Invalid left-hand side in assignment' ,
InvalidLHSInForIn : 'Invalid left-hand side in for-in' ,
MultipleDefaultsInSwitch : 'More than one default clause in switch statement' ,
NoCatchOrFinally : 'Missing catch or finally after try' ,
UnknownLabel : 'Undefined label \'%0\'' ,
Redeclaration : '%0 \'%1\' has already been declared' ,
IllegalContinue : 'Illegal continue statement' ,
IllegalBreak : 'Illegal break statement' ,
IllegalReturn : 'Illegal return statement' ,
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' ,
StrictFunctionName : 'Function name may not be eval or arguments in strict mode' ,
StrictOctalLiteral : 'Octal literals are not allowed in strict mode.' ,
StrictDelete : 'Delete of an unqualified identifier in strict mode.' ,
StrictDuplicateProperty : 'Duplicate data property in object literal not allowed in strict mode' ,
AccessorDataProperty : 'Object literal may not have data and accessor property with the same name' ,
AccessorGetSet : 'Object literal may not have multiple get/set accessors with the same name' ,
StrictLHSAssignment : 'Assignment to eval or arguments is not allowed in strict mode' ,
StrictLHSPostfix : 'Postfix increment/decrement may not have eval or arguments operand in strict mode' ,
StrictLHSPrefix : 'Prefix increment/decrement may not have eval or arguments operand in strict mode' ,
StrictReservedWord : 'Use of future reserved word in strict mode'
} ;
// See also tools/generate-unicode-regex.py.
Regex = {
NonAsciiIdentifierStart : new RegExp ( ' [ \ 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 - \ u
NonAsciiIdentifierPart : new RegExp ( ' [ \ xAA \ xB5 \ xBA \ xC0 - \ xD6 \ xD8 - \ xF6 \ xF8 - \u02C1\u02C6 - \u02D1\u02E0 - \u02E4\u02EC\u02EE\u0300 - \u0374\u0376\u0377\u037A - \u037D\u0386\u0388 - \u038A\u038C\u038E - \u03A1\u03A3 - \u03F5\u03F7 - \u0481\u0483 - \u0487\u048A - \u0527\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\u08A2 - \u08AC\u08E4 - \u08FE\u0900 - \u0963\u0966 - \u096F\u0971 - \u0977\u0979 - \u097F\u0981 - \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\u0C01 - \u0C03\u0C05 - \u0C0C\u0C0E - \u0C10\u0C12 - \u0C28\u0C2A - \u0C33\u0C35 - \u0C39\u0C3D - \u0C44\u0C46 - \u0C48\u0C4A - \u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60 - \u0C63\u0C66 - \u0C6F\u0C82\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\u0D02\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\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 - \u16F0\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 - \u191C\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\u1B00 - \u1B4B\u1B50 - \u1B59\u1B6B - \u1B73\u1B80 - \u1BF3\u1C00 - \u1C37\u1C40 - \u1C49\u1C4D - \u1C7D\u1CD0 - \u1CD2\u1CD4 - \u1CF6\u1D00 - \u1DE6\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 \ u
} ;
// Ensure the condition is true, otherwise throw an error.
// This is only to have a better contract semantic, i.e. another safety net
// to catch a logic error. The condition shall be fulfilled in normal case.
// Do NOT use this to enforce a certain condition on any user input.
function assert ( condition , message ) {
/* istanbul ignore if */
if ( ! condition ) {
throw new Error ( 'ASSERT: ' + message ) ;
}
}
function isDecimalDigit ( ch ) {
return ( ch >= 48 && ch <= 57 ) ; // 0..9
}
function isHexDigit ( ch ) {
return '0123456789abcdefABCDEF' . indexOf ( ch ) >= 0 ;
}
function isOctalDigit ( ch ) {
return '01234567' . indexOf ( ch ) >= 0 ;
}
// 7.2 White Space
function isWhiteSpace ( ch ) {
return ( ch === 0x20 ) || ( ch === 0x09 ) || ( ch === 0x0B ) || ( ch === 0x0C ) || ( ch === 0xA0 ) ||
( ch >= 0x1680 && [ 0x1680 , 0x180E , 0x2000 , 0x2001 , 0x2002 , 0x2003 , 0x2004 , 0x2005 , 0x2006 , 0x2007 , 0x2008 , 0x2009 , 0x200A , 0x202F , 0x205F , 0x3000 , 0xFEFF ] . 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 isIdentifierStart ( ch ) {
return ( ch === 0x24 ) || ( ch === 0x5F ) || // $ (dollar) and _ (underscore)
( ch >= 0x41 && ch <= 0x5A ) || // A..Z
( ch >= 0x61 && ch <= 0x7A ) || // a..z
( ch === 0x5C ) || // \ (backslash)
( ( ch >= 0x80 ) && Regex . NonAsciiIdentifierStart . test ( String . fromCharCode ( ch ) ) ) ;
}
function isIdentifierPart ( ch ) {
return ( ch === 0x24 ) || ( ch === 0x5F ) || // $ (dollar) and _ (underscore)
( ch >= 0x41 && ch <= 0x5A ) || // A..Z
( ch >= 0x61 && ch <= 0x7A ) || // a..z
( ch >= 0x30 && ch <= 0x39 ) || // 0..9
( ch === 0x5C ) || // \ (backslash)
( ( ch >= 0x80 ) && Regex . NonAsciiIdentifierPart . test ( String . fromCharCode ( ch ) ) ) ;
}
// 7.6.1.2 Future Reserved Words
function isFutureReservedWord ( id ) {
switch ( id ) {
case 'class' :
case 'enum' :
case 'export' :
case 'extends' :
case 'import' :
case 'super' :
return true ;
default :
return false ;
}
}
function isStrictModeReservedWord ( id ) {
switch ( id ) {
case 'implements' :
case 'interface' :
case 'package' :
case 'private' :
case 'protected' :
case 'public' :
case 'static' :
case 'yield' :
case 'let' :
return true ;
default :
return false ;
}
}
function isRestrictedWord ( id ) {
return id === 'eval' || id === 'arguments' ;
}
// 7.6.1.1 Keywords
function isKeyword ( id ) {
if ( strict && isStrictModeReservedWord ( id ) ) {
return true ;
}
// 'const' is specialized as Keyword in V8.
// 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next.
// Some others are from future reserved words.
switch ( id . length ) {
case 2 :
return ( id === 'if' ) || ( id === 'in' ) || ( id === 'do' ) ;
case 3 :
return ( id === 'var' ) || ( id === 'for' ) || ( id === 'new' ) ||
( id === 'try' ) || ( id === 'let' ) ;
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 ;
}
}
// 7.4 Comments
function addComment ( type , value , start , end , loc ) {
var comment , attacher ;
assert ( typeof start === 'number' , 'Comment must have valid position' ) ;
// Because the way the actual token is scanned, often the comments
// (if any) are skipped twice during the lexical analysis.
// Thus, we need to skip adding a comment if the comment array already
// handled it.
if ( state . lastCommentStart >= start ) {
return ;
}
state . lastCommentStart = start ;
comment = {
type : type ,
value : value
} ;
if ( extra . range ) {
comment . range = [ start , end ] ;
}
if ( extra . loc ) {
comment . loc = loc ;
}
extra . comments . push ( comment ) ;
if ( extra . attachComment ) {
extra . leadingComments . push ( comment ) ;
extra . trailingComments . push ( comment ) ;
}
}
function skipSingleLineComment ( offset ) {
var start , loc , ch , comment ;
start = index - offset ;
loc = {
start : {
line : lineNumber ,
column : index - lineStart - offset
}
} ;
while ( index < length ) {
ch = source . charCodeAt ( index ) ;
++ index ;
if ( isLineTerminator ( ch ) ) {
if ( extra . comments ) {
comment = source . slice ( start + offset , index - 1 ) ;
loc . end = {
line : lineNumber ,
column : index - lineStart - 1
} ;
addComment ( 'Line' , comment , start , index - 1 , loc ) ;
}
if ( ch === 13 && source . charCodeAt ( index ) === 10 ) {
++ index ;
}
++ lineNumber ;
lineStart = index ;
return ;
}
}
if ( extra . comments ) {
comment = source . slice ( start + offset , index ) ;
loc . end = {
line : lineNumber ,
column : index - lineStart
} ;
addComment ( 'Line' , comment , start , index , loc ) ;
}
}
function skipMultiLineComment ( ) {
var start , loc , ch , comment ;
if ( extra . comments ) {
start = index - 2 ;
loc = {
start : {
line : lineNumber ,
column : index - lineStart - 2
}
} ;
}
while ( index < length ) {
ch = source . charCodeAt ( index ) ;
if ( isLineTerminator ( ch ) ) {
if ( ch === 0x0D && source . charCodeAt ( index + 1 ) === 0x0A ) {
++ index ;
}
++ lineNumber ;
++ index ;
lineStart = index ;
if ( index >= length ) {
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
} else if ( ch === 0x2A ) {
// Block comment ends with '*/'.
if ( source . charCodeAt ( index + 1 ) === 0x2F ) {
++ index ;
++ index ;
if ( extra . comments ) {
comment = source . slice ( start + 2 , index - 2 ) ;
loc . end = {
line : lineNumber ,
column : index - lineStart
} ;
addComment ( 'Block' , comment , start , index , loc ) ;
}
return ;
}
++ index ;
} else {
++ index ;
}
}
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
function skipComment ( ) {
var ch , start ;
start = ( index === 0 ) ;
while ( index < length ) {
ch = source . charCodeAt ( index ) ;
if ( isWhiteSpace ( ch ) ) {
++ index ;
} else if ( isLineTerminator ( ch ) ) {
++ index ;
if ( ch === 0x0D && source . charCodeAt ( index ) === 0x0A ) {
++ index ;
}
++ lineNumber ;
lineStart = index ;
start = true ;
} else if ( ch === 0x2F ) { // U+002F is '/'
ch = source . charCodeAt ( index + 1 ) ;
if ( ch === 0x2F ) {
++ index ;
++ index ;
skipSingleLineComment ( 2 ) ;
start = true ;
} else if ( ch === 0x2A ) { // U+002A is '*'
++ index ;
++ index ;
skipMultiLineComment ( ) ;
} else {
break ;
}
} else if ( start && ch === 0x2D ) { // U+002D is '-'
// U+003E is '>'
if ( ( source . charCodeAt ( index + 1 ) === 0x2D ) && ( source . charCodeAt ( index + 2 ) === 0x3E ) ) {
// '-->' is a single-line comment
index += 3 ;
skipSingleLineComment ( 3 ) ;
} else {
break ;
}
} else if ( ch === 0x3C ) { // U+003C is '<'
if ( source . slice ( index + 1 , index + 4 ) === '!--' ) {
++ index ; // `<`
++ index ; // `!`
++ index ; // `-`
++ index ; // `-`
skipSingleLineComment ( 4 ) ;
} else {
break ;
}
} else {
break ;
}
}
}
function scanHexEscape ( prefix ) {
var i , len , ch , code = 0 ;
len = ( prefix === 'u' ) ? 4 : 2 ;
for ( i = 0 ; i < len ; ++ i ) {
if ( index < length && isHexDigit ( source [ index ] ) ) {
ch = source [ index ++ ] ;
code = code * 16 + '0123456789abcdef' . indexOf ( ch . toLowerCase ( ) ) ;
} else {
return '' ;
}
}
return String . fromCharCode ( code ) ;
}
function getEscapedIdentifier ( ) {
var ch , id ;
ch = source . charCodeAt ( index ++ ) ;
id = String . fromCharCode ( ch ) ;
// '\u' (U+005C, U+0075) denotes an escaped character.
if ( ch === 0x5C ) {
if ( source . charCodeAt ( index ) !== 0x75 ) {
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
++ index ;
ch = scanHexEscape ( 'u' ) ;
if ( ! ch || ch === '\\' || ! isIdentifierStart ( ch . charCodeAt ( 0 ) ) ) {
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
id = ch ;
}
while ( index < length ) {
ch = source . charCodeAt ( index ) ;
if ( ! isIdentifierPart ( ch ) ) {
break ;
}
++ index ;
id += String . fromCharCode ( ch ) ;
// '\u' (U+005C, U+0075) denotes an escaped character.
if ( ch === 0x5C ) {
id = id . substr ( 0 , id . length - 1 ) ;
if ( source . charCodeAt ( index ) !== 0x75 ) {
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
++ index ;
ch = scanHexEscape ( 'u' ) ;
if ( ! ch || ch === '\\' || ! isIdentifierPart ( ch . charCodeAt ( 0 ) ) ) {
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
id += ch ;
}
}
return id ;
}
function getIdentifier ( ) {
var start , ch ;
start = index ++ ;
while ( index < length ) {
ch = source . charCodeAt ( index ) ;
if ( ch === 0x5C ) {
// Blackslash (U+005C) marks Unicode escape sequence.
index = start ;
return getEscapedIdentifier ( ) ;
}
if ( isIdentifierPart ( ch ) ) {
++ index ;
} else {
break ;
}
}
return source . slice ( start , index ) ;
}
function scanIdentifier ( ) {
var start , id , type ;
start = index ;
// Backslash (U+005C) starts an escaped character.
id = ( source . charCodeAt ( index ) === 0x5C ) ? getEscapedIdentifier ( ) : getIdentifier ( ) ;
// There is no keyword or literal with only one character.
// Thus, it must be an identifier.
if ( id . length === 1 ) {
type = Token . Identifier ;
} else if ( isKeyword ( id ) ) {
type = Token . Keyword ;
} else if ( id === 'null' ) {
type = Token . NullLiteral ;
} else if ( id === 'true' || id === 'false' ) {
type = Token . BooleanLiteral ;
} else {
type = Token . Identifier ;
}
return {
type : type ,
value : id ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
}
// 7.7 Punctuators
function scanPunctuator ( ) {
var start = index ,
code = source . charCodeAt ( index ) ,
code2 ,
ch1 = source [ index ] ,
ch2 ,
ch3 ,
ch4 ;
switch ( code ) {
// Check for most common single-character punctuators.
case 0x2E : // . dot
case 0x28 : // ( open bracket
case 0x29 : // ) close bracket
case 0x3B : // ; semicolon
case 0x2C : // , comma
case 0x7B : // { open curly brace
case 0x7D : // } close curly brace
case 0x5B : // [
case 0x5D : // ]
case 0x3A : // :
case 0x3F : // ?
case 0x7E : // ~
++ index ;
if ( extra . tokenize ) {
if ( code === 0x28 ) {
extra . openParenToken = extra . tokens . length ;
} else if ( code === 0x7B ) {
extra . openCurlyToken = extra . tokens . length ;
}
}
return {
type : Token . Punctuator ,
value : String . fromCharCode ( code ) ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
default :
code2 = source . charCodeAt ( index + 1 ) ;
// '=' (U+003D) marks an assignment or comparison operator.
if ( code2 === 0x3D ) {
switch ( code ) {
case 0x2B : // +
case 0x2D : // -
case 0x2F : // /
case 0x3C : // <
case 0x3E : // >
case 0x5E : // ^
case 0x7C : // |
case 0x25 : // %
case 0x26 : // &
case 0x2A : // *
index += 2 ;
return {
type : Token . Punctuator ,
value : String . fromCharCode ( code ) + String . fromCharCode ( code2 ) ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
case 0x21 : // !
case 0x3D : // =
index += 2 ;
// !== and ===
if ( source . charCodeAt ( index ) === 0x3D ) {
++ index ;
}
return {
type : Token . Punctuator ,
value : source . slice ( start , index ) ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
}
}
}
// 4-character punctuator: >>>=
ch4 = source . substr ( index , 4 ) ;
if ( ch4 === '>>>=' ) {
index += 4 ;
return {
type : Token . Punctuator ,
value : ch4 ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
}
// 3-character punctuators: === !== >>> <<= >>=
ch3 = ch4 . substr ( 0 , 3 ) ;
if ( ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=' ) {
index += 3 ;
return {
type : Token . Punctuator ,
value : ch3 ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
}
// Other 2-character punctuators: ++ -- << >> && ||
ch2 = ch3 . substr ( 0 , 2 ) ;
if ( ( ch1 === ch2 [ 1 ] && ( '+-<>&|' . indexOf ( ch1 ) >= 0 ) ) || ch2 === '=>' ) {
index += 2 ;
return {
type : Token . Punctuator ,
value : ch2 ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
}
// 1-character punctuators: < > = ! + - * % & | ^ /
if ( '<>=!+-*%&|^/' . indexOf ( ch1 ) >= 0 ) {
++ index ;
return {
type : Token . Punctuator ,
value : ch1 ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
}
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
// 7.8.3 Numeric Literals
function scanHexLiteral ( start ) {
var number = '' ;
while ( index < length ) {
if ( ! isHexDigit ( source [ index ] ) ) {
break ;
}
number += source [ index ++ ] ;
}
if ( number . length === 0 ) {
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
if ( isIdentifierStart ( source . charCodeAt ( index ) ) ) {
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
return {
type : Token . NumericLiteral ,
value : parseInt ( '0x' + number , 16 ) ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
}
function scanOctalLiteral ( start ) {
var number = '0' + source [ index ++ ] ;
while ( index < length ) {
if ( ! isOctalDigit ( source [ index ] ) ) {
break ;
}
number += source [ index ++ ] ;
}
if ( isIdentifierStart ( source . charCodeAt ( index ) ) || isDecimalDigit ( source . charCodeAt ( index ) ) ) {
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
return {
type : Token . NumericLiteral ,
value : parseInt ( number , 8 ) ,
octal : true ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
}
function scanNumericLiteral ( ) {
var number , start , ch ;
ch = source [ index ] ;
assert ( isDecimalDigit ( ch . charCodeAt ( 0 ) ) || ( ch === '.' ) ,
'Numeric literal must start with a decimal digit or a decimal point' ) ;
start = index ;
number = '' ;
if ( ch !== '.' ) {
number = source [ index ++ ] ;
ch = source [ index ] ;
// Hex number starts with '0x'.
// Octal number starts with '0'.
if ( number === '0' ) {
if ( ch === 'x' || ch === 'X' ) {
++ index ;
return scanHexLiteral ( start ) ;
}
if ( isOctalDigit ( ch ) ) {
return scanOctalLiteral ( start ) ;
}
// decimal number starts with '0' such as '09' is illegal.
if ( ch && isDecimalDigit ( ch . charCodeAt ( 0 ) ) ) {
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
}
while ( isDecimalDigit ( source . charCodeAt ( index ) ) ) {
number += source [ index ++ ] ;
}
ch = source [ index ] ;
}
if ( ch === '.' ) {
number += source [ index ++ ] ;
while ( isDecimalDigit ( source . charCodeAt ( index ) ) ) {
number += source [ index ++ ] ;
}
ch = source [ index ] ;
}
if ( ch === 'e' || ch === 'E' ) {
number += source [ index ++ ] ;
ch = source [ index ] ;
if ( ch === '+' || ch === '-' ) {
number += source [ index ++ ] ;
}
if ( isDecimalDigit ( source . charCodeAt ( index ) ) ) {
while ( isDecimalDigit ( source . charCodeAt ( index ) ) ) {
number += source [ index ++ ] ;
}
} else {
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
}
if ( isIdentifierStart ( source . charCodeAt ( index ) ) ) {
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
return {
type : Token . NumericLiteral ,
value : parseFloat ( number ) ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
}
// 7.8.4 String Literals
function scanStringLiteral ( ) {
var str = '' , quote , start , ch , code , unescaped , restore , octal = false , startLineNumber , startLineStart ;
startLineNumber = lineNumber ;
startLineStart = lineStart ;
quote = source [ index ] ;
assert ( ( quote === '\'' || quote === '"' ) ,
'String literal must starts with a quote' ) ;
start = index ;
++ index ;
while ( index < length ) {
ch = source [ index ++ ] ;
if ( ch === quote ) {
quote = '' ;
break ;
} else if ( ch === '\\' ) {
ch = source [ index ++ ] ;
if ( ! ch || ! isLineTerminator ( ch . charCodeAt ( 0 ) ) ) {
switch ( ch ) {
case 'u' :
case 'x' :
restore = index ;
unescaped = scanHexEscape ( ch ) ;
if ( unescaped ) {
str += unescaped ;
} else {
index = restore ;
str += ch ;
}
break ;
case 'n' :
str += '\n' ;
break ;
case 'r' :
str += '\r' ;
break ;
case 't' :
str += '\t' ;
break ;
case 'b' :
str += '\b' ;
break ;
case 'f' :
str += '\f' ;
break ;
case 'v' :
str += '\x0B' ;
break ;
default :
if ( isOctalDigit ( ch ) ) {
code = '01234567' . indexOf ( ch ) ;
// \0 is not octal escape sequence
if ( code !== 0 ) {
octal = true ;
}
if ( index < length && isOctalDigit ( source [ index ] ) ) {
octal = true ;
code = code * 8 + '01234567' . indexOf ( source [ index ++ ] ) ;
// 3 digits are only allowed when string starts
// with 0, 1, 2, 3
if ( '0123' . indexOf ( ch ) >= 0 &&
index < length &&
isOctalDigit ( source [ index ] ) ) {
code = code * 8 + '01234567' . indexOf ( source [ index ++ ] ) ;
}
}
str += String . fromCharCode ( code ) ;
} else {
str += ch ;
}
break ;
}
} else {
++ lineNumber ;
if ( ch === '\r' && source [ index ] === '\n' ) {
++ index ;
}
lineStart = index ;
}
} else if ( isLineTerminator ( ch . charCodeAt ( 0 ) ) ) {
break ;
} else {
str += ch ;
}
}
if ( quote !== '' ) {
throwError ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
return {
type : Token . StringLiteral ,
value : str ,
octal : octal ,
startLineNumber : startLineNumber ,
startLineStart : startLineStart ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
}
function testRegExp ( pattern , flags ) {
var value ;
try {
value = new RegExp ( pattern , flags ) ;
} catch ( e ) {
throwError ( { } , Messages . InvalidRegExp ) ;
}
return value ;
}
function scanRegExpBody ( ) {
var ch , str , classMarker , terminated , body ;
ch = source [ index ] ;
assert ( ch === '/' , 'Regular expression literal must start with a slash' ) ;
str = source [ index ++ ] ;
classMarker = false ;
terminated = false ;
while ( index < length ) {
ch = source [ index ++ ] ;
str += ch ;
if ( ch === '\\' ) {
ch = source [ index ++ ] ;
// ECMA-262 7.8.5
if ( isLineTerminator ( ch . charCodeAt ( 0 ) ) ) {
throwError ( { } , Messages . UnterminatedRegExp ) ;
}
str += ch ;
} else if ( isLineTerminator ( ch . charCodeAt ( 0 ) ) ) {
throwError ( { } , Messages . UnterminatedRegExp ) ;
} else if ( classMarker ) {
if ( ch === ']' ) {
classMarker = false ;
}
} else {
if ( ch === '/' ) {
terminated = true ;
break ;
} else if ( ch === '[' ) {
classMarker = true ;
}
}
}
if ( ! terminated ) {
throwError ( { } , Messages . UnterminatedRegExp ) ;
}
// Exclude leading and trailing slash.
body = str . substr ( 1 , str . length - 2 ) ;
return {
value : body ,
literal : str
} ;
}
function scanRegExpFlags ( ) {
var ch , str , flags , restore ;
str = '' ;
flags = '' ;
while ( index < length ) {
ch = source [ index ] ;
if ( ! isIdentifierPart ( ch . charCodeAt ( 0 ) ) ) {
break ;
}
++ index ;
if ( ch === '\\' && index < length ) {
ch = source [ index ] ;
if ( ch === 'u' ) {
++ index ;
restore = index ;
ch = scanHexEscape ( 'u' ) ;
if ( ch ) {
flags += ch ;
for ( str += '\\u' ; restore < index ; ++ restore ) {
str += source [ restore ] ;
}
} else {
index = restore ;
flags += 'u' ;
str += '\\u' ;
}
throwErrorTolerant ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
} else {
str += '\\' ;
throwErrorTolerant ( { } , Messages . UnexpectedToken , 'ILLEGAL' ) ;
}
} else {
flags += ch ;
str += ch ;
}
}
return {
value : flags ,
literal : str
} ;
}
function scanRegExp ( ) {
var start , body , flags , pattern , value ;
lookahead = null ;
skipComment ( ) ;
start = index ;
body = scanRegExpBody ( ) ;
flags = scanRegExpFlags ( ) ;
value = testRegExp ( body . value , flags . value ) ;
if ( extra . tokenize ) {
return {
type : Token . RegularExpression ,
value : value ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : start ,
end : index
} ;
}
return {
literal : body . literal + flags . literal ,
value : value ,
start : start ,
end : index
} ;
}
function collectRegex ( ) {
var pos , loc , regex , token ;
skipComment ( ) ;
pos = index ;
loc = {
start : {
line : lineNumber ,
column : index - lineStart
}
} ;
regex = scanRegExp ( ) ;
loc . end = {
line : lineNumber ,
column : index - lineStart
} ;
/* istanbul ignore next */
if ( ! extra . tokenize ) {
// Pop the previous token, which is likely '/' or '/='
if ( extra . tokens . length > 0 ) {
token = extra . tokens [ extra . tokens . length - 1 ] ;
if ( token . range [ 0 ] === pos && token . type === 'Punctuator' ) {
if ( token . value === '/' || token . value === '/=' ) {
extra . tokens . pop ( ) ;
}
}
}
extra . tokens . push ( {
type : 'RegularExpression' ,
value : regex . literal ,
range : [ pos , index ] ,
loc : loc
} ) ;
}
return regex ;
}
function isIdentifierName ( token ) {
return token . type === Token . Identifier ||
token . type === Token . Keyword ||
token . type === Token . BooleanLiteral ||
token . type === Token . NullLiteral ;
}
function advanceSlash ( ) {
var prevToken ,
checkToken ;
// Using the following algorithm:
// https://github.com/mozilla/sweet.js/wiki/design
prevToken = extra . tokens [ extra . tokens . length - 1 ] ;
if ( ! prevToken ) {
// Nothing before that: it cannot be a division.
return collectRegex ( ) ;
}
if ( prevToken . type === 'Punctuator' ) {
if ( prevToken . value === ']' ) {
return scanPunctuator ( ) ;
}
if ( prevToken . value === ')' ) {
checkToken = extra . tokens [ extra . openParenToken - 1 ] ;
if ( checkToken &&
checkToken . type === 'Keyword' &&
( checkToken . value === 'if' ||
checkToken . value === 'while' ||
checkToken . value === 'for' ||
checkToken . value === 'with' ) ) {
return collectRegex ( ) ;
}
return scanPunctuator ( ) ;
}
if ( prevToken . value === '}' ) {
// Dividing a function by anything makes little sense,
// but we have to check for that.
if ( extra . tokens [ extra . openCurlyToken - 3 ] &&
extra . tokens [ extra . openCurlyToken - 3 ] . type === 'Keyword' ) {
// Anonymous function.
checkToken = extra . tokens [ extra . openCurlyToken - 4 ] ;
if ( ! checkToken ) {
return scanPunctuator ( ) ;
}
} else if ( extra . tokens [ extra . openCurlyToken - 4 ] &&
extra . tokens [ extra . openCurlyToken - 4 ] . type === 'Keyword' ) {
// Named function.
checkToken = extra . tokens [ extra . openCurlyToken - 5 ] ;
if ( ! checkToken ) {
return collectRegex ( ) ;
}
} else {
return scanPunctuator ( ) ;
}
// checkToken determines whether the function is
// a declaration or an expression.
if ( FnExprTokens . indexOf ( checkToken . value ) >= 0 ) {
// It is an expression.
return scanPunctuator ( ) ;
}
// It is a declaration.
return collectRegex ( ) ;
}
return collectRegex ( ) ;
}
if ( prevToken . type === 'Keyword' ) {
return collectRegex ( ) ;
}
return scanPunctuator ( ) ;
}
function advance ( ) {
var ch ;
skipComment ( ) ;
if ( index >= length ) {
return {
type : Token . EOF ,
lineNumber : lineNumber ,
lineStart : lineStart ,
start : index ,
end : index
} ;
}
ch = source . charCodeAt ( index ) ;
if ( isIdentifierStart ( ch ) ) {
return scanIdentifier ( ) ;
}
// Very common: ( and ) and ;
if ( ch === 0x28 || ch === 0x29 || ch === 0x3B ) {
return scanPunctuator ( ) ;
}
// String literal starts with single quote (U+0027) or double quote (U+0022).
if ( ch === 0x27 || ch === 0x22 ) {
return scanStringLiteral ( ) ;
}
// Dot (.) U+002E can also start a floating-point number, hence the need
// to check the next character.
if ( ch === 0x2E ) {
if ( isDecimalDigit ( source . charCodeAt ( index + 1 ) ) ) {
return scanNumericLiteral ( ) ;
}
return scanPunctuator ( ) ;
}
if ( isDecimalDigit ( ch ) ) {
return scanNumericLiteral ( ) ;
}
// Slash (/) U+002F can also start a regex.
if ( extra . tokenize && ch === 0x2F ) {
return advanceSlash ( ) ;
}
return scanPunctuator ( ) ;
}
function collectToken ( ) {
var loc , token , range , value ;
skipComment ( ) ;
loc = {
start : {
line : lineNumber ,
column : index - lineStart
}
} ;
token = advance ( ) ;
loc . end = {
line : lineNumber ,
column : index - lineStart
} ;
if ( token . type !== Token . EOF ) {
value = source . slice ( token . start , token . end ) ;
extra . tokens . push ( {
type : TokenName [ token . type ] ,
value : value ,
range : [ token . start , token . end ] ,
loc : loc
} ) ;
}
return token ;
}
function lex ( ) {
var token ;
token = lookahead ;
index = token . end ;
lineNumber = token . lineNumber ;
lineStart = token . lineStart ;
lookahead = ( typeof extra . tokens !== 'undefined' ) ? collectToken ( ) : advance ( ) ;
index = token . end ;
lineNumber = token . lineNumber ;
lineStart = token . lineStart ;
return token ;
}
function peek ( ) {
var pos , line , start ;
pos = index ;
line = lineNumber ;
start = lineStart ;
lookahead = ( typeof extra . tokens !== 'undefined' ) ? collectToken ( ) : advance ( ) ;
index = pos ;
lineNumber = line ;
lineStart = start ;
}
function Position ( line , column ) {
this . line = line ;
this . column = column ;
}
function SourceLocation ( startLine , startColumn , line , column ) {
this . start = new Position ( startLine , startColumn ) ;
this . end = new Position ( line , column ) ;
}
SyntaxTreeDelegate = {
name : 'SyntaxTree' ,
processComment : function ( node ) {
var lastChild , trailingComments ;
if ( node . type === Syntax . Program ) {
if ( node . body . length > 0 ) {
return ;
}
}
if ( extra . trailingComments . length > 0 ) {
if ( extra . trailingComments [ 0 ] . range [ 0 ] >= node . range [ 1 ] ) {
trailingComments = extra . trailingComments ;
extra . trailingComments = [ ] ;
} else {
extra . trailingComments . length = 0 ;
}
} else {
if ( extra . bottomRightStack . length > 0 &&
extra . bottomRightStack [ extra . bottomRightStack . length - 1 ] . trailingComments &&
extra . bottomRightStack [ extra . bottomRightStack . length - 1 ] . trailingComments [ 0 ] . range [ 0 ] >= node . range [ 1 ] ) {
trailingComments = extra . bottomRightStack [ extra . bottomRightStack . length - 1 ] . trailingComments ;
delete extra . bottomRightStack [ extra . bottomRightStack . length - 1 ] . trailingComments ;
}
}
// Eating the stack.
while ( extra . bottomRightStack . length > 0 && extra . bottomRightStack [ extra . bottomRightStack . length - 1 ] . range [ 0 ] >= node . range [ 0 ] ) {
lastChild = extra . bottomRightStack . pop ( ) ;
}
if ( lastChild ) {
if ( lastChild . leadingComments && lastChild . leadingComments [ lastChild . leadingComments . length - 1 ] . range [ 1 ] <= node . range [ 0 ] ) {
node . leadingComments = lastChild . leadingComments ;
delete lastChild . leadingComments ;
}
} else if ( extra . leadingComments . length > 0 && extra . leadingComments [ extra . leadingComments . length - 1 ] . range [ 1 ] <= node . range [ 0 ] ) {
node . leadingComments = extra . leadingComments ;
extra . leadingComments = [ ] ;
}
if ( trailingComments ) {
node . trailingComments = trailingComments ;
}
extra . bottomRightStack . push ( node ) ;
} ,
markEnd : function ( node , startToken ) {
if ( extra . range ) {
node . range = [ startToken . start , index ] ;
}
if ( extra . loc ) {
node . loc = new SourceLocation (
startToken . startLineNumber === undefined ? startToken . lineNumber : startToken . startLineNumber ,
startToken . start - ( startToken . startLineStart === undefined ? startToken . lineStart : startToken . startLineStart ) ,
lineNumber ,
index - lineStart
) ;
this . postProcess ( node ) ;
}
if ( extra . attachComment ) {
this . processComment ( node ) ;
}
return node ;
} ,
postProcess : function ( node ) {
if ( extra . source ) {
node . loc . source = extra . source ;
}
return node ;
} ,
createArrayExpression : function ( elements ) {
return {
type : Syntax . ArrayExpression ,
elements : elements
} ;
} ,
createAssignmentExpression : function ( operator , left , right ) {
return {
type : Syntax . AssignmentExpression ,
operator : operator ,
left : left ,
right : right
} ;
} ,
createBinaryExpression : function ( operator , left , right ) {
var type = ( operator === '||' || operator === '&&' ) ? Syntax . LogicalExpression :
Syntax . BinaryExpression ;
return {
type : type ,
operator : operator ,
left : left ,
right : right
} ;
} ,
createBlockStatement : function ( body ) {
return {
type : Syntax . BlockStatement ,
body : body
} ;
} ,
createBreakStatement : function ( label ) {
return {
type : Syntax . BreakStatement ,
label : label
} ;
} ,
createCallExpression : function ( callee , args ) {
return {
type : Syntax . CallExpression ,
callee : callee ,
'arguments' : args
} ;
} ,
createCatchClause : function ( param , body ) {
return {
type : Syntax . CatchClause ,
param : param ,
body : body
} ;
} ,
createConditionalExpression : function ( test , consequent , alternate ) {
return {
type : Syntax . ConditionalExpression ,
test : test ,
consequent : consequent ,
alternate : alternate
} ;
} ,
createContinueStatement : function ( label ) {
return {
type : Syntax . ContinueStatement ,
label : label
} ;
} ,
createDebuggerStatement : function ( ) {
return {
type : Syntax . DebuggerStatement
} ;
} ,
createDoWhileStatement : function ( body , test ) {
return {
type : Syntax . DoWhileStatement ,
body : body ,
test : test
} ;
} ,
createEmptyStatement : function ( ) {
return {
type : Syntax . EmptyStatement
} ;
} ,
createExpressionStatement : function ( expression ) {
return {
type : Syntax . ExpressionStatement ,
expression : expression
} ;
} ,
createForStatement : function ( init , test , update , body ) {
return {
type : Syntax . ForStatement ,
init : init ,
test : test ,
update : update ,
body : body
} ;
} ,
createForInStatement : function ( left , right , body ) {
return {
type : Syntax . ForInStatement ,
left : left ,
right : right ,
body : body ,
each : false
} ;
} ,
createFunctionDeclaration : function ( id , params , defaults , body ) {
return {
type : Syntax . FunctionDeclaration ,
id : id ,
params : params ,
defaults : defaults ,
body : body ,
rest : null ,
generator : false ,
expression : false
} ;
} ,
createFunctionExpression : function ( id , params , defaults , body ) {
return {
type : Syntax . FunctionExpression ,
id : id ,
params : params ,
defaults : defaults ,
body : body ,
rest : null ,
generator : false ,
expression : false
} ;
} ,
createIdentifier : function ( name ) {
return {
type : Syntax . Identifier ,
name : name
} ;
} ,
createIfStatement : function ( test , consequent , alternate ) {
return {
type : Syntax . IfStatement ,
test : test ,
consequent : consequent ,
alternate : alternate
} ;
} ,
createLabeledStatement : function ( label , body ) {
return {
type : Syntax . LabeledStatement ,
label : label ,
body : body
} ;
} ,
createLiteral : function ( token ) {
return {
type : Syntax . Literal ,
value : token . value ,
raw : source . slice ( token . start , token . end )
} ;
} ,
createMemberExpression : function ( accessor , object , property ) {
return {
type : Syntax . MemberExpression ,
computed : accessor === '[' ,
object : object ,
property : property
} ;
} ,
createNewExpression : function ( callee , args ) {
return {
type : Syntax . NewExpression ,
callee : callee ,
'arguments' : args
} ;
} ,
createObjectExpression : function ( properties ) {
return {
type : Syntax . ObjectExpression ,
properties : properties
} ;
} ,
createPostfixExpression : function ( operator , argument ) {
return {
type : Syntax . UpdateExpression ,
operator : operator ,
argument : argument ,
prefix : false
} ;
} ,
createProgram : function ( body ) {
return {
type : Syntax . Program ,
body : body
} ;
} ,
createProperty : function ( kind , key , value ) {
return {
type : Syntax . Property ,
key : key ,
value : value ,
kind : kind
} ;
} ,
createReturnStatement : function ( argument ) {
return {
type : Syntax . ReturnStatement ,
argument : argument
} ;
} ,
createSequenceExpression : function ( expressions ) {
return {
type : Syntax . SequenceExpression ,
expressions : expressions
} ;
} ,
createSwitchCase : function ( test , consequent ) {
return {
type : Syntax . SwitchCase ,
test : test ,
consequent : consequent
} ;
} ,
createSwitchStatement : function ( discriminant , cases ) {
return {
type : Syntax . SwitchStatement ,
discriminant : discriminant ,
cases : cases
} ;
} ,
createThisExpression : function ( ) {
return {
type : Syntax . ThisExpression
} ;
} ,
createThrowStatement : function ( argument ) {
return {
type : Syntax . ThrowStatement ,
argument : argument
} ;
} ,
createTryStatement : function ( block , guardedHandlers , handlers , finalizer ) {
return {
type : Syntax . TryStatement ,
block : block ,
guardedHandlers : guardedHandlers ,
handlers : handlers ,
finalizer : finalizer
} ;
} ,
createUnaryExpression : function ( operator , argument ) {
if ( operator === '++' || operator === '--' ) {
return {
type : Syntax . UpdateExpression ,
operator : operator ,
argument : argument ,
prefix : true
} ;
}
return {
type : Syntax . UnaryExpression ,
operator : operator ,
argument : argument ,
prefix : true
} ;
} ,
createVariableDeclaration : function ( declarations , kind ) {
return {
type : Syntax . VariableDeclaration ,
declarations : declarations ,
kind : kind
} ;
} ,
createVariableDeclarator : function ( id , init ) {
return {
type : Syntax . VariableDeclarator ,
id : id ,
init : init
} ;
} ,
createWhileStatement : function ( test , body ) {
return {
type : Syntax . WhileStatement ,
test : test ,
body : body
} ;
} ,
createWithStatement : function ( object , body ) {
return {
type : Syntax . WithStatement ,
object : object ,
body : body
} ;
}
} ;
// Return true if there is a line terminator before the next token.
function peekLineTerminator ( ) {
var pos , line , start , found ;
pos = index ;
line = lineNumber ;
start = lineStart ;
skipComment ( ) ;
found = lineNumber !== line ;
index = pos ;
lineNumber = line ;
lineStart = start ;
return found ;
}
// Throw an exception
function throwError ( token , messageFormat ) {
var error ,
args = Array . prototype . slice . call ( arguments , 2 ) ,
msg = messageFormat . replace (
/%(\d)/g ,
function ( whole , index ) {
assert ( index < args . length , 'Message reference must be in range' ) ;
return args [ index ] ;
}
) ;
if ( typeof token . lineNumber === 'number' ) {
error = new Error ( 'Line ' + token . lineNumber + ': ' + msg ) ;
error . index = token . start ;
error . lineNumber = token . lineNumber ;
error . column = token . start - lineStart + 1 ;
} else {
error = new Error ( 'Line ' + lineNumber + ': ' + msg ) ;
error . index = index ;
error . lineNumber = lineNumber ;
error . column = index - lineStart + 1 ;
}
error . description = msg ;
throw error ;
}
function throwErrorTolerant ( ) {
try {
throwError . apply ( null , arguments ) ;
} catch ( e ) {
if ( extra . errors ) {
extra . errors . push ( e ) ;
} else {
throw e ;
}
}
}
// Throw an exception because of the token.
function throwUnexpected ( token ) {
if ( token . type === Token . EOF ) {
throwError ( token , Messages . UnexpectedEOS ) ;
}
if ( token . type === Token . NumericLiteral ) {
throwError ( token , Messages . UnexpectedNumber ) ;
}
if ( token . type === Token . StringLiteral ) {
throwError ( token , Messages . UnexpectedString ) ;
}
if ( token . type === Token . Identifier ) {
throwError ( token , Messages . UnexpectedIdentifier ) ;
}
if ( token . type === Token . Keyword ) {
if ( isFutureReservedWord ( token . value ) ) {
throwError ( token , Messages . UnexpectedReserved ) ;
} else if ( strict && isStrictModeReservedWord ( token . value ) ) {
throwErrorTolerant ( token , Messages . StrictReservedWord ) ;
return ;
}
throwError ( token , Messages . UnexpectedToken , token . value ) ;
}
// BooleanLiteral, NullLiteral, or Punctuator.
throwError ( token , Messages . UnexpectedToken , token . value ) ;
}
// Expect the next token to match the specified punctuator.
// If not, an exception will be thrown.
function expect ( value ) {
var token = lex ( ) ;
if ( token . type !== Token . Punctuator || token . value !== value ) {
throwUnexpected ( token ) ;
}
}
// Expect the next token to match the specified keyword.
// If not, an exception will be thrown.
function expectKeyword ( keyword ) {
var token = lex ( ) ;
if ( token . type !== Token . Keyword || token . value !== keyword ) {
throwUnexpected ( token ) ;
}
}
// Return true if the next token matches the specified punctuator.
function match ( value ) {
return lookahead . type === Token . Punctuator && lookahead . value === value ;
}
// Return true if the next token matches the specified keyword
function matchKeyword ( keyword ) {
return lookahead . type === Token . Keyword && lookahead . value === keyword ;
}
// Return true if the next token is an assignment operator
function matchAssign ( ) {
var op ;
if ( lookahead . type !== Token . Punctuator ) {
return false ;
}
op = lookahead . value ;
return op === '=' ||
op === '*=' ||
op === '/=' ||
op === '%=' ||
op === '+=' ||
op === '-=' ||
op === '<<=' ||
op === '>>=' ||
op === '>>>=' ||
op === '&=' ||
op === '^=' ||
op === '|=' ;
}
function consumeSemicolon ( ) {
var line ;
// Catch the very common case first: immediately a semicolon (U+003B).
if ( source . charCodeAt ( index ) === 0x3B || match ( ';' ) ) {
lex ( ) ;
return ;
}
line = lineNumber ;
skipComment ( ) ;
if ( lineNumber !== line ) {
return ;
}
if ( lookahead . type !== Token . EOF && ! match ( '}' ) ) {
throwUnexpected ( lookahead ) ;
}
}
// Return true if provided expression is LeftHandSideExpression
function isLeftHandSide ( expr ) {
return expr . type === Syntax . Identifier || expr . type === Syntax . MemberExpression ;
}
// 11.1.4 Array Initialiser
function parseArrayInitialiser ( ) {
var elements = [ ] , startToken ;
startToken = lookahead ;
expect ( '[' ) ;
while ( ! match ( ']' ) ) {
if ( match ( ',' ) ) {
lex ( ) ;
elements . push ( null ) ;
} else {
elements . push ( parseAssignmentExpression ( ) ) ;
if ( ! match ( ']' ) ) {
expect ( ',' ) ;
}
}
}
lex ( ) ;
return delegate . markEnd ( delegate . createArrayExpression ( elements ) , startToken ) ;
}
// 11.1.5 Object Initialiser
function parsePropertyFunction ( param , first ) {
var previousStrict , body , startToken ;
previousStrict = strict ;
startToken = lookahead ;
body = parseFunctionSourceElements ( ) ;
if ( first && strict && isRestrictedWord ( param [ 0 ] . name ) ) {
throwErrorTolerant ( first , Messages . StrictParamName ) ;
}
strict = previousStrict ;
return delegate . markEnd ( delegate . createFunctionExpression ( null , param , [ ] , body ) , startToken ) ;
}
function parseObjectPropertyKey ( ) {
var token , startToken ;
startToken = lookahead ;
token = lex ( ) ;
// Note: This function is called only from parseObjectProperty(), where
// EOF and Punctuator tokens are already filtered out.
if ( token . type === Token . StringLiteral || token . type === Token . NumericLiteral ) {
if ( strict && token . octal ) {
throwErrorTolerant ( token , Messages . StrictOctalLiteral ) ;
}
return delegate . markEnd ( delegate . createLiteral ( token ) , startToken ) ;
}
return delegate . markEnd ( delegate . createIdentifier ( token . value ) , startToken ) ;
}
function parseObjectProperty ( ) {
var token , key , id , value , param , startToken ;
token = lookahead ;
startToken = lookahead ;
if ( token . type === Token . Identifier ) {
id = parseObjectPropertyKey ( ) ;
// Property Assignment: Getter and Setter.
if ( token . value === 'get' && ! match ( ':' ) ) {
key = parseObjectPropertyKey ( ) ;
expect ( '(' ) ;
expect ( ')' ) ;
value = parsePropertyFunction ( [ ] ) ;
return delegate . markEnd ( delegate . createProperty ( 'get' , key , value ) , startToken ) ;
}
if ( token . value === 'set' && ! match ( ':' ) ) {
key = parseObjectPropertyKey ( ) ;
expect ( '(' ) ;
token = lookahead ;
if ( token . type !== Token . Identifier ) {
expect ( ')' ) ;
throwErrorTolerant ( token , Messages . UnexpectedToken , token . value ) ;
value = parsePropertyFunction ( [ ] ) ;
} else {
param = [ parseVariableIdentifier ( ) ] ;
expect ( ')' ) ;
value = parsePropertyFunction ( param , token ) ;
}
return delegate . markEnd ( delegate . createProperty ( 'set' , key , value ) , startToken ) ;
}
expect ( ':' ) ;
value = parseAssignmentExpression ( ) ;
return delegate . markEnd ( delegate . createProperty ( 'init' , id , value ) , startToken ) ;
}
if ( token . type === Token . EOF || token . type === Token . Punctuator ) {
throwUnexpected ( token ) ;
} else {
key = parseObjectPropertyKey ( ) ;
expect ( ':' ) ;
value = parseAssignmentExpression ( ) ;
return delegate . markEnd ( delegate . createProperty ( 'init' , key , value ) , startToken ) ;
}
}
function parseObjectInitialiser ( ) {
var properties = [ ] , property , name , key , kind , map = { } , toString = String , startToken ;
startToken = lookahead ;
expect ( '{' ) ;
while ( ! match ( '}' ) ) {
property = parseObjectProperty ( ) ;
if ( property . key . type === Syntax . Identifier ) {
name = property . key . name ;
} else {
name = toString ( property . key . value ) ;
}
kind = ( property . kind === 'init' ) ? PropertyKind . Data : ( property . kind === 'get' ) ? PropertyKind . Get : PropertyKind . Set ;
key = '$' + name ;
if ( Object . prototype . hasOwnProperty . call ( map , key ) ) {
if ( map [ key ] === PropertyKind . Data ) {
if ( strict && kind === PropertyKind . Data ) {
throwErrorTolerant ( { } , Messages . StrictDuplicateProperty ) ;
} else if ( kind !== PropertyKind . Data ) {
throwErrorTolerant ( { } , Messages . AccessorDataProperty ) ;
}
} else {
if ( kind === PropertyKind . Data ) {
throwErrorTolerant ( { } , Messages . AccessorDataProperty ) ;
} else if ( map [ key ] & kind ) {
throwErrorTolerant ( { } , Messages . AccessorGetSet ) ;
}
}
map [ key ] |= kind ;
} else {
map [ key ] = kind ;
}
properties . push ( property ) ;
if ( ! match ( '}' ) ) {
expect ( ',' ) ;
}
}
expect ( '}' ) ;
return delegate . markEnd ( delegate . createObjectExpression ( properties ) , startToken ) ;
}
// 11.1.6 The Grouping Operator
function parseGroupExpression ( ) {
var expr ;
expect ( '(' ) ;
expr = parseExpression ( ) ;
expect ( ')' ) ;
return expr ;
}
// 11.1 Primary Expressions
function parsePrimaryExpression ( ) {
var type , token , expr , startToken ;
if ( match ( '(' ) ) {
return parseGroupExpression ( ) ;
}
if ( match ( '[' ) ) {
return parseArrayInitialiser ( ) ;
}
if ( match ( '{' ) ) {
return parseObjectInitialiser ( ) ;
}
type = lookahead . type ;
startToken = lookahead ;
if ( type === Token . Identifier ) {
expr = delegate . createIdentifier ( lex ( ) . value ) ;
} else if ( type === Token . StringLiteral || type === Token . NumericLiteral ) {
if ( strict && lookahead . octal ) {
throwErrorTolerant ( lookahead , Messages . StrictOctalLiteral ) ;
}
expr = delegate . createLiteral ( lex ( ) ) ;
} else if ( type === Token . Keyword ) {
if ( matchKeyword ( 'function' ) ) {
return parseFunctionExpression ( ) ;
}
if ( matchKeyword ( 'this' ) ) {
lex ( ) ;
expr = delegate . createThisExpression ( ) ;
} else {
throwUnexpected ( lex ( ) ) ;
}
} else if ( type === Token . BooleanLiteral ) {
token = lex ( ) ;
token . value = ( token . value === 'true' ) ;
expr = delegate . createLiteral ( token ) ;
} else if ( type === Token . NullLiteral ) {
token = lex ( ) ;
token . value = null ;
expr = delegate . createLiteral ( token ) ;
} else if ( match ( '/' ) || match ( '/=' ) ) {
if ( typeof extra . tokens !== 'undefined' ) {
expr = delegate . createLiteral ( collectRegex ( ) ) ;
} else {
expr = delegate . createLiteral ( scanRegExp ( ) ) ;
}
peek ( ) ;
} else {
throwUnexpected ( lex ( ) ) ;
}
return delegate . markEnd ( expr , startToken ) ;
}
// 11.2 Left-Hand-Side Expressions
function parseArguments ( ) {
var args = [ ] ;
expect ( '(' ) ;
if ( ! match ( ')' ) ) {
while ( index < length ) {
args . push ( parseAssignmentExpression ( ) ) ;
if ( match ( ')' ) ) {
break ;
}
expect ( ',' ) ;
}
}
expect ( ')' ) ;
return args ;
}
function parseNonComputedProperty ( ) {
var token , startToken ;
startToken = lookahead ;
token = lex ( ) ;
if ( ! isIdentifierName ( token ) ) {
throwUnexpected ( token ) ;
}
return delegate . markEnd ( delegate . createIdentifier ( token . value ) , startToken ) ;
}
function parseNonComputedMember ( ) {
expect ( '.' ) ;
return parseNonComputedProperty ( ) ;
}
function parseComputedMember ( ) {
var expr ;
expect ( '[' ) ;
expr = parseExpression ( ) ;
expect ( ']' ) ;
return expr ;
}
function parseNewExpression ( ) {
var callee , args , startToken ;
startToken = lookahead ;
expectKeyword ( 'new' ) ;
callee = parseLeftHandSideExpression ( ) ;
args = match ( '(' ) ? parseArguments ( ) : [ ] ;
return delegate . markEnd ( delegate . createNewExpression ( callee , args ) , startToken ) ;
}
function parseLeftHandSideExpressionAllowCall ( ) {
var previousAllowIn , expr , args , property , startToken ;
startToken = lookahead ;
previousAllowIn = state . allowIn ;
state . allowIn = true ;
expr = matchKeyword ( 'new' ) ? parseNewExpression ( ) : parsePrimaryExpression ( ) ;
state . allowIn = previousAllowIn ;
for ( ; ; ) {
if ( match ( '.' ) ) {
property = parseNonComputedMember ( ) ;
expr = delegate . createMemberExpression ( '.' , expr , property ) ;
} else if ( match ( '(' ) ) {
args = parseArguments ( ) ;
expr = delegate . createCallExpression ( expr , args ) ;
} else if ( match ( '[' ) ) {
property = parseComputedMember ( ) ;
expr = delegate . createMemberExpression ( '[' , expr , property ) ;
} else {
break ;
}
delegate . markEnd ( expr , startToken ) ;
}
return expr ;
}
function parseLeftHandSideExpression ( ) {
var previousAllowIn , expr , property , startToken ;
startToken = lookahead ;
previousAllowIn = state . allowIn ;
expr = matchKeyword ( 'new' ) ? parseNewExpression ( ) : parsePrimaryExpression ( ) ;
state . allowIn = previousAllowIn ;
while ( match ( '.' ) || match ( '[' ) ) {
if ( match ( '[' ) ) {
property = parseComputedMember ( ) ;
expr = delegate . createMemberExpression ( '[' , expr , property ) ;
} else {
property = parseNonComputedMember ( ) ;
expr = delegate . createMemberExpression ( '.' , expr , property ) ;
}
delegate . markEnd ( expr , startToken ) ;
}
return expr ;
}
// 11.3 Postfix Expressions
function parsePostfixExpression ( ) {
var expr , token , startToken = lookahead ;
expr = parseLeftHandSideExpressionAllowCall ( ) ;
if ( lookahead . type === Token . Punctuator ) {
if ( ( match ( '++' ) || match ( '--' ) ) && ! peekLineTerminator ( ) ) {
// 11.3.1, 11.3.2
if ( strict && expr . type === Syntax . Identifier && isRestrictedWord ( expr . name ) ) {
throwErrorTolerant ( { } , Messages . StrictLHSPostfix ) ;
}
if ( ! isLeftHandSide ( expr ) ) {
throwErrorTolerant ( { } , Messages . InvalidLHSInAssignment ) ;
}
token = lex ( ) ;
expr = delegate . markEnd ( delegate . createPostfixExpression ( token . value , expr ) , startToken ) ;
}
}
return expr ;
}
// 11.4 Unary Operators
function parseUnaryExpression ( ) {
var token , expr , startToken ;
if ( lookahead . type !== Token . Punctuator && lookahead . type !== Token . Keyword ) {
expr = parsePostfixExpression ( ) ;
} else if ( match ( '++' ) || match ( '--' ) ) {
startToken = lookahead ;
token = lex ( ) ;
expr = parseUnaryExpression ( ) ;
// 11.4.4, 11.4.5
if ( strict && expr . type === Syntax . Identifier && isRestrictedWord ( expr . name ) ) {
throwErrorTolerant ( { } , Messages . StrictLHSPrefix ) ;
}
if ( ! isLeftHandSide ( expr ) ) {
throwErrorTolerant ( { } , Messages . InvalidLHSInAssignment ) ;
}
expr = delegate . createUnaryExpression ( token . value , expr ) ;
expr = delegate . markEnd ( expr , startToken ) ;
} else if ( match ( '+' ) || match ( '-' ) || match ( '~' ) || match ( '!' ) ) {
startToken = lookahead ;
token = lex ( ) ;
expr = parseUnaryExpression ( ) ;
expr = delegate . createUnaryExpression ( token . value , expr ) ;
expr = delegate . markEnd ( expr , startToken ) ;
} else if ( matchKeyword ( 'delete' ) || matchKeyword ( 'void' ) || matchKeyword ( 'typeof' ) ) {
startToken = lookahead ;
token = lex ( ) ;
expr = parseUnaryExpression ( ) ;
expr = delegate . createUnaryExpression ( token . value , expr ) ;
expr = delegate . markEnd ( expr , startToken ) ;
if ( strict && expr . operator === 'delete' && expr . argument . type === Syntax . Identifier ) {
throwErrorTolerant ( { } , Messages . StrictDelete ) ;
}
} else {
expr = parsePostfixExpression ( ) ;
}
return expr ;
}
function binaryPrecedence ( token , allowIn ) {
var prec = 0 ;
if ( token . type !== Token . Punctuator && token . type !== Token . Keyword ) {
return 0 ;
}
switch ( token . value ) {
case '||' :
prec = 1 ;
break ;
case '&&' :
prec = 2 ;
break ;
case '|' :
prec = 3 ;
break ;
case '^' :
prec = 4 ;
break ;
case '&' :
prec = 5 ;
break ;
case '==' :
case '!=' :
case '===' :
case '!==' :
prec = 6 ;
break ;
case '<' :
case '>' :
case '<=' :
case '>=' :
case 'instanceof' :
prec = 7 ;
break ;
case 'in' :
prec = allowIn ? 7 : 0 ;
break ;
case '<<' :
case '>>' :
case '>>>' :
prec = 8 ;
break ;
case '+' :
case '-' :
prec = 9 ;
break ;
case '*' :
case '/' :
case '%' :
prec = 11 ;
break ;
default :
break ;
}
return prec ;
}
// 11.5 Multiplicative Operators
// 11.6 Additive Operators
// 11.7 Bitwise Shift Operators
// 11.8 Relational Operators
// 11.9 Equality Operators
// 11.10 Binary Bitwise Operators
// 11.11 Binary Logical Operators
function parseBinaryExpression ( ) {
var marker , markers , expr , token , prec , stack , right , operator , left , i ;
marker = lookahead ;
left = parseUnaryExpression ( ) ;
token = lookahead ;
prec = binaryPrecedence ( token , state . allowIn ) ;
if ( prec === 0 ) {
return left ;
}
token . prec = prec ;
lex ( ) ;
markers = [ marker , lookahead ] ;
right = parseUnaryExpression ( ) ;
stack = [ left , token , right ] ;
while ( ( prec = binaryPrecedence ( lookahead , state . allowIn ) ) > 0 ) {
// Reduce: make a binary expression from the three topmost entries.
while ( ( stack . length > 2 ) && ( prec <= stack [ stack . length - 2 ] . prec ) ) {
right = stack . pop ( ) ;
operator = stack . pop ( ) . value ;
left = stack . pop ( ) ;
expr = delegate . createBinaryExpression ( operator , left , right ) ;
markers . pop ( ) ;
marker = markers [ markers . length - 1 ] ;
delegate . markEnd ( expr , marker ) ;
stack . push ( expr ) ;
}
// Shift.
token = lex ( ) ;
token . prec = prec ;
stack . push ( token ) ;
markers . push ( lookahead ) ;
expr = parseUnaryExpression ( ) ;
stack . push ( expr ) ;
}
// Final reduce to clean-up the stack.
i = stack . length - 1 ;
expr = stack [ i ] ;
markers . pop ( ) ;
while ( i > 1 ) {
expr = delegate . createBinaryExpression ( stack [ i - 1 ] . value , stack [ i - 2 ] , expr ) ;
i -= 2 ;
marker = markers . pop ( ) ;
delegate . markEnd ( expr , marker ) ;
}
return expr ;
}
// 11.12 Conditional Operator
function parseConditionalExpression ( ) {
var expr , previousAllowIn , consequent , alternate , startToken ;
startToken = lookahead ;
expr = parseBinaryExpression ( ) ;
if ( match ( '?' ) ) {
lex ( ) ;
previousAllowIn = state . allowIn ;
state . allowIn = true ;
consequent = parseAssignmentExpression ( ) ;
state . allowIn = previousAllowIn ;
expect ( ':' ) ;
alternate = parseAssignmentExpression ( ) ;
expr = delegate . createConditionalExpression ( expr , consequent , alternate ) ;
delegate . markEnd ( expr , startToken ) ;
}
return expr ;
}
// 11.13 Assignment Operators
function parseAssignmentExpression ( ) {
var token , left , right , node , startToken ;
token = lookahead ;
startToken = lookahead ;
node = left = parseConditionalExpression ( ) ;
if ( matchAssign ( ) ) {
// LeftHandSideExpression
if ( ! isLeftHandSide ( left ) ) {
throwErrorTolerant ( { } , Messages . InvalidLHSInAssignment ) ;
}
// 11.13.1
if ( strict && left . type === Syntax . Identifier && isRestrictedWord ( left . name ) ) {
throwErrorTolerant ( token , Messages . StrictLHSAssignment ) ;
}
token = lex ( ) ;
right = parseAssignmentExpression ( ) ;
node = delegate . markEnd ( delegate . createAssignmentExpression ( token . value , left , right ) , startToken ) ;
}
return node ;
}
// 11.14 Comma Operator
function parseExpression ( ) {
var expr , startToken = lookahead ;
expr = parseAssignmentExpression ( ) ;
if ( match ( ',' ) ) {
expr = delegate . createSequenceExpression ( [ expr ] ) ;
while ( index < length ) {
if ( ! match ( ',' ) ) {
break ;
}
lex ( ) ;
expr . expressions . push ( parseAssignmentExpression ( ) ) ;
}
delegate . markEnd ( expr , startToken ) ;
}
return expr ;
}
// 12.1 Block
function parseStatementList ( ) {
var list = [ ] ,
statement ;
while ( index < length ) {
if ( match ( '}' ) ) {
break ;
}
statement = parseSourceElement ( ) ;
if ( typeof statement === 'undefined' ) {
break ;
}
list . push ( statement ) ;
}
return list ;
}
function parseBlock ( ) {
var block , startToken ;
startToken = lookahead ;
expect ( '{' ) ;
block = parseStatementList ( ) ;
expect ( '}' ) ;
return delegate . markEnd ( delegate . createBlockStatement ( block ) , startToken ) ;
}
// 12.2 Variable Statement
function parseVariableIdentifier ( ) {
var token , startToken ;
startToken = lookahead ;
token = lex ( ) ;
if ( token . type !== Token . Identifier ) {
throwUnexpected ( token ) ;
}
return delegate . markEnd ( delegate . createIdentifier ( token . value ) , startToken ) ;
}
function parseVariableDeclaration ( kind ) {
var init = null , id , startToken ;
startToken = lookahead ;
id = parseVariableIdentifier ( ) ;
// 12.2.1
if ( strict && isRestrictedWord ( id . name ) ) {
throwErrorTolerant ( { } , Messages . StrictVarName ) ;
}
if ( kind === 'const' ) {
expect ( '=' ) ;
init = parseAssignmentExpression ( ) ;
} else if ( match ( '=' ) ) {
lex ( ) ;
init = parseAssignmentExpression ( ) ;
}
return delegate . markEnd ( delegate . createVariableDeclarator ( id , init ) , startToken ) ;
}
function parseVariableDeclarationList ( kind ) {
var list = [ ] ;
do {
list . push ( parseVariableDeclaration ( kind ) ) ;
if ( ! match ( ',' ) ) {
break ;
}
lex ( ) ;
} while ( index < length ) ;
return list ;
}
function parseVariableStatement ( ) {
var declarations ;
expectKeyword ( 'var' ) ;
declarations = parseVariableDeclarationList ( ) ;
consumeSemicolon ( ) ;
return delegate . createVariableDeclaration ( declarations , 'var' ) ;
}
// kind may be `const` or `let`
// Both are experimental and not in the specification yet.
// see http://wiki.ecmascript.org/doku.php?id=harmony:const
// and http://wiki.ecmascript.org/doku.php?id=harmony:let
function parseConstLetDeclaration ( kind ) {
var declarations , startToken ;
startToken = lookahead ;
expectKeyword ( kind ) ;
declarations = parseVariableDeclarationList ( kind ) ;
consumeSemicolon ( ) ;
return delegate . markEnd ( delegate . createVariableDeclaration ( declarations , kind ) , startToken ) ;
}
// 12.3 Empty Statement
function parseEmptyStatement ( ) {
expect ( ';' ) ;
return delegate . createEmptyStatement ( ) ;
}
// 12.4 Expression Statement
function parseExpressionStatement ( ) {
var expr = parseExpression ( ) ;
consumeSemicolon ( ) ;
return delegate . createExpressionStatement ( expr ) ;
}
// 12.5 If statement
function parseIfStatement ( ) {
var test , consequent , alternate ;
expectKeyword ( 'if' ) ;
expect ( '(' ) ;
test = parseExpression ( ) ;
expect ( ')' ) ;
consequent = parseStatement ( ) ;
if ( matchKeyword ( 'else' ) ) {
lex ( ) ;
alternate = parseStatement ( ) ;
} else {
alternate = null ;
}
return delegate . createIfStatement ( test , consequent , alternate ) ;
}
// 12.6 Iteration Statements
function parseDoWhileStatement ( ) {
var body , test , oldInIteration ;
expectKeyword ( 'do' ) ;
oldInIteration = state . inIteration ;
state . inIteration = true ;
body = parseStatement ( ) ;
state . inIteration = oldInIteration ;
expectKeyword ( 'while' ) ;
expect ( '(' ) ;
test = parseExpression ( ) ;
expect ( ')' ) ;
if ( match ( ';' ) ) {
lex ( ) ;
}
return delegate . createDoWhileStatement ( body , test ) ;
}
function parseWhileStatement ( ) {
var test , body , oldInIteration ;
expectKeyword ( 'while' ) ;
expect ( '(' ) ;
test = parseExpression ( ) ;
expect ( ')' ) ;
oldInIteration = state . inIteration ;
state . inIteration = true ;
body = parseStatement ( ) ;
state . inIteration = oldInIteration ;
return delegate . createWhileStatement ( test , body ) ;
}
function parseForVariableDeclaration ( ) {
var token , declarations , startToken ;
startToken = lookahead ;
token = lex ( ) ;
declarations = parseVariableDeclarationList ( ) ;
return delegate . markEnd ( delegate . createVariableDeclaration ( declarations , token . value ) , startToken ) ;
}
function parseForStatement ( ) {
var init , test , update , left , right , body , oldInIteration ;
init = test = update = null ;
expectKeyword ( 'for' ) ;
expect ( '(' ) ;
if ( match ( ';' ) ) {
lex ( ) ;
} else {
if ( matchKeyword ( 'var' ) || matchKeyword ( 'let' ) ) {
state . allowIn = false ;
init = parseForVariableDeclaration ( ) ;
state . allowIn = true ;
if ( init . declarations . length === 1 && matchKeyword ( 'in' ) ) {
lex ( ) ;
left = init ;
right = parseExpression ( ) ;
init = null ;
}
} else {
state . allowIn = false ;
init = parseExpression ( ) ;
state . allowIn = true ;
if ( matchKeyword ( 'in' ) ) {
// LeftHandSideExpression
if ( ! isLeftHandSide ( init ) ) {
throwErrorTolerant ( { } , Messages . InvalidLHSInForIn ) ;
}
lex ( ) ;
left = init ;
right = parseExpression ( ) ;
init = null ;
}
}
if ( typeof left === 'undefined' ) {
expect ( ';' ) ;
}
}
if ( typeof left === 'undefined' ) {
if ( ! match ( ';' ) ) {
test = parseExpression ( ) ;
}
expect ( ';' ) ;
if ( ! match ( ')' ) ) {
update = parseExpression ( ) ;
}
}
expect ( ')' ) ;
oldInIteration = state . inIteration ;
state . inIteration = true ;
body = parseStatement ( ) ;
state . inIteration = oldInIteration ;
return ( typeof left === 'undefined' ) ?
delegate . createForStatement ( init , test , update , body ) :
delegate . createForInStatement ( left , right , body ) ;
}
// 12.7 The continue statement
function parseContinueStatement ( ) {
var label = null , key ;
expectKeyword ( 'continue' ) ;
// Optimize the most common form: 'continue;'.
if ( source . charCodeAt ( index ) === 0x3B ) {
lex ( ) ;
if ( ! state . inIteration ) {
throwError ( { } , Messages . IllegalContinue ) ;
}
return delegate . createContinueStatement ( null ) ;
}
if ( peekLineTerminator ( ) ) {
if ( ! state . inIteration ) {
throwError ( { } , Messages . IllegalContinue ) ;
}
return delegate . createContinueStatement ( null ) ;
}
if ( lookahead . type === Token . Identifier ) {
label = parseVariableIdentifier ( ) ;
key = '$' + label . name ;
if ( ! Object . prototype . hasOwnProperty . call ( state . labelSet , key ) ) {
throwError ( { } , Messages . UnknownLabel , label . name ) ;
}
}
consumeSemicolon ( ) ;
if ( label === null && ! state . inIteration ) {
throwError ( { } , Messages . IllegalContinue ) ;
}
return delegate . createContinueStatement ( label ) ;
}
// 12.8 The break statement
function parseBreakStatement ( ) {
var label = null , key ;
expectKeyword ( 'break' ) ;
// Catch the very common case first: immediately a semicolon (U+003B).
if ( source . charCodeAt ( index ) === 0x3B ) {
lex ( ) ;
if ( ! ( state . inIteration || state . inSwitch ) ) {
throwError ( { } , Messages . IllegalBreak ) ;
}
return delegate . createBreakStatement ( null ) ;
}
if ( peekLineTerminator ( ) ) {
if ( ! ( state . inIteration || state . inSwitch ) ) {
throwError ( { } , Messages . IllegalBreak ) ;
}
return delegate . createBreakStatement ( null ) ;
}
if ( lookahead . type === Token . Identifier ) {
label = parseVariableIdentifier ( ) ;
key = '$' + label . name ;
if ( ! Object . prototype . hasOwnProperty . call ( state . labelSet , key ) ) {
throwError ( { } , Messages . UnknownLabel , label . name ) ;
}
}
consumeSemicolon ( ) ;
if ( label === null && ! ( state . inIteration || state . inSwitch ) ) {
throwError ( { } , Messages . IllegalBreak ) ;
}
return delegate . createBreakStatement ( label ) ;
}
// 12.9 The return statement
function parseReturnStatement ( ) {
var argument = null ;
expectKeyword ( 'return' ) ;
if ( ! state . inFunctionBody ) {
throwErrorTolerant ( { } , Messages . IllegalReturn ) ;
}
// 'return' followed by a space and an identifier is very common.
if ( source . charCodeAt ( index ) === 0x20 ) {
if ( isIdentifierStart ( source . charCodeAt ( index + 1 ) ) ) {
argument = parseExpression ( ) ;
consumeSemicolon ( ) ;
return delegate . createReturnStatement ( argument ) ;
}
}
if ( peekLineTerminator ( ) ) {
return delegate . createReturnStatement ( null ) ;
}
if ( ! match ( ';' ) ) {
if ( ! match ( '}' ) && lookahead . type !== Token . EOF ) {
argument = parseExpression ( ) ;
}
}
consumeSemicolon ( ) ;
return delegate . createReturnStatement ( argument ) ;
}
// 12.10 The with statement
function parseWithStatement ( ) {
var object , body ;
if ( strict ) {
// TODO(ikarienator): Should we update the test cases instead?
skipComment ( ) ;
throwErrorTolerant ( { } , Messages . StrictModeWith ) ;
}
expectKeyword ( 'with' ) ;
expect ( '(' ) ;
object = parseExpression ( ) ;
expect ( ')' ) ;
body = parseStatement ( ) ;
return delegate . createWithStatement ( object , body ) ;
}
// 12.10 The swith statement
function parseSwitchCase ( ) {
var test , consequent = [ ] , statement , startToken ;
startToken = lookahead ;
if ( matchKeyword ( 'default' ) ) {
lex ( ) ;
test = null ;
} else {
expectKeyword ( 'case' ) ;
test = parseExpression ( ) ;
}
expect ( ':' ) ;
while ( index < length ) {
if ( match ( '}' ) || matchKeyword ( 'default' ) || matchKeyword ( 'case' ) ) {
break ;
}
statement = parseStatement ( ) ;
consequent . push ( statement ) ;
}
return delegate . markEnd ( delegate . createSwitchCase ( test , consequent ) , startToken ) ;
}
function parseSwitchStatement ( ) {
var discriminant , cases , clause , oldInSwitch , defaultFound ;
expectKeyword ( 'switch' ) ;
expect ( '(' ) ;
discriminant = parseExpression ( ) ;
expect ( ')' ) ;
expect ( '{' ) ;
cases = [ ] ;
if ( match ( '}' ) ) {
lex ( ) ;
return delegate . createSwitchStatement ( discriminant , cases ) ;
}
oldInSwitch = state . inSwitch ;
state . inSwitch = true ;
defaultFound = false ;
while ( index < length ) {
if ( match ( '}' ) ) {
break ;
}
clause = parseSwitchCase ( ) ;
if ( clause . test === null ) {
if ( defaultFound ) {
throwError ( { } , Messages . MultipleDefaultsInSwitch ) ;
}
defaultFound = true ;
}
cases . push ( clause ) ;
}
state . inSwitch = oldInSwitch ;
expect ( '}' ) ;
return delegate . createSwitchStatement ( discriminant , cases ) ;
}
// 12.13 The throw statement
function parseThrowStatement ( ) {
var argument ;
expectKeyword ( 'throw' ) ;
if ( peekLineTerminator ( ) ) {
throwError ( { } , Messages . NewlineAfterThrow ) ;
}
argument = parseExpression ( ) ;
consumeSemicolon ( ) ;
return delegate . createThrowStatement ( argument ) ;
}
// 12.14 The try statement
function parseCatchClause ( ) {
var param , body , startToken ;
startToken = lookahead ;
expectKeyword ( 'catch' ) ;
expect ( '(' ) ;
if ( match ( ')' ) ) {
throwUnexpected ( lookahead ) ;
}
param = parseVariableIdentifier ( ) ;
// 12.14.1
if ( strict && isRestrictedWord ( param . name ) ) {
throwErrorTolerant ( { } , Messages . StrictCatchVariable ) ;
}
expect ( ')' ) ;
body = parseBlock ( ) ;
return delegate . markEnd ( delegate . createCatchClause ( param , body ) , startToken ) ;
}
function parseTryStatement ( ) {
var block , handlers = [ ] , finalizer = null ;
expectKeyword ( 'try' ) ;
block = parseBlock ( ) ;
if ( matchKeyword ( 'catch' ) ) {
handlers . push ( parseCatchClause ( ) ) ;
}
if ( matchKeyword ( 'finally' ) ) {
lex ( ) ;
finalizer = parseBlock ( ) ;
}
if ( handlers . length === 0 && ! finalizer ) {
throwError ( { } , Messages . NoCatchOrFinally ) ;
}
return delegate . createTryStatement ( block , [ ] , handlers , finalizer ) ;
}
// 12.15 The debugger statement
function parseDebuggerStatement ( ) {
expectKeyword ( 'debugger' ) ;
consumeSemicolon ( ) ;
return delegate . createDebuggerStatement ( ) ;
}
// 12 Statements
function parseStatement ( ) {
var type = lookahead . type ,
expr ,
labeledBody ,
key ,
startToken ;
if ( type === Token . EOF ) {
throwUnexpected ( lookahead ) ;
}
if ( type === Token . Punctuator && lookahead . value === '{' ) {
return parseBlock ( ) ;
}
startToken = lookahead ;
if ( type === Token . Punctuator ) {
switch ( lookahead . value ) {
case ';' :
return delegate . markEnd ( parseEmptyStatement ( ) , startToken ) ;
case '(' :
return delegate . markEnd ( parseExpressionStatement ( ) , startToken ) ;
default :
break ;
}
}
if ( type === Token . Keyword ) {
switch ( lookahead . value ) {
case 'break' :
return delegate . markEnd ( parseBreakStatement ( ) , startToken ) ;
case 'continue' :
return delegate . markEnd ( parseContinueStatement ( ) , startToken ) ;
case 'debugger' :
return delegate . markEnd ( parseDebuggerStatement ( ) , startToken ) ;
case 'do' :
return delegate . markEnd ( parseDoWhileStatement ( ) , startToken ) ;
case 'for' :
return delegate . markEnd ( parseForStatement ( ) , startToken ) ;
case 'function' :
return delegate . markEnd ( parseFunctionDeclaration ( ) , startToken ) ;
case 'if' :
return delegate . markEnd ( parseIfStatement ( ) , startToken ) ;
case 'return' :
return delegate . markEnd ( parseReturnStatement ( ) , startToken ) ;
case 'switch' :
return delegate . markEnd ( parseSwitchStatement ( ) , startToken ) ;
case 'throw' :
return delegate . markEnd ( parseThrowStatement ( ) , startToken ) ;
case 'try' :
return delegate . markEnd ( parseTryStatement ( ) , startToken ) ;
case 'var' :
return delegate . markEnd ( parseVariableStatement ( ) , startToken ) ;
case 'while' :
return delegate . markEnd ( parseWhileStatement ( ) , startToken ) ;
case 'with' :
return delegate . markEnd ( parseWithStatement ( ) , startToken ) ;
default :
break ;
}
}
expr = parseExpression ( ) ;
// 12.12 Labelled Statements
if ( ( expr . type === Syntax . Identifier ) && match ( ':' ) ) {
lex ( ) ;
key = '$' + expr . name ;
if ( Object . prototype . hasOwnProperty . call ( state . labelSet , key ) ) {
throwError ( { } , Messages . Redeclaration , 'Label' , expr . name ) ;
}
state . labelSet [ key ] = true ;
labeledBody = parseStatement ( ) ;
delete state . labelSet [ key ] ;
return delegate . markEnd ( delegate . createLabeledStatement ( expr , labeledBody ) , startToken ) ;
}
consumeSemicolon ( ) ;
return delegate . markEnd ( delegate . createExpressionStatement ( expr ) , startToken ) ;
}
// 13 Function Definition
function parseFunctionSourceElements ( ) {
var sourceElement , sourceElements = [ ] , token , directive , firstRestricted ,
oldLabelSet , oldInIteration , oldInSwitch , oldInFunctionBody , startToken ;
startToken = lookahead ;
expect ( '{' ) ;
while ( index < length ) {
if ( lookahead . type !== Token . StringLiteral ) {
break ;
}
token = lookahead ;
sourceElement = parseSourceElement ( ) ;
sourceElements . push ( sourceElement ) ;
if ( sourceElement . expression . type !== Syntax . Literal ) {
// this is not directive
break ;
}
directive = source . slice ( token . start + 1 , token . end - 1 ) ;
if ( directive === 'use strict' ) {
strict = true ;
if ( firstRestricted ) {
throwErrorTolerant ( firstRestricted , Messages . StrictOctalLiteral ) ;
}
} else {
if ( ! firstRestricted && token . octal ) {
firstRestricted = token ;
}
}
}
oldLabelSet = state . labelSet ;
oldInIteration = state . inIteration ;
oldInSwitch = state . inSwitch ;
oldInFunctionBody = state . inFunctionBody ;
state . labelSet = { } ;
state . inIteration = false ;
state . inSwitch = false ;
state . inFunctionBody = true ;
while ( index < length ) {
if ( match ( '}' ) ) {
break ;
}
sourceElement = parseSourceElement ( ) ;
if ( typeof sourceElement === 'undefined' ) {
break ;
}
sourceElements . push ( sourceElement ) ;
}
expect ( '}' ) ;
state . labelSet = oldLabelSet ;
state . inIteration = oldInIteration ;
state . inSwitch = oldInSwitch ;
state . inFunctionBody = oldInFunctionBody ;
return delegate . markEnd ( delegate . createBlockStatement ( sourceElements ) , startToken ) ;
}
function parseParams ( firstRestricted ) {
var param , params = [ ] , token , stricted , paramSet , key , message ;
expect ( '(' ) ;
if ( ! match ( ')' ) ) {
paramSet = { } ;
while ( index < length ) {
token = lookahead ;
param = parseVariableIdentifier ( ) ;
key = '$' + token . value ;
if ( strict ) {
if ( isRestrictedWord ( token . value ) ) {
stricted = token ;
message = Messages . StrictParamName ;
}
if ( Object . prototype . hasOwnProperty . call ( paramSet , key ) ) {
stricted = token ;
message = Messages . StrictParamDupe ;
}
} else if ( ! firstRestricted ) {
if ( isRestrictedWord ( token . value ) ) {
firstRestricted = token ;
message = Messages . StrictParamName ;
} else if ( isStrictModeReservedWord ( token . value ) ) {
firstRestricted = token ;
message = Messages . StrictReservedWord ;
} else if ( Object . prototype . hasOwnProperty . call ( paramSet , key ) ) {
firstRestricted = token ;
message = Messages . StrictParamDupe ;
}
}
params . push ( param ) ;
paramSet [ key ] = true ;
if ( match ( ')' ) ) {
break ;
}
expect ( ',' ) ;
}
}
expect ( ')' ) ;
return {
params : params ,
stricted : stricted ,
firstRestricted : firstRestricted ,
message : message
} ;
}
function parseFunctionDeclaration ( ) {
var id , params = [ ] , body , token , stricted , tmp , firstRestricted , message , previousStrict , startToken ;
startToken = lookahead ;
expectKeyword ( 'function' ) ;
token = lookahead ;
id = parseVariableIdentifier ( ) ;
if ( strict ) {
if ( isRestrictedWord ( token . value ) ) {
throwErrorTolerant ( token , Messages . StrictFunctionName ) ;
}
} else {
if ( isRestrictedWord ( token . value ) ) {
firstRestricted = token ;
message = Messages . StrictFunctionName ;
} else if ( isStrictModeReservedWord ( token . value ) ) {
firstRestricted = token ;
message = Messages . StrictReservedWord ;
}
}
tmp = parseParams ( firstRestricted ) ;
params = tmp . params ;
stricted = tmp . stricted ;
firstRestricted = tmp . firstRestricted ;
if ( tmp . message ) {
message = tmp . message ;
}
previousStrict = strict ;
body = parseFunctionSourceElements ( ) ;
if ( strict && firstRestricted ) {
throwError ( firstRestricted , message ) ;
}
if ( strict && stricted ) {
throwErrorTolerant ( stricted , message ) ;
}
strict = previousStrict ;
return delegate . markEnd ( delegate . createFunctionDeclaration ( id , params , [ ] , body ) , startToken ) ;
}
function parseFunctionExpression ( ) {
var token , id = null , stricted , firstRestricted , message , tmp , params = [ ] , body , previousStrict , startToken ;
startToken = lookahead ;
expectKeyword ( 'function' ) ;
if ( ! match ( '(' ) ) {
token = lookahead ;
id = parseVariableIdentifier ( ) ;
if ( strict ) {
if ( isRestrictedWord ( token . value ) ) {
throwErrorTolerant ( token , Messages . StrictFunctionName ) ;
}
} else {
if ( isRestrictedWord ( token . value ) ) {
firstRestricted = token ;
message = Messages . StrictFunctionName ;
} else if ( isStrictModeReservedWord ( token . value ) ) {
firstRestricted = token ;
message = Messages . StrictReservedWord ;
}
}
}
tmp = parseParams ( firstRestricted ) ;
params = tmp . params ;
stricted = tmp . stricted ;
firstRestricted = tmp . firstRestricted ;
if ( tmp . message ) {
message = tmp . message ;
}
previousStrict = strict ;
body = parseFunctionSourceElements ( ) ;
if ( strict && firstRestricted ) {
throwError ( firstRestricted , message ) ;
}
if ( strict && stricted ) {
throwErrorTolerant ( stricted , message ) ;
}
strict = previousStrict ;
return delegate . markEnd ( delegate . createFunctionExpression ( id , params , [ ] , body ) , startToken ) ;
}
// 14 Program
function parseSourceElement ( ) {
if ( lookahead . type === Token . Keyword ) {
switch ( lookahead . value ) {
case 'const' :
case 'let' :
return parseConstLetDeclaration ( lookahead . value ) ;
case 'function' :
return parseFunctionDeclaration ( ) ;
default :
return parseStatement ( ) ;
}
}
if ( lookahead . type !== Token . EOF ) {
return parseStatement ( ) ;
}
}
function parseSourceElements ( ) {
var sourceElement , sourceElements = [ ] , token , directive , firstRestricted ;
while ( index < length ) {
token = lookahead ;
if ( token . type !== Token . StringLiteral ) {
break ;
}
sourceElement = parseSourceElement ( ) ;
sourceElements . push ( sourceElement ) ;
if ( sourceElement . expression . type !== Syntax . Literal ) {
// this is not directive
break ;
}
directive = source . slice ( token . start + 1 , token . end - 1 ) ;
if ( directive === 'use strict' ) {
strict = true ;
if ( firstRestricted ) {
throwErrorTolerant ( firstRestricted , Messages . StrictOctalLiteral ) ;
}
} else {
if ( ! firstRestricted && token . octal ) {
firstRestricted = token ;
}
}
}
while ( index < length ) {
sourceElement = parseSourceElement ( ) ;
/* istanbul ignore if */
if ( typeof sourceElement === 'undefined' ) {
break ;
}
sourceElements . push ( sourceElement ) ;
}
return sourceElements ;
}
function parseProgram ( ) {
var body , startToken ;
skipComment ( ) ;
peek ( ) ;
startToken = lookahead ;
strict = false ;
body = parseSourceElements ( ) ;
return delegate . markEnd ( delegate . createProgram ( body ) , startToken ) ;
}
function filterTokenLocation ( ) {
var i , entry , token , tokens = [ ] ;
for ( i = 0 ; i < extra . tokens . length ; ++ i ) {
entry = extra . tokens [ i ] ;
token = {
type : entry . type ,
value : entry . value
} ;
if ( extra . range ) {
token . range = entry . range ;
}
if ( extra . loc ) {
token . loc = entry . loc ;
}
tokens . push ( token ) ;
}
extra . tokens = tokens ;
}
function tokenize ( code , options ) {
var toString ,
token ,
tokens ;
toString = String ;
if ( typeof code !== 'string' && ! ( code instanceof String ) ) {
code = toString ( code ) ;
}
delegate = SyntaxTreeDelegate ;
source = code ;
index = 0 ;
lineNumber = ( source . length > 0 ) ? 1 : 0 ;
lineStart = 0 ;
length = source . length ;
lookahead = null ;
state = {
allowIn : true ,
labelSet : { } ,
inFunctionBody : false ,
inIteration : false ,
inSwitch : false ,
lastCommentStart : - 1
} ;
extra = { } ;
// Options matching.
options = options || { } ;
// Of course we collect tokens here.
options . tokens = true ;
extra . tokens = [ ] ;
extra . tokenize = true ;
// The following two fields are necessary to compute the Regex tokens.
extra . openParenToken = - 1 ;
extra . openCurlyToken = - 1 ;
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 = [ ] ;
}
if ( typeof options . tolerant === 'boolean' && options . tolerant ) {
extra . errors = [ ] ;
}
try {
peek ( ) ;
if ( lookahead . type === Token . EOF ) {
return extra . tokens ;
}
token = lex ( ) ;
while ( lookahead . type !== Token . EOF ) {
try {
token = lex ( ) ;
} catch ( lexError ) {
token = lookahead ;
if ( extra . errors ) {
extra . errors . push ( lexError ) ;
// We have to break on the first error
// to avoid infinite loops.
break ;
} else {
throw lexError ;
}
}
}
filterTokenLocation ( ) ;
tokens = extra . tokens ;
if ( typeof extra . comments !== 'undefined' ) {
tokens . comments = extra . comments ;
}
if ( typeof extra . errors !== 'undefined' ) {
tokens . errors = extra . errors ;
}
} catch ( e ) {
throw e ;
} finally {
extra = { } ;
}
return tokens ;
}
function parse ( code , options ) {
var program , toString ;
toString = String ;
if ( typeof code !== 'string' && ! ( code instanceof String ) ) {
code = toString ( code ) ;
}
delegate = SyntaxTreeDelegate ;
source = code ;
index = 0 ;
lineNumber = ( source . length > 0 ) ? 1 : 0 ;
lineStart = 0 ;
length = source . length ;
lookahead = null ;
state = {
allowIn : true ,
labelSet : { } ,
inFunctionBody : false ,
inIteration : false ,
inSwitch : false ,
lastCommentStart : - 1
} ;
extra = { } ;
if ( typeof options !== 'undefined' ) {
extra . range = ( typeof options . range === 'boolean' ) && options . range ;
extra . loc = ( typeof options . loc === 'boolean' ) && options . loc ;
extra . attachComment = ( typeof options . attachComment === 'boolean' ) && options . attachComment ;
if ( extra . loc && options . source !== null && options . source !== undefined ) {
extra . source = toString ( options . source ) ;
}
if ( typeof options . tokens === 'boolean' && options . tokens ) {
extra . tokens = [ ] ;
}
if ( typeof options . comment === 'boolean' && options . comment ) {
extra . comments = [ ] ;
}
if ( typeof options . tolerant === 'boolean' && options . tolerant ) {
extra . errors = [ ] ;
}
if ( extra . attachComment ) {
extra . range = true ;
extra . comments = [ ] ;
extra . bottomRightStack = [ ] ;
extra . trailingComments = [ ] ;
extra . leadingComments = [ ] ;
}
}
try {
program = parseProgram ( ) ;
if ( typeof extra . comments !== 'undefined' ) {
program . comments = extra . comments ;
}
if ( typeof extra . tokens !== 'undefined' ) {
filterTokenLocation ( ) ;
program . tokens = extra . tokens ;
}
if ( typeof extra . errors !== 'undefined' ) {
program . errors = extra . errors ;
}
} catch ( e ) {
throw e ;
} finally {
extra = { } ;
}
return program ;
}
// Sync with *.json manifests.
exports . version = '1.2.2' ;
exports . tokenize = tokenize ;
exports . parse = parse ;
// Deep copy.
/* istanbul ignore next */
exports . Syntax = ( function ( ) {
var name , types = { } ;
if ( typeof Object . create === 'function' ) {
types = Object . create ( null ) ;
}
for ( name in Syntax ) {
if ( Syntax . hasOwnProperty ( name ) ) {
types [ name ] = Syntax [ name ] ;
}
}
if ( typeof Object . freeze === 'function' ) {
Object . freeze ( types ) ;
}
return types ;
} ( ) ) ;
} ) ) ;
/* vim: set sw=4 ts=4 et tw=80 : */
} ) ( null ) ;
/ * !
* falafel ( c ) James Halliday / MIT License
* https : //github.com/substack/node-falafel
* /
( function ( require , module ) {
var parse = require ( 'esprima' ) . parse ;
var objectKeys = Object . keys || function ( obj ) {
var keys = [ ] ;
for ( var key in obj ) keys . push ( key ) ;
return keys ;
} ;
var forEach = function ( xs , fn ) {
if ( xs . forEach ) return xs . forEach ( fn ) ;
for ( var i = 0 ; i < xs . length ; i ++ ) {
fn . call ( xs , xs [ i ] , i , xs ) ;
}
} ;
var isArray = Array . isArray || function ( xs ) {
return Object . prototype . toString . call ( xs ) === '[object Array]' ;
} ;
module . exports = function ( src , opts , fn ) {
if ( typeof opts === 'function' ) {
fn = opts ;
opts = { } ;
}
if ( typeof src === 'object' ) {
opts = src ;
src = opts . source ;
delete opts . source ;
}
src = src === undefined ? opts . source : src ;
opts . range = true ;
if ( typeof src !== 'string' ) src = String ( src ) ;
var ast = parse ( src , opts ) ;
var result = {
chunks : src . split ( '' ) ,
toString : function ( ) { return result . chunks . join ( '' ) } ,
inspect : function ( ) { return result . toString ( ) }
} ;
var index = 0 ;
( function walk ( node , parent ) {
insertHelpers ( node , parent , result . chunks ) ;
forEach ( objectKeys ( node ) , function ( key ) {
if ( key === 'parent' ) return ;
var child = node [ key ] ;
if ( isArray ( child ) ) {
forEach ( child , function ( c ) {
if ( c && typeof c . type === 'string' ) {
walk ( c , node ) ;
}
} ) ;
}
else if ( child && typeof child . type === 'string' ) {
insertHelpers ( child , node , result . chunks ) ;
walk ( child , node ) ;
}
} ) ;
fn ( node ) ;
} ) ( ast , undefined ) ;
return result ;
} ;
function insertHelpers ( node , parent , chunks ) {
if ( ! node . range ) return ;
node . parent = parent ;
node . source = function ( ) {
return chunks . slice (
node . range [ 0 ] , node . range [ 1 ]
) . join ( '' ) ;
} ;
if ( node . update && typeof node . update === 'object' ) {
var prev = node . update ;
forEach ( objectKeys ( prev ) , function ( key ) {
update [ key ] = prev [ key ] ;
} ) ;
node . update = update ;
}
else {
node . update = update ;
}
function update ( s ) {
chunks [ node . range [ 0 ] ] = s ;
for ( var i = node . range [ 0 ] + 1 ; i < node . range [ 1 ] ; i ++ ) {
chunks [ i ] = '' ;
}
} ;
}
window . falafel = module . exports ; } ) ( function ( ) { return { parse : esprima . parse } ; } , { exports : { } } ) ;
var inBrowser = typeof window !== 'undefined' && this === window ;
var parseAndModify = ( inBrowser ? window . falafel : require ( "falafel" ) ) ;
( inBrowser ? window : exports ) . blanket = ( function ( ) {
var linesToAddTracking = [
"ExpressionStatement" ,
"BreakStatement" ,
"ContinueStatement" ,
"VariableDeclaration" ,
"ReturnStatement" ,
"ThrowStatement" ,
"TryStatement" ,
"FunctionDeclaration" ,
"IfStatement" ,
"WhileStatement" ,
"DoWhileStatement" ,
"ForStatement" ,
"ForInStatement" ,
"SwitchStatement" ,
"WithStatement"
] ,
linesToAddBrackets = [
"IfStatement" ,
"WhileStatement" ,
"DoWhileStatement" ,
"ForStatement" ,
"ForInStatement" ,
"WithStatement"
] ,
_ _blanket ,
copynumber = Math . floor ( Math . random ( ) * 1000 ) ,
coverageInfo = { } , options = {
reporter : null ,
adapter : null ,
filter : null ,
customVariable : null ,
loader : null ,
ignoreScriptError : false ,
existingRequireJS : false ,
autoStart : false ,
timeout : 180 ,
ignoreCors : false ,
branchTracking : false ,
sourceURL : false ,
debug : false ,
engineOnly : false ,
testReadyCallback : null ,
commonJS : false ,
instrumentCache : false ,
modulePattern : null
} ;
if ( inBrowser && typeof window . blanket !== 'undefined' ) {
_ _blanket = window . blanket . noConflict ( ) ;
}
_blanket = {
noConflict : function ( ) {
if ( _ _blanket ) {
return _ _blanket ;
}
return _blanket ;
} ,
_getCopyNumber : function ( ) {
//internal method
//for differentiating between instances
return copynumber ;
} ,
extend : function ( obj ) {
//borrowed from underscore
_blanket . _extend ( _blanket , obj ) ;
} ,
_extend : function ( dest , source ) {
if ( source ) {
for ( var prop in source ) {
if ( dest [ prop ] instanceof Object && typeof dest [ prop ] !== "function" ) {
_blanket . _extend ( dest [ prop ] , source [ prop ] ) ;
} else {
dest [ prop ] = source [ prop ] ;
}
}
}
} ,
getCovVar : function ( ) {
var opt = _blanket . options ( "customVariable" ) ;
if ( opt ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Using custom tracking variable:" , opt ) ; }
return inBrowser ? "window." + opt : opt ;
}
return inBrowser ? "window._$blanket" : "_$jscoverage" ;
} ,
options : function ( key , value ) {
if ( typeof key !== "string" ) {
_blanket . _extend ( options , key ) ;
} else if ( typeof value === 'undefined' ) {
return options [ key ] ;
} else {
options [ key ] = value ;
}
} ,
instrument : function ( config , next ) {
//check instrumented hash table,
//return instrumented code if available.
var inFile = config . inputFile ,
inFileName = config . inputFileName ;
//check instrument cache
if ( _blanket . options ( "instrumentCache" ) && sessionStorage && sessionStorage . getItem ( "blanket_instrument_store-" + inFileName ) ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Reading instrumentation from cache: " , inFileName ) ; }
next ( sessionStorage . getItem ( "blanket_instrument_store-" + inFileName ) ) ;
} else {
var sourceArray = _blanket . _prepareSource ( inFile ) ;
_blanket . _trackingArraySetup = [ ] ;
//remove shebang
inFile = inFile . replace ( /^\#\!.*/ , "" ) ;
var instrumented = parseAndModify ( inFile , { loc : true , comment : true } , _blanket . _addTracking ( inFileName ) ) ;
instrumented = _blanket . _trackingSetup ( inFileName , sourceArray ) + instrumented ;
if ( _blanket . options ( "sourceURL" ) ) {
instrumented += "\n//@ sourceURL=" + inFileName . replace ( "http://" , "" ) ;
}
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Instrumented file: " , inFileName ) ; }
if ( _blanket . options ( "instrumentCache" ) && sessionStorage ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Saving instrumentation to cache: " , inFileName ) ; }
sessionStorage . setItem ( "blanket_instrument_store-" + inFileName , instrumented ) ;
}
next ( instrumented ) ;
}
} ,
_trackingArraySetup : [ ] ,
_branchingArraySetup : [ ] ,
_prepareSource : function ( source ) {
return source . replace ( /\\/g , "\\\\" ) . replace ( /'/g , "\\'" ) . replace ( /(\r\n|\n|\r)/gm , "\n" ) . split ( '\n' ) ;
} ,
_trackingSetup : function ( filename , sourceArray ) {
var branches = _blanket . options ( "branchTracking" ) ;
var sourceString = sourceArray . join ( "',\n'" ) ;
var intro = "" ;
var covVar = _blanket . getCovVar ( ) ;
intro += "if (typeof " + covVar + " === 'undefined') " + covVar + " = {};\n" ;
if ( branches ) {
intro += "var _$branchFcn=function(f,l,c,r){ " ;
intro += "if (!!r) { " ;
intro += covVar + "[f].branchData[l][c][0] = " + covVar + "[f].branchData[l][c][0] || [];" ;
intro += covVar + "[f].branchData[l][c][0].push(r); }" ;
intro += "else { " ;
intro += covVar + "[f].branchData[l][c][1] = " + covVar + "[f].branchData[l][c][1] || [];" ;
intro += covVar + "[f].branchData[l][c][1].push(r); }" ;
intro += "return r;};\n" ;
}
intro += "if (typeof " + covVar + "['" + filename + "'] === 'undefined'){" ;
intro += covVar + "['" + filename + "']=[];\n" ;
if ( branches ) {
intro += covVar + "['" + filename + "'].branchData=[];\n" ;
}
intro += covVar + "['" + filename + "'].source=['" + sourceString + "'];\n" ;
//initialize array values
_blanket . _trackingArraySetup . sort ( function ( a , b ) {
return parseInt ( a , 10 ) > parseInt ( b , 10 ) ;
} ) . forEach ( function ( item ) {
intro += covVar + "['" + filename + "'][" + item + "]=0;\n" ;
} ) ;
if ( branches ) {
_blanket . _branchingArraySetup . sort ( function ( a , b ) {
return a . line > b . line ;
} ) . sort ( function ( a , b ) {
return a . column > b . column ;
} ) . forEach ( function ( item ) {
if ( item . file === filename ) {
intro += "if (typeof " + covVar + "['" + filename + "'].branchData[" + item . line + "] === 'undefined'){\n" ;
intro += covVar + "['" + filename + "'].branchData[" + item . line + "]=[];\n" ;
intro += "}" ;
intro += covVar + "['" + filename + "'].branchData[" + item . line + "][" + item . column + "] = [];\n" ;
intro += covVar + "['" + filename + "'].branchData[" + item . line + "][" + item . column + "].consequent = " + JSON . stringify ( item . consequent ) + ";\n" ;
intro += covVar + "['" + filename + "'].branchData[" + item . line + "][" + item . column + "].alternate = " + JSON . stringify ( item . alternate ) + ";\n" ;
}
} ) ;
}
intro += "}" ;
return intro ;
} ,
_blockifyIf : function ( node ) {
if ( linesToAddBrackets . indexOf ( node . type ) > - 1 ) {
var bracketsExistObject = node . consequent || node . body ;
var bracketsExistAlt = node . alternate ;
if ( bracketsExistAlt && bracketsExistAlt . type !== "BlockStatement" ) {
bracketsExistAlt . update ( "{\n" + bracketsExistAlt . source ( ) + "}\n" ) ;
}
if ( bracketsExistObject && bracketsExistObject . type !== "BlockStatement" ) {
bracketsExistObject . update ( "{\n" + bracketsExistObject . source ( ) + "}\n" ) ;
}
}
} ,
_trackBranch : function ( node , filename ) {
//recursive on consequent and alternative
var line = node . loc . start . line ;
var col = node . loc . start . column ;
_blanket . _branchingArraySetup . push ( {
line : line ,
column : col ,
file : filename ,
consequent : node . consequent . loc ,
alternate : node . alternate . loc
} ) ;
var updated = "_$branchFcn" +
"('" + filename + "'," + line + "," + col + "," + node . test . source ( ) +
")?" + node . consequent . source ( ) + ":" + node . alternate . source ( ) ;
node . update ( updated ) ;
} ,
_addTracking : function ( filename ) {
//falafel doesn't take a file name
//so we include the filename in a closure
//and return the function to falafel
var covVar = _blanket . getCovVar ( ) ;
return function ( node ) {
_blanket . _blockifyIf ( node ) ;
if ( linesToAddTracking . indexOf ( node . type ) > - 1 && node . parent . type !== "LabeledStatement" ) {
_blanket . _checkDefs ( node , filename ) ;
if ( node . type === "VariableDeclaration" &&
( node . parent . type === "ForStatement" || node . parent . type === "ForInStatement" ) ) {
return ;
}
if ( node . loc && node . loc . start ) {
node . update ( covVar + "['" + filename + "'][" + node . loc . start . line + "]++;\n" + node . source ( ) ) ;
_blanket . _trackingArraySetup . push ( node . loc . start . line ) ;
} else {
//I don't think we can handle a node with no location
throw new Error ( "The instrumenter encountered a node with no location: " + Object . keys ( node ) ) ;
}
} else if ( _blanket . options ( "branchTracking" ) && node . type === "ConditionalExpression" ) {
_blanket . _trackBranch ( node , filename ) ;
}
} ;
} ,
_checkDefs : function ( node , filename ) {
// Make sure developers don't redefine window. if they do, inform them it is wrong.
if ( inBrowser ) {
if ( node . type === "VariableDeclaration" && node . declarations ) {
node . declarations . forEach ( function ( declaration ) {
if ( declaration . id . name === "window" ) {
throw new Error ( "Instrumentation error, you cannot redefine the 'window' variable in " + filename + ":" + node . loc . start . line ) ;
}
} ) ;
}
if ( node . type === "FunctionDeclaration" && node . params ) {
node . params . forEach ( function ( param ) {
if ( param . name === "window" ) {
throw new Error ( "Instrumentation error, you cannot redefine the 'window' variable in " + filename + ":" + node . loc . start . line ) ;
}
} ) ;
}
//Make sure developers don't redefine the coverage variable
if ( node . type === "ExpressionStatement" &&
node . expression && node . expression . left &&
node . expression . left . object && node . expression . left . property &&
node . expression . left . object . name +
"." + node . expression . left . property . name === _blanket . getCovVar ( ) ) {
throw new Error ( "Instrumentation error, you cannot redefine the coverage variable in " + filename + ":" + node . loc . start . line ) ;
}
} else {
//Make sure developers don't redefine the coverage variable in node
if ( node . type === "ExpressionStatement" &&
node . expression && node . expression . left &&
! node . expression . left . object && ! node . expression . left . property &&
node . expression . left . name === _blanket . getCovVar ( ) ) {
throw new Error ( "Instrumentation error, you cannot redefine the coverage variable in " + filename + ":" + node . loc . start . line ) ;
}
}
} ,
setupCoverage : function ( ) {
coverageInfo . instrumentation = "blanket" ;
coverageInfo . stats = {
"suites" : 0 ,
"tests" : 0 ,
"passes" : 0 ,
"pending" : 0 ,
"failures" : 0 ,
"start" : new Date ( )
} ;
} ,
_checkIfSetup : function ( ) {
if ( ! coverageInfo . stats ) {
throw new Error ( "You must call blanket.setupCoverage() first." ) ;
}
} ,
onTestStart : function ( ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Test event started" ) ; }
this . _checkIfSetup ( ) ;
coverageInfo . stats . tests ++ ;
coverageInfo . stats . pending ++ ;
} ,
onTestDone : function ( total , passed ) {
this . _checkIfSetup ( ) ;
if ( passed === total ) {
coverageInfo . stats . passes ++ ;
} else {
coverageInfo . stats . failures ++ ;
}
coverageInfo . stats . pending -- ;
} ,
onModuleStart : function ( ) {
this . _checkIfSetup ( ) ;
coverageInfo . stats . suites ++ ;
} ,
onTestsDone : function ( ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Test event done" ) ; }
this . _checkIfSetup ( ) ;
coverageInfo . stats . end = new Date ( ) ;
if ( inBrowser ) {
this . report ( coverageInfo ) ;
} else {
if ( ! _blanket . options ( "branchTracking" ) ) {
delete ( inBrowser ? window : global ) [ _blanket . getCovVar ( ) ] . branchFcn ;
}
this . options ( "reporter" ) . call ( this , coverageInfo ) ;
}
}
} ;
return _blanket ;
} ) ( ) ;
( function ( _blanket ) {
var oldOptions = _blanket . options ;
_blanket . extend ( {
outstandingRequireFiles : [ ] ,
options : function ( key , value ) {
var newVal = { } ;
if ( typeof key !== "string" ) {
//key is key/value map
oldOptions ( key ) ;
newVal = key ;
} else if ( typeof value === 'undefined' ) {
//accessor
return oldOptions ( key ) ;
} else {
//setter
oldOptions ( key , value ) ;
newVal [ key ] = value ;
}
if ( newVal . adapter ) {
_blanket . _loadFile ( newVal . adapter ) ;
}
if ( newVal . loader ) {
_blanket . _loadFile ( newVal . loader ) ;
}
} ,
requiringFile : function ( filename , done ) {
if ( typeof filename === "undefined" ) {
_blanket . outstandingRequireFiles = [ ] ;
} else if ( typeof done === "undefined" ) {
_blanket . outstandingRequireFiles . push ( filename ) ;
} else {
_blanket . outstandingRequireFiles . splice ( _blanket . outstandingRequireFiles . indexOf ( filename ) , 1 ) ;
}
} ,
requireFilesLoaded : function ( ) {
return _blanket . outstandingRequireFiles . length === 0 ;
} ,
showManualLoader : function ( ) {
if ( document . getElementById ( "blanketLoaderDialog" ) ) {
return ;
}
//copied from http://blog.avtex.com/2012/01/26/cross-browser-css-only-modal-box/
var loader = "<div class='blanketDialogOverlay'>" ;
loader += " </div>" ;
loader += "<div class='blanketDialogVerticalOffset'>" ;
loader += "<div class='blanketDialogBox'>" ;
loader += "<b>Error:</b> Blanket.js encountered a cross origin request error while instrumenting the source files. " ;
loader += "<br><br>This is likely caused by the source files being referenced locally (using the file:// protocol). " ;
loader += "<br><br>Some solutions include <a href='http://askubuntu.com/questions/160245/making-google-chrome-option-allow-file-access-from-files-permanent' target='_blank'>starting Chrome with special flags</a>, <a target='_blank' href='https://github.com/remy/servedir'>running a server locally</a>, or using a browser without these CORS restrictions (Safari)." ;
loader += "<br>" ;
if ( typeof FileReader !== "undefined" ) {
loader += "<br>Or, try the experimental loader. When prompted, simply click on the directory containing all the source files you want covered." ;
loader += "<a href='javascript:document.getElementById(\"fileInput\").click();'>Start Loader</a>" ;
loader += "<input type='file' type='application/x-javascript' accept='application/x-javascript' webkitdirectory id='fileInput' multiple onchange='window.blanket.manualFileLoader(this.files)' style='visibility:hidden;position:absolute;top:-50;left:-50'/>" ;
}
loader += "<br><span style='float:right;cursor:pointer;' onclick=document.getElementById('blanketLoaderDialog').style.display='none';>Close</span>" ;
loader += "<div style='clear:both'></div>" ;
loader += "</div></div>" ;
var css = ".blanketDialogWrapper {" ;
css += "display:block;" ;
css += "position:fixed;" ;
css += "z-index:40001; }" ;
css += ".blanketDialogOverlay {" ;
css += "position:fixed;" ;
css += "width:100%;" ;
css += "height:100%;" ;
css += "background-color:black;" ;
css += "opacity:.5; " ;
css += "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)'; " ;
css += "filter:alpha(opacity=50); " ;
css += "z-index:40001; }" ;
css += ".blanketDialogVerticalOffset { " ;
css += "position:fixed;" ;
css += "top:30%;" ;
css += "width:100%;" ;
css += "z-index:40002; }" ;
css += ".blanketDialogBox { " ;
css += "width:405px; " ;
css += "position:relative;" ;
css += "margin:0 auto;" ;
css += "background-color:white;" ;
css += "padding:10px;" ;
css += "border:1px solid black; }" ;
var dom = document . createElement ( "style" ) ;
dom . innerHTML = css ;
document . head . appendChild ( dom ) ;
var div = document . createElement ( "div" ) ;
div . id = "blanketLoaderDialog" ;
div . className = "blanketDialogWrapper" ;
div . innerHTML = loader ;
document . body . insertBefore ( div , document . body . firstChild ) ;
} ,
manualFileLoader : function ( files ) {
var toArray = Array . prototype . slice ;
files = toArray . call ( files ) . filter ( function ( item ) {
return item . type !== "" ;
} ) ;
var sessionLength = files . length - 1 ;
var sessionIndx = 0 ;
var sessionArray = { } ;
if ( sessionStorage [ "blanketSessionLoader" ] ) {
sessionArray = JSON . parse ( sessionStorage [ "blanketSessionLoader" ] ) ;
}
var fileLoader = function ( event ) {
var fileContent = event . currentTarget . result ;
var file = files [ sessionIndx ] ;
var filename = file . webkitRelativePath && file . webkitRelativePath !== '' ? file . webkitRelativePath : file . name ;
sessionArray [ filename ] = fileContent ;
sessionIndx ++ ;
if ( sessionIndx === sessionLength ) {
sessionStorage . setItem ( "blanketSessionLoader" , JSON . stringify ( sessionArray ) ) ;
document . location . reload ( ) ;
} else {
readFile ( files [ sessionIndx ] ) ;
}
} ;
function readFile ( file ) {
var reader = new FileReader ( ) ;
reader . onload = fileLoader ;
reader . readAsText ( file ) ;
}
readFile ( files [ sessionIndx ] ) ;
} ,
_loadFile : function ( path ) {
if ( typeof path !== "undefined" ) {
var request = new XMLHttpRequest ( ) ;
request . open ( 'GET' , path , false ) ;
request . send ( ) ;
_blanket . _addScript ( request . responseText ) ;
}
} ,
_addScript : function ( data ) {
/ * v a r s c r i p t = d o c u m e n t . c r e a t e E l e m e n t ( " s c r i p t " ) ;
script . type = "text/javascript" ;
script . text = data ;
( document . body || document . getElementsByTagName ( 'head' ) [ 0 ] ) . appendChild ( script ) ; * /
( 1 , eval ) ( data ) ;
} ,
hasAdapter : function ( callback ) {
return _blanket . options ( "adapter" ) !== null ;
} ,
report : function ( coverage _data ) {
if ( ! document . getElementById ( "blanketLoaderDialog" ) ) {
//all found, clear it
_blanket . blanketSession = null ;
}
coverage _data . files = window . _$blanket ;
var require = blanket . options ( "commonJS" ) ? blanket . _commonjs . require : window . require ;
// Check if we have any covered files that requires reporting
// otherwise just exit gracefully.
if ( ! coverage _data . files || ! Object . keys ( coverage _data . files ) . length ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Reporting No files were instrumented." ) ; }
return ;
}
if ( typeof coverage _data . files . branchFcn !== "undefined" ) {
delete coverage _data . files . branchFcn ;
}
if ( typeof _blanket . options ( "reporter" ) === "string" ) {
_blanket . _loadFile ( _blanket . options ( "reporter" ) ) ;
_blanket . customReporter ( coverage _data , _blanket . options ( "reporter_options" ) ) ;
} else if ( typeof _blanket . options ( "reporter" ) === "function" ) {
_blanket . options ( "reporter" ) ( coverage _data , _blanket . options ( "reporter_options" ) ) ;
} else if ( typeof _blanket . defaultReporter === 'function' ) {
_blanket . defaultReporter ( coverage _data , _blanket . options ( "reporter_options" ) ) ;
} else {
throw new Error ( "no reporter defined." ) ;
}
} ,
_bindStartTestRunner : function ( bindEvent , startEvent ) {
if ( bindEvent ) {
bindEvent ( startEvent ) ;
} else {
window . addEventListener ( "load" , startEvent , false ) ;
}
} ,
_loadSourceFiles : function ( callback ) {
var require = blanket . options ( "commonJS" ) ? blanket . _commonjs . require : window . require ;
function copy ( o ) {
var _copy = Object . create ( Object . getPrototypeOf ( o ) ) ;
var propNames = Object . getOwnPropertyNames ( o ) ;
propNames . forEach ( function ( name ) {
var desc = Object . getOwnPropertyDescriptor ( o , name ) ;
Object . defineProperty ( _copy , name , desc ) ;
} ) ;
return _copy ;
}
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Collecting page scripts" ) ; }
var scripts = _blanket . utils . collectPageScripts ( ) ;
//_blanket.options("filter",scripts);
if ( scripts . length === 0 ) {
callback ( ) ;
} else {
//check session state
if ( sessionStorage [ "blanketSessionLoader" ] ) {
_blanket . blanketSession = JSON . parse ( sessionStorage [ "blanketSessionLoader" ] ) ;
}
scripts . forEach ( function ( file , indx ) {
_blanket . utils . cache [ file ] = {
loaded : false
} ;
} ) ;
var currScript = - 1 ;
_blanket . utils . loadAll ( function ( test ) {
if ( test ) {
return typeof scripts [ currScript + 1 ] !== 'undefined' ;
}
currScript ++ ;
if ( currScript >= scripts . length ) {
return null ;
}
return scripts [ currScript ] ;
} , callback ) ;
}
} ,
beforeStartTestRunner : function ( opts ) {
opts = opts || { } ;
opts . checkRequirejs = typeof opts . checkRequirejs === "undefined" ? true : opts . checkRequirejs ;
opts . callback = opts . callback || function ( ) { } ;
opts . coverage = typeof opts . coverage === "undefined" ? true : opts . coverage ;
if ( opts . coverage ) {
_blanket . _bindStartTestRunner ( opts . bindEvent ,
function ( ) {
_blanket . _loadSourceFiles ( function ( ) {
var allLoaded = function ( ) {
return opts . condition ? opts . condition ( ) : _blanket . requireFilesLoaded ( ) ;
} ;
var check = function ( ) {
if ( allLoaded ( ) ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-All files loaded, init start test runner callback." ) ; }
var cb = _blanket . options ( "testReadyCallback" ) ;
if ( cb ) {
if ( typeof cb === "function" ) {
cb ( opts . callback ) ;
} else if ( typeof cb === "string" ) {
_blanket . _addScript ( cb ) ;
opts . callback ( ) ;
}
} else {
opts . callback ( ) ;
}
} else {
setTimeout ( check , 13 ) ;
}
} ;
check ( ) ;
} ) ;
} ) ;
} else {
opts . callback ( ) ;
}
} ,
utils : {
qualifyURL : function ( url ) {
//http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
var a = document . createElement ( 'a' ) ;
a . href = url ;
return a . href ;
}
}
} ) ;
} ) ( blanket ) ;
blanket . defaultReporter = function ( coverage ) {
var cssSytle = "#blanket-main {margin:2px;background:#EEE;color:#333;clear:both;font-family:'Helvetica Neue Light', 'HelveticaNeue-Light', 'Helvetica Neue', Calibri, Helvetica, Arial, sans-serif; font-size:17px;} #blanket-main a {color:#333;text-decoration:none;} #blanket-main a:hover {text-decoration:underline;} .blanket {margin:0;padding:5px;clear:both;border-bottom: 1px solid #FFFFFF;} .bl-error {color:red;}.bl-success {color:#5E7D00;} .bl-file{width:auto;} .bl-cl{float:left;} .blanket div.rs {margin-left:50px; width:150px; float:right} .bl-nb {padding-right:10px;} #blanket-main a.bl-logo {color: #EB1764;cursor: pointer;font-weight: bold;text-decoration: none} .bl-source{ overflow-x:scroll; background-color: #FFFFFF; border: 1px solid #CBCBCB; color: #363636; margin: 25px 20px; width: 80%;} .bl-source div{white-space: pre;font-family: monospace;} .bl-source > div > span:first-child{background-color: #EAEAEA;color: #949494;display: inline-block;padding: 0 10px;text-align: center;width: 30px;} .bl-source .miss{background-color:#e6c3c7} .bl-source span.branchWarning{color:#000;background-color:yellow;} .bl-source span.branchOkay{color:#000;background-color:transparent;}" ,
successRate = 60 ,
head = document . head ,
fileNumber = 0 ,
body = document . body ,
headerContent ,
hasBranchTracking = Object . keys ( coverage . files ) . some ( function ( elem ) {
return typeof coverage . files [ elem ] . branchData !== 'undefined' ;
} ) ,
bodyContent = "<div id='blanket-main'><div class='blanket bl-title'><div class='bl-cl bl-file'><a href='http://alex-seville.github.com/blanket/' target='_blank' class='bl-logo'>Blanket.js</a> results</div><div class='bl-cl rs'>Coverage (%)</div><div class='bl-cl rs'>Covered/Total Smts.</div>" + ( hasBranchTracking ? "<div class='bl-cl rs'>Covered/Total Branches</div>" : "" ) + "<div style='clear:both;'></div></div>" ,
fileTemplate = "<div class='blanket {{statusclass}}'><div class='bl-cl bl-file'><span class='bl-nb'>{{fileNumber}}.</span><a id='blanket-link-file-{{fileNumber}}' href='javascript:void(0)'>{{file}}</a></div><div class='bl-cl rs'>{{percentage}} %</div><div class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</div>" + ( hasBranchTracking ? "<div class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</div>" : "" ) + "<div id='file-{{fileNumber}}' class='bl-source' style='display:none;'>{{source}}</div><div style='clear:both;'></div></div>" ;
grandTotalTemplate = "<div class='blanket grand-total {{statusclass}}'><div class='bl-cl'>{{rowTitle}}</div><div class='bl-cl rs'>{{percentage}} %</div><div class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</div>" + ( hasBranchTracking ? "<div class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</div>" : "" ) + "<div style='clear:both;'></div></div>" ;
function blanket _toggleSource ( id ) {
var element = document . getElementById ( id ) ;
if ( element . style . display === 'block' ) {
element . style . display = 'none' ;
} else {
element . style . display = 'block' ;
}
}
/ * v a r s c r i p t = d o c u m e n t . c r e a t e E l e m e n t ( " s c r i p t " ) ;
script . type = "text/javascript" ;
script . text = blanket _toggleSource . toString ( ) . replace ( 'function ' + blanket _toggleSource . name , 'function blanket_toggleSource' ) ;
body . appendChild ( script ) ; * /
( 1 , eval ) ( blanket _toggleSource . toString ( ) . replace ( 'function ' + blanket _toggleSource . name , 'function blanket_toggleSource' ) ) ;
var percentage = function ( number , total ) {
return ( Math . round ( ( ( number / total ) * 100 ) * 100 ) / 100 ) ;
} ;
var appendTag = function ( type , el , str ) {
var dom = document . createElement ( type ) ;
dom . innerHTML = str ;
el . appendChild ( dom ) ;
} ;
function escapeInvalidXmlChars ( str ) {
return str . replace ( /\&/g , "&" )
. replace ( /</g , "<" )
. replace ( /\>/g , ">" )
. replace ( /\"/g , """ )
. replace ( /\'/g , "'" ) ;
}
function isBranchFollowed ( data , bool ) {
var mode = bool ? 0 : 1 ;
if ( typeof data === 'undefined' ||
typeof data === null ||
typeof data [ mode ] === 'undefined' ) {
return false ;
}
return data [ mode ] . length > 0 ;
}
var branchStack = [ ] ;
function branchReport ( colsIndex , src , cols , offset , lineNum ) {
var newsrc = "" ;
var postfix = "" ;
if ( branchStack . length > 0 ) {
newsrc += "<span class='" + ( isBranchFollowed ( branchStack [ 0 ] [ 1 ] , branchStack [ 0 ] [ 1 ] . consequent === branchStack [ 0 ] [ 0 ] ) ? 'branchOkay' : 'branchWarning' ) + "'>" ;
if ( branchStack [ 0 ] [ 0 ] . end . line === lineNum ) {
newsrc += escapeInvalidXmlChars ( src . slice ( 0 , branchStack [ 0 ] [ 0 ] . end . column ) ) + "</span>" ;
src = src . slice ( branchStack [ 0 ] [ 0 ] . end . column ) ;
branchStack . shift ( ) ;
if ( branchStack . length > 0 ) {
newsrc += "<span class='" + ( isBranchFollowed ( branchStack [ 0 ] [ 1 ] , false ) ? 'branchOkay' : 'branchWarning' ) + "'>" ;
if ( branchStack [ 0 ] [ 0 ] . end . line === lineNum ) {
newsrc += escapeInvalidXmlChars ( src . slice ( 0 , branchStack [ 0 ] [ 0 ] . end . column ) ) + "</span>" ;
src = src . slice ( branchStack [ 0 ] [ 0 ] . end . column ) ;
branchStack . shift ( ) ;
if ( ! cols ) {
return { src : newsrc + escapeInvalidXmlChars ( src ) , cols : cols } ;
}
}
else if ( ! cols ) {
return { src : newsrc + escapeInvalidXmlChars ( src ) + "</span>" , cols : cols } ;
}
else {
postfix = "</span>" ;
}
} else if ( ! cols ) {
return { src : newsrc + escapeInvalidXmlChars ( src ) , cols : cols } ;
}
} else if ( ! cols ) {
return { src : newsrc + escapeInvalidXmlChars ( src ) + "</span>" , cols : cols } ;
} else {
postfix = "</span>" ;
}
}
var thisline = cols [ colsIndex ] ;
//consequent
var cons = thisline . consequent ;
if ( cons . start . line > lineNum ) {
branchStack . unshift ( [ thisline . alternate , thisline ] ) ;
branchStack . unshift ( [ cons , thisline ] ) ;
src = escapeInvalidXmlChars ( src ) ;
} else {
var style = "<span class='" + ( isBranchFollowed ( thisline , true ) ? 'branchOkay' : 'branchWarning' ) + "'>" ;
newsrc += escapeInvalidXmlChars ( src . slice ( 0 , cons . start . column - offset ) ) + style ;
if ( cols . length > colsIndex + 1 &&
cols [ colsIndex + 1 ] . consequent . start . line === lineNum &&
cols [ colsIndex + 1 ] . consequent . start . column - offset < cols [ colsIndex ] . consequent . end . column - offset )
{
var res = branchReport ( colsIndex + 1 , src . slice ( cons . start . column - offset , cons . end . column - offset ) , cols , cons . start . column - offset , lineNum ) ;
newsrc += res . src ;
cols = res . cols ;
cols [ colsIndex + 1 ] = cols [ colsIndex + 2 ] ;
cols . length -- ;
} else {
newsrc += escapeInvalidXmlChars ( src . slice ( cons . start . column - offset , cons . end . column - offset ) ) ;
}
newsrc += "</span>" ;
var alt = thisline . alternate ;
if ( alt . start . line > lineNum ) {
newsrc += escapeInvalidXmlChars ( src . slice ( cons . end . column - offset ) ) ;
branchStack . unshift ( [ alt , thisline ] ) ;
} else {
newsrc += escapeInvalidXmlChars ( src . slice ( cons . end . column - offset , alt . start . column - offset ) ) ;
style = "<span class='" + ( isBranchFollowed ( thisline , false ) ? 'branchOkay' : 'branchWarning' ) + "'>" ;
newsrc += style ;
if ( cols . length > colsIndex + 1 &&
cols [ colsIndex + 1 ] . consequent . start . line === lineNum &&
cols [ colsIndex + 1 ] . consequent . start . column - offset < cols [ colsIndex ] . alternate . end . column - offset )
{
var res2 = branchReport ( colsIndex + 1 , src . slice ( alt . start . column - offset , alt . end . column - offset ) , cols , alt . start . column - offset , lineNum ) ;
newsrc += res2 . src ;
cols = res2 . cols ;
cols [ colsIndex + 1 ] = cols [ colsIndex + 2 ] ;
cols . length -- ;
} else {
newsrc += escapeInvalidXmlChars ( src . slice ( alt . start . column - offset , alt . end . column - offset ) ) ;
}
newsrc += "</span>" ;
newsrc += escapeInvalidXmlChars ( src . slice ( alt . end . column - offset ) ) ;
src = newsrc ;
}
}
return { src : src + postfix , cols : cols } ;
}
var isUndefined = function ( item ) {
return typeof item !== 'undefined' ;
} ;
var files = coverage . files ;
var totals = {
totalSmts : 0 ,
numberOfFilesCovered : 0 ,
passedBranches : 0 ,
totalBranches : 0 ,
moduleTotalStatements : { } ,
moduleTotalCoveredStatements : { } ,
moduleTotalBranches : { } ,
moduleTotalCoveredBranches : { }
} ;
// check if a data-cover-modulepattern was provided for per-module coverage reporting
var modulePattern = _blanket . options ( "modulePattern" ) ;
var modulePatternRegex = ( modulePattern ? new RegExp ( modulePattern ) : null ) ;
for ( var file in files )
{
if ( ! files . hasOwnProperty ( file ) ) {
continue ;
}
fileNumber ++ ;
var statsForFile = files [ file ] ,
totalSmts = 0 ,
numberOfFilesCovered = 0 ,
code = [ ] ,
i ;
var end = [ ] ;
for ( i = 0 ; i < statsForFile . source . length ; i += 1 ) {
var src = statsForFile . source [ i ] ;
if ( branchStack . length > 0 ||
typeof statsForFile . branchData !== 'undefined' )
{
if ( typeof statsForFile . branchData [ i + 1 ] !== 'undefined' )
{
var cols = statsForFile . branchData [ i + 1 ] . filter ( isUndefined ) ;
var colsIndex = 0 ;
src = branchReport ( colsIndex , src , cols , 0 , i + 1 ) . src ;
} else if ( branchStack . length ) {
src = branchReport ( 0 , src , null , 0 , i + 1 ) . src ;
} else {
src = escapeInvalidXmlChars ( src ) ;
}
} else {
src = escapeInvalidXmlChars ( src ) ;
}
var lineClass = "" ;
if ( statsForFile [ i + 1 ] ) {
numberOfFilesCovered += 1 ;
totalSmts += 1 ;
lineClass = 'hit' ;
} else {
if ( statsForFile [ i + 1 ] === 0 ) {
totalSmts ++ ;
lineClass = 'miss' ;
}
}
code [ i + 1 ] = "<div class='" + lineClass + "'><span class=''>" + ( i + 1 ) + "</span>" + src + "</div>" ;
}
totals . totalSmts += totalSmts ;
totals . numberOfFilesCovered += numberOfFilesCovered ;
var totalBranches = 0 ;
var passedBranches = 0 ;
if ( typeof statsForFile . branchData !== 'undefined' ) {
for ( var j = 0 ; j < statsForFile . branchData . length ; j ++ ) {
if ( typeof statsForFile . branchData [ j ] !== 'undefined' ) {
for ( var k = 0 ; k < statsForFile . branchData [ j ] . length ; k ++ ) {
if ( typeof statsForFile . branchData [ j ] [ k ] !== 'undefined' ) {
totalBranches ++ ;
if ( typeof statsForFile . branchData [ j ] [ k ] [ 0 ] !== 'undefined' &&
statsForFile . branchData [ j ] [ k ] [ 0 ] . length > 0 &&
typeof statsForFile . branchData [ j ] [ k ] [ 1 ] !== 'undefined' &&
statsForFile . branchData [ j ] [ k ] [ 1 ] . length > 0 ) {
passedBranches ++ ;
}
}
}
}
}
}
totals . passedBranches += passedBranches ;
totals . totalBranches += totalBranches ;
// if "data-cover-modulepattern" was provided,
// track totals per module name as well as globally
if ( modulePatternRegex ) {
var moduleName = file . match ( modulePatternRegex ) [ 1 ] ;
if ( ! totals . moduleTotalStatements . hasOwnProperty ( moduleName ) ) {
totals . moduleTotalStatements [ moduleName ] = 0 ;
totals . moduleTotalCoveredStatements [ moduleName ] = 0 ;
}
totals . moduleTotalStatements [ moduleName ] += totalSmts ;
totals . moduleTotalCoveredStatements [ moduleName ] += numberOfFilesCovered ;
if ( ! totals . moduleTotalBranches . hasOwnProperty ( moduleName ) ) {
totals . moduleTotalBranches [ moduleName ] = 0 ;
totals . moduleTotalCoveredBranches [ moduleName ] = 0 ;
}
totals . moduleTotalBranches [ moduleName ] += totalBranches ;
totals . moduleTotalCoveredBranches [ moduleName ] += passedBranches ;
}
var result = percentage ( numberOfFilesCovered , totalSmts ) ;
var output = fileTemplate . replace ( "{{file}}" , file )
. replace ( "{{percentage}}" , result )
. replace ( "{{numberCovered}}" , numberOfFilesCovered )
. replace ( /\{\{fileNumber\}\}/g , fileNumber )
. replace ( "{{totalSmts}}" , totalSmts )
. replace ( "{{totalBranches}}" , totalBranches )
. replace ( "{{passedBranches}}" , passedBranches )
. replace ( "{{source}}" , code . join ( " " ) ) ;
if ( result < successRate )
{
output = output . replace ( "{{statusclass}}" , "bl-error" ) ;
} else {
output = output . replace ( "{{statusclass}}" , "bl-success" ) ;
}
bodyContent += output ;
}
// create temporary function for use by the global totals reporter,
// as well as the per-module totals reporter
var createAggregateTotal = function ( numSt , numCov , numBranch , numCovBr , moduleName ) {
var totalPercent = percentage ( numCov , numSt ) ;
var statusClass = totalPercent < successRate ? "bl-error" : "bl-success" ;
var rowTitle = ( moduleName ? "Total for module: " + moduleName : "Global total" ) ;
var totalsOutput = grandTotalTemplate . replace ( "{{rowTitle}}" , rowTitle )
. replace ( "{{percentage}}" , totalPercent )
. replace ( "{{numberCovered}}" , numCov )
. replace ( "{{totalSmts}}" , numSt )
. replace ( "{{passedBranches}}" , numCovBr )
. replace ( "{{totalBranches}}" , numBranch )
. replace ( "{{statusclass}}" , statusClass ) ;
bodyContent += totalsOutput ;
} ;
// if "data-cover-modulepattern" was provided,
// output the per-module totals alongside the global totals
if ( modulePatternRegex ) {
for ( var thisModuleName in totals . moduleTotalStatements ) {
if ( totals . moduleTotalStatements . hasOwnProperty ( thisModuleName ) ) {
var moduleTotalSt = totals . moduleTotalStatements [ thisModuleName ] ;
var moduleTotalCovSt = totals . moduleTotalCoveredStatements [ thisModuleName ] ;
var moduleTotalBr = totals . moduleTotalBranches [ thisModuleName ] ;
var moduleTotalCovBr = totals . moduleTotalCoveredBranches [ thisModuleName ] ;
createAggregateTotal ( moduleTotalSt , moduleTotalCovSt , moduleTotalBr , moduleTotalCovBr , thisModuleName ) ;
}
}
}
createAggregateTotal ( totals . totalSmts , totals . numberOfFilesCovered , totals . totalBranches , totals . passedBranches , null ) ;
bodyContent += "</div>" ; //closing main
appendTag ( 'style' , head , cssSytle ) ;
//appendStyle(body, headerContent);
if ( document . getElementById ( "blanket-main" ) ) {
document . getElementById ( "blanket-main" ) . innerHTML =
bodyContent . slice ( 23 , - 6 ) ;
} else {
appendTag ( 'div' , body , bodyContent ) ;
}
fileNumber = 0 ;
for ( var file in files ) {
if ( ! files . hasOwnProperty ( file ) ) {
continue ;
}
fileNumber ++ ;
var _ = function ( ) {
var localFN = fileNumber ;
$ ( "#blanket-link-file-" + fileNumber ) . click ( function ( ) {
blanket _toggleSource ( "file-" + localFN ) ;
} ) ;
} ( ) ;
}
//appendHtml(body, '</div>');
} ;
( function ( ) {
var newOptions = { } ;
//http://stackoverflow.com/a/2954896
var toArray = Array . prototype . slice ;
var scripts = toArray . call ( document . scripts ) ;
toArray . call ( scripts [ scripts . length - 1 ] . attributes )
. forEach ( function ( es ) {
if ( es . nodeName === "data-cover-only" ) {
newOptions . filter = es . nodeValue ;
}
if ( es . nodeName === "data-cover-never" ) {
newOptions . antifilter = es . nodeValue ;
}
if ( es . nodeName === "data-cover-reporter" ) {
newOptions . reporter = es . nodeValue ;
}
if ( es . nodeName === "data-cover-adapter" ) {
newOptions . adapter = es . nodeValue ;
}
if ( es . nodeName === "data-cover-loader" ) {
newOptions . loader = es . nodeValue ;
}
if ( es . nodeName === "data-cover-timeout" ) {
newOptions . timeout = es . nodeValue ;
}
if ( es . nodeName === "data-cover-modulepattern" ) {
newOptions . modulePattern = es . nodeValue ;
}
if ( es . nodeName === "data-cover-reporter-options" ) {
try {
newOptions . reporter _options = JSON . parse ( es . nodeValue ) ;
} catch ( e ) {
if ( blanket . options ( "debug" ) ) {
throw new Error ( "Invalid reporter options. Must be a valid stringified JSON object." ) ;
}
}
}
if ( es . nodeName === "data-cover-testReadyCallback" ) {
newOptions . testReadyCallback = es . nodeValue ;
}
if ( es . nodeName === "data-cover-customVariable" ) {
newOptions . customVariable = es . nodeValue ;
}
if ( es . nodeName === "data-cover-flags" ) {
var flags = " " + es . nodeValue + " " ;
if ( flags . indexOf ( " ignoreError " ) > - 1 ) {
newOptions . ignoreScriptError = true ;
}
if ( flags . indexOf ( " autoStart " ) > - 1 ) {
newOptions . autoStart = true ;
}
if ( flags . indexOf ( " ignoreCors " ) > - 1 ) {
newOptions . ignoreCors = true ;
}
if ( flags . indexOf ( " branchTracking " ) > - 1 ) {
newOptions . branchTracking = true ;
}
if ( flags . indexOf ( " sourceURL " ) > - 1 ) {
newOptions . sourceURL = true ;
}
if ( flags . indexOf ( " debug " ) > - 1 ) {
newOptions . debug = true ;
}
if ( flags . indexOf ( " engineOnly " ) > - 1 ) {
newOptions . engineOnly = true ;
}
if ( flags . indexOf ( " commonJS " ) > - 1 ) {
newOptions . commonJS = true ;
}
if ( flags . indexOf ( " instrumentCache " ) > - 1 ) {
newOptions . instrumentCache = true ;
}
}
} ) ;
blanket . options ( newOptions ) ;
if ( typeof requirejs !== 'undefined' ) {
blanket . options ( "existingRequireJS" , true ) ;
}
/* setup requirejs loader, if needed */
if ( blanket . options ( "commonJS" ) ) {
blanket . _commonjs = { } ;
}
} ) ( ) ;
( function ( _blanket ) {
_blanket . extend ( {
utils : {
normalizeBackslashes : function ( str ) {
return str . replace ( /\\/g , '/' ) ;
} ,
matchPatternAttribute : function ( filename , pattern ) {
if ( typeof pattern === 'string' ) {
if ( pattern . indexOf ( "[" ) === 0 ) {
//treat as array
var pattenArr = pattern . slice ( 1 , pattern . length - 1 ) . split ( "," ) ;
return pattenArr . some ( function ( elem ) {
return _blanket . utils . matchPatternAttribute ( filename , _blanket . utils . normalizeBackslashes ( elem . slice ( 1 , - 1 ) ) ) ;
//return filename.indexOf(_blanket.utils.normalizeBackslashes(elem.slice(1,-1))) > -1;
} ) ;
} else if ( pattern . indexOf ( "//" ) === 0 ) {
var ex = pattern . slice ( 2 , pattern . lastIndexOf ( '/' ) ) ;
var mods = pattern . slice ( pattern . lastIndexOf ( '/' ) + 1 ) ;
var regex = new RegExp ( ex , mods ) ;
return regex . test ( filename ) ;
} else if ( pattern . indexOf ( "#" ) === 0 ) {
return window [ pattern . slice ( 1 ) ] . call ( window , filename ) ;
} else {
return filename . indexOf ( _blanket . utils . normalizeBackslashes ( pattern ) ) > - 1 ;
}
} else if ( pattern instanceof Array ) {
return pattern . some ( function ( elem ) {
return _blanket . utils . matchPatternAttribute ( filename , elem ) ;
} ) ;
} else if ( pattern instanceof RegExp ) {
return pattern . test ( filename ) ;
} else if ( typeof pattern === "function" ) {
return pattern . call ( window , filename ) ;
}
} ,
blanketEval : function ( data ) {
_blanket . _addScript ( data ) ;
} ,
collectPageScripts : function ( ) {
var toArray = Array . prototype . slice ;
var scripts = toArray . call ( document . scripts ) ;
var selectedScripts = [ ] , scriptNames = [ ] ;
var filter = _blanket . options ( "filter" ) ;
if ( filter != null ) {
//global filter in place, data-cover-only
var antimatch = _blanket . options ( "antifilter" ) ;
selectedScripts = toArray . call ( document . scripts )
. filter ( function ( s ) {
return toArray . call ( s . attributes ) . filter ( function ( sn ) {
return sn . nodeName === "src" && _blanket . utils . matchPatternAttribute ( sn . nodeValue , filter ) &&
( typeof antimatch === "undefined" || ! _blanket . utils . matchPatternAttribute ( sn . nodeValue , antimatch ) ) ;
} ) . length === 1 ;
} ) ;
} else {
selectedScripts = toArray . call ( document . querySelectorAll ( "script[data-cover]" ) ) ;
}
scriptNames = selectedScripts . map ( function ( s ) {
return _blanket . utils . qualifyURL (
toArray . call ( s . attributes ) . filter (
function ( sn ) {
return sn . nodeName === "src" ;
} ) [ 0 ] . nodeValue ) ;
} ) ;
if ( ! filter ) {
_blanket . options ( "filter" , "['" + scriptNames . join ( "','" ) + "']" ) ;
}
return scriptNames ;
} ,
loadAll : function ( nextScript , cb , preprocessor ) {
/ * *
* load dependencies
* @ param { nextScript } factory for priority level
* @ param { cb } the done callback
* /
var currScript = nextScript ( ) ;
var isLoaded = _blanket . utils . scriptIsLoaded (
currScript ,
_blanket . utils . ifOrdered ,
nextScript ,
cb
) ;
if ( ! ( _blanket . utils . cache [ currScript ] && _blanket . utils . cache [ currScript ] . loaded ) ) {
var attach = function ( ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Mark script:" + currScript + ", as loaded and move to next script." ) ; }
isLoaded ( ) ;
} ;
var whenDone = function ( result ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-File loading finished" ) ; }
if ( typeof result !== 'undefined' ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Add file to DOM." ) ; }
_blanket . _addScript ( result ) ;
}
attach ( ) ;
} ;
_blanket . utils . attachScript (
{
url : currScript
} ,
function ( content ) {
_blanket . utils . processFile (
content ,
currScript ,
whenDone ,
whenDone
) ;
}
) ;
} else {
isLoaded ( ) ;
}
} ,
attachScript : function ( options , cb ) {
var timeout = _blanket . options ( "timeout" ) || 3000 ;
setTimeout ( function ( ) {
if ( ! _blanket . utils . cache [ options . url ] . loaded ) {
throw new Error ( "error loading source script" ) ;
}
} , timeout ) ;
_blanket . utils . getFile (
options . url ,
cb ,
function ( ) { throw new Error ( "error loading source script" ) ; }
) ;
} ,
ifOrdered : function ( nextScript , cb ) {
/ * *
* ordered loading callback
* @ param { nextScript } factory for priority level
* @ param { cb } the done callback
* /
var currScript = nextScript ( true ) ;
if ( currScript ) {
_blanket . utils . loadAll ( nextScript , cb ) ;
} else {
cb ( new Error ( "Error in loading chain." ) ) ;
}
} ,
scriptIsLoaded : function ( url , orderedCb , nextScript , cb ) {
/ * *
* returns a callback that checks a loading list to see if a script is loaded .
* @ param { orderedCb } callback if ordered loading is being done
* @ param { nextScript } factory for next priority level
* @ param { cb } the done callback
* /
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Returning function" ) ; }
return function ( ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Marking file as loaded: " + url ) ; }
_blanket . utils . cache [ url ] . loaded = true ;
if ( _blanket . utils . allLoaded ( ) ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-All files loaded" ) ; }
cb ( ) ;
} else if ( orderedCb ) {
//if it's ordered we need to
//traverse down to the next
//priority level
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Load next file." ) ; }
orderedCb ( nextScript , cb ) ;
}
} ;
} ,
cache : { } ,
allLoaded : function ( ) {
/ * *
* check if depdencies are loaded in cache
* /
var cached = Object . keys ( _blanket . utils . cache ) ;
for ( var i = 0 ; i < cached . length ; i ++ ) {
if ( ! _blanket . utils . cache [ cached [ i ] ] . loaded ) {
return false ;
}
}
return true ;
} ,
processFile : function ( content , url , cb , oldCb ) {
var match = _blanket . options ( "filter" ) ;
//we check the never matches first
var antimatch = _blanket . options ( "antifilter" ) ;
if ( typeof antimatch !== "undefined" &&
_blanket . utils . matchPatternAttribute ( url , antimatch )
) {
oldCb ( content ) ;
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-File will never be instrumented:" + url ) ; }
_blanket . requiringFile ( url , true ) ;
} else if ( _blanket . utils . matchPatternAttribute ( url , match ) ) {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Attempting instrument of:" + url ) ; }
_blanket . instrument ( {
inputFile : content ,
inputFileName : url
} , function ( instrumented ) {
try {
2020-11-03 00:46:49 +00:00
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-instrument of:" + url + " was successful." ) ; }
2015-01-14 01:04:21 +00:00
_blanket . utils . blanketEval ( instrumented ) ;
cb ( ) ;
_blanket . requiringFile ( url , true ) ;
}
catch ( err ) {
if ( _blanket . options ( "ignoreScriptError" ) ) {
//we can continue like normal if
//we're ignoring script errors,
//but otherwise we don't want
//to completeLoad or the error might be
//missed.
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-There was an error loading the file:" + url ) ; }
cb ( content ) ;
_blanket . requiringFile ( url , true ) ;
} else {
throw new Error ( "Error parsing instrumented code: " + err ) ;
}
}
} ) ;
} else {
if ( _blanket . options ( "debug" ) ) { console . log ( "BLANKET-Loading (without instrumenting) the file:" + url ) ; }
oldCb ( content ) ;
_blanket . requiringFile ( url , true ) ;
}
} ,
cacheXhrConstructor : function ( ) {
var Constructor , createXhr , i , progId ;
if ( typeof XMLHttpRequest !== "undefined" ) {
Constructor = XMLHttpRequest ;
this . createXhr = function ( ) { return new Constructor ( ) ; } ;
} else if ( typeof ActiveXObject !== "undefined" ) {
Constructor = ActiveXObject ;
for ( i = 0 ; i < 3 ; i += 1 ) {
progId = progIds [ i ] ;
try {
new ActiveXObject ( progId ) ;
break ;
} catch ( e ) { }
}
this . createXhr = function ( ) { return new Constructor ( progId ) ; } ;
}
} ,
craeteXhr : function ( ) {
throw new Error ( "cacheXhrConstructor is supposed to overwrite this function." ) ;
} ,
getFile : function ( url , callback , errback , onXhr ) {
var foundInSession = false ;
if ( _blanket . blanketSession ) {
var files = Object . keys ( _blanket . blanketSession ) ;
for ( var i = 0 ; i < files . length ; i ++ ) {
var key = files [ i ] ;
if ( url . indexOf ( key ) > - 1 ) {
callback ( _blanket . blanketSession [ key ] ) ;
foundInSession = true ;
return ;
}
}
}
if ( ! foundInSession ) {
var xhr = _blanket . utils . createXhr ( ) ;
xhr . open ( 'GET' , url , true ) ;
//Allow overrides specified in config
if ( onXhr ) {
onXhr ( xhr , url ) ;
}
xhr . onreadystatechange = function ( evt ) {
var status , err ;
//Do not explicitly handle errors, those should be
//visible via console output in the browser.
if ( xhr . readyState === 4 ) {
status = xhr . status ;
if ( ( status > 399 && status < 600 ) / * ||
( status === 0 &&
navigator . userAgent . toLowerCase ( ) . indexOf ( 'firefox' ) > - 1 )
* / ) {
//An http 4xx or 5xx error. Signal an error.
err = new Error ( url + ' HTTP status: ' + status ) ;
err . xhr = xhr ;
errback ( err ) ;
} else {
callback ( xhr . responseText ) ;
}
}
} ;
try {
xhr . send ( null ) ;
} catch ( e ) {
if ( e . code && ( e . code === 101 || e . code === 1012 ) && _blanket . options ( "ignoreCors" ) === false ) {
//running locally and getting error from browser
_blanket . showManualLoader ( ) ;
} else {
throw e ;
}
}
}
}
}
} ) ;
( function ( ) {
var require = blanket . options ( "commonJS" ) ? blanket . _commonjs . require : window . require ;
var requirejs = blanket . options ( "commonJS" ) ? blanket . _commonjs . requirejs : window . requirejs ;
if ( ! _blanket . options ( "engineOnly" ) && _blanket . options ( "existingRequireJS" ) ) {
_blanket . utils . oldloader = requirejs . load ;
requirejs . load = function ( context , moduleName , url ) {
_blanket . requiringFile ( url ) ;
_blanket . utils . getFile ( url ,
function ( content ) {
_blanket . utils . processFile (
content ,
url ,
function newLoader ( ) {
context . completeLoad ( moduleName ) ;
} ,
function oldLoader ( ) {
_blanket . utils . oldloader ( context , moduleName , url ) ;
}
) ;
} , function ( err ) {
_blanket . requiringFile ( ) ;
throw err ;
} ) ;
} ;
}
// Save the XHR constructor, just in case frameworks like Sinon would sandbox it.
_blanket . utils . cacheXhrConstructor ( ) ;
} ) ( ) ;
} ) ( blanket ) ;
( function ( ) {
if ( ! mocha ) {
throw new Exception ( "mocha library does not exist in global namespace!" ) ;
}
/ *
* Mocha Events :
*
* - ` start ` execution started
* - ` end ` execution complete
* - ` suite ` ( suite ) test suite execution started
* - ` suite end ` ( suite ) all tests ( and sub - suites ) have finished
* - ` test ` ( test ) test execution started
* - ` test end ` ( test ) test completed
* - ` hook ` ( hook ) hook execution started
* - ` hook end ` ( hook ) hook complete
* - ` pass ` ( test ) test passed
* - ` fail ` ( test , err ) test failed
*
* /
var OriginalReporter = mocha . _reporter ;
var BlanketReporter = function ( runner ) {
runner . on ( 'start' , function ( ) {
blanket . setupCoverage ( ) ;
} ) ;
runner . on ( 'end' , function ( ) {
blanket . onTestsDone ( ) ;
} ) ;
runner . on ( 'suite' , function ( ) {
blanket . onModuleStart ( ) ;
} ) ;
runner . on ( 'test' , function ( ) {
blanket . onTestStart ( ) ;
} ) ;
runner . on ( 'test end' , function ( test ) {
blanket . onTestDone ( test . parent . tests . length , test . state === 'passed' ) ;
} ) ;
// NOTE: this is an instance of BlanketReporter
new OriginalReporter ( runner ) ;
} ;
BlanketReporter . prototype = OriginalReporter . prototype ;
mocha . reporter ( BlanketReporter ) ;
var oldRun = mocha . run ,
oldCallback = null ;
mocha . run = function ( finishCallback ) {
oldCallback = finishCallback ;
console . log ( "waiting for blanket..." ) ;
} ;
blanket . beforeStartTestRunner ( {
callback : function ( ) {
if ( ! blanket . options ( "existingRequireJS" ) ) {
oldRun ( oldCallback ) ;
}
mocha . run = oldRun ;
}
} ) ;
} ) ( ) ;