PageRenderTime 89ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 1ms

/ajax/libs/blanket.js/1.1.4/blanket_jasmine.js

https://bitbucket.org/kolbyjAFK/cdnjs
JavaScript | 7292 lines | 6365 code | 716 blank | 211 comment | 790 complexity | de8c3f8aa0636d50458f345a56fe4c2b MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. /*! blanket - v1.1.3 */
  2. (function(define){
  3. /*
  4. Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
  5. Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
  6. Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
  7. Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
  8. Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
  9. Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
  10. Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
  11. Redistribution and use in source and binary forms, with or without
  12. modification, are permitted provided that the following conditions are met:
  13. * Redistributions of source code must retain the above copyright
  14. notice, this list of conditions and the following disclaimer.
  15. * Redistributions in binary form must reproduce the above copyright
  16. notice, this list of conditions and the following disclaimer in the
  17. documentation and/or other materials provided with the distribution.
  18. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  19. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  22. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. /*jslint bitwise:true plusplus:true */
  30. /*global esprima:true, define:true, exports:true, window: true,
  31. throwError: true, createLiteral: true, generateStatement: true,
  32. parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
  33. parseFunctionDeclaration: true, parseFunctionExpression: true,
  34. parseFunctionSourceElements: true, parseVariableIdentifier: true,
  35. parseLeftHandSideExpression: true,
  36. parseStatement: true, parseSourceElement: true */
  37. (function (root, factory) {
  38. 'use strict';
  39. // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
  40. // Rhino, and plain browser loading.
  41. if (typeof define === 'function' && define.amd) {
  42. define(['exports'], factory);
  43. } else if (typeof exports !== 'undefined') {
  44. factory(exports);
  45. } else {
  46. factory((root.esprima = {}));
  47. }
  48. }(this, function (exports) {
  49. 'use strict';
  50. var Token,
  51. TokenName,
  52. Syntax,
  53. PropertyKind,
  54. Messages,
  55. Regex,
  56. source,
  57. strict,
  58. index,
  59. lineNumber,
  60. lineStart,
  61. length,
  62. buffer,
  63. state,
  64. extra;
  65. Token = {
  66. BooleanLiteral: 1,
  67. EOF: 2,
  68. Identifier: 3,
  69. Keyword: 4,
  70. NullLiteral: 5,
  71. NumericLiteral: 6,
  72. Punctuator: 7,
  73. StringLiteral: 8
  74. };
  75. TokenName = {};
  76. TokenName[Token.BooleanLiteral] = 'Boolean';
  77. TokenName[Token.EOF] = '<end>';
  78. TokenName[Token.Identifier] = 'Identifier';
  79. TokenName[Token.Keyword] = 'Keyword';
  80. TokenName[Token.NullLiteral] = 'Null';
  81. TokenName[Token.NumericLiteral] = 'Numeric';
  82. TokenName[Token.Punctuator] = 'Punctuator';
  83. TokenName[Token.StringLiteral] = 'String';
  84. Syntax = {
  85. AssignmentExpression: 'AssignmentExpression',
  86. ArrayExpression: 'ArrayExpression',
  87. BlockStatement: 'BlockStatement',
  88. BinaryExpression: 'BinaryExpression',
  89. BreakStatement: 'BreakStatement',
  90. CallExpression: 'CallExpression',
  91. CatchClause: 'CatchClause',
  92. ConditionalExpression: 'ConditionalExpression',
  93. ContinueStatement: 'ContinueStatement',
  94. DoWhileStatement: 'DoWhileStatement',
  95. DebuggerStatement: 'DebuggerStatement',
  96. EmptyStatement: 'EmptyStatement',
  97. ExpressionStatement: 'ExpressionStatement',
  98. ForStatement: 'ForStatement',
  99. ForInStatement: 'ForInStatement',
  100. FunctionDeclaration: 'FunctionDeclaration',
  101. FunctionExpression: 'FunctionExpression',
  102. Identifier: 'Identifier',
  103. IfStatement: 'IfStatement',
  104. Literal: 'Literal',
  105. LabeledStatement: 'LabeledStatement',
  106. LogicalExpression: 'LogicalExpression',
  107. MemberExpression: 'MemberExpression',
  108. NewExpression: 'NewExpression',
  109. ObjectExpression: 'ObjectExpression',
  110. Program: 'Program',
  111. Property: 'Property',
  112. ReturnStatement: 'ReturnStatement',
  113. SequenceExpression: 'SequenceExpression',
  114. SwitchStatement: 'SwitchStatement',
  115. SwitchCase: 'SwitchCase',
  116. ThisExpression: 'ThisExpression',
  117. ThrowStatement: 'ThrowStatement',
  118. TryStatement: 'TryStatement',
  119. UnaryExpression: 'UnaryExpression',
  120. UpdateExpression: 'UpdateExpression',
  121. VariableDeclaration: 'VariableDeclaration',
  122. VariableDeclarator: 'VariableDeclarator',
  123. WhileStatement: 'WhileStatement',
  124. WithStatement: 'WithStatement'
  125. };
  126. PropertyKind = {
  127. Data: 1,
  128. Get: 2,
  129. Set: 4
  130. };
  131. // Error messages should be identical to V8.
  132. Messages = {
  133. UnexpectedToken: 'Unexpected token %0',
  134. UnexpectedNumber: 'Unexpected number',
  135. UnexpectedString: 'Unexpected string',
  136. UnexpectedIdentifier: 'Unexpected identifier',
  137. UnexpectedReserved: 'Unexpected reserved word',
  138. UnexpectedEOS: 'Unexpected end of input',
  139. NewlineAfterThrow: 'Illegal newline after throw',
  140. InvalidRegExp: 'Invalid regular expression',
  141. UnterminatedRegExp: 'Invalid regular expression: missing /',
  142. InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
  143. InvalidLHSInForIn: 'Invalid left-hand side in for-in',
  144. MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
  145. NoCatchOrFinally: 'Missing catch or finally after try',
  146. UnknownLabel: 'Undefined label \'%0\'',
  147. Redeclaration: '%0 \'%1\' has already been declared',
  148. IllegalContinue: 'Illegal continue statement',
  149. IllegalBreak: 'Illegal break statement',
  150. IllegalReturn: 'Illegal return statement',
  151. StrictModeWith: 'Strict mode code may not include a with statement',
  152. StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
  153. StrictVarName: 'Variable name may not be eval or arguments in strict mode',
  154. StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
  155. StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
  156. StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
  157. StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
  158. StrictDelete: 'Delete of an unqualified identifier in strict mode.',
  159. StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
  160. AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
  161. AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
  162. StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
  163. StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
  164. StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
  165. StrictReservedWord: 'Use of future reserved word in strict mode'
  166. };
  167. // See also tools/generate-unicode-regex.py.
  168. Regex = {
  169. 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-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'),
  170. 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\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]')
  171. };
  172. // Ensure the condition is true, otherwise throw an error.
  173. // This is only to have a better contract semantic, i.e. another safety net
  174. // to catch a logic error. The condition shall be fulfilled in normal case.
  175. // Do NOT use this to enforce a certain condition on any user input.
  176. function assert(condition, message) {
  177. if (!condition) {
  178. throw new Error('ASSERT: ' + message);
  179. }
  180. }
  181. function sliceSource(from, to) {
  182. return source.slice(from, to);
  183. }
  184. if (typeof 'esprima'[0] === 'undefined') {
  185. sliceSource = function sliceArraySource(from, to) {
  186. return source.slice(from, to).join('');
  187. };
  188. }
  189. function isDecimalDigit(ch) {
  190. return '0123456789'.indexOf(ch) >= 0;
  191. }
  192. function isHexDigit(ch) {
  193. return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
  194. }
  195. function isOctalDigit(ch) {
  196. return '01234567'.indexOf(ch) >= 0;
  197. }
  198. // 7.2 White Space
  199. function isWhiteSpace(ch) {
  200. return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') ||
  201. (ch === '\u000C') || (ch === '\u00A0') ||
  202. (ch.charCodeAt(0) >= 0x1680 &&
  203. '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0);
  204. }
  205. // 7.3 Line Terminators
  206. function isLineTerminator(ch) {
  207. return (ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029');
  208. }
  209. // 7.6 Identifier Names and Identifiers
  210. function isIdentifierStart(ch) {
  211. return (ch === '$') || (ch === '_') || (ch === '\\') ||
  212. (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
  213. ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch));
  214. }
  215. function isIdentifierPart(ch) {
  216. return (ch === '$') || (ch === '_') || (ch === '\\') ||
  217. (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
  218. ((ch >= '0') && (ch <= '9')) ||
  219. ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch));
  220. }
  221. // 7.6.1.2 Future Reserved Words
  222. function isFutureReservedWord(id) {
  223. switch (id) {
  224. // Future reserved words.
  225. case 'class':
  226. case 'enum':
  227. case 'export':
  228. case 'extends':
  229. case 'import':
  230. case 'super':
  231. return true;
  232. }
  233. return false;
  234. }
  235. function isStrictModeReservedWord(id) {
  236. switch (id) {
  237. // Strict Mode reserved words.
  238. case 'implements':
  239. case 'interface':
  240. case 'package':
  241. case 'private':
  242. case 'protected':
  243. case 'public':
  244. case 'static':
  245. case 'yield':
  246. case 'let':
  247. return true;
  248. }
  249. return false;
  250. }
  251. function isRestrictedWord(id) {
  252. return id === 'eval' || id === 'arguments';
  253. }
  254. // 7.6.1.1 Keywords
  255. function isKeyword(id) {
  256. var keyword = false;
  257. switch (id.length) {
  258. case 2:
  259. keyword = (id === 'if') || (id === 'in') || (id === 'do');
  260. break;
  261. case 3:
  262. keyword = (id === 'var') || (id === 'for') || (id === 'new') || (id === 'try');
  263. break;
  264. case 4:
  265. keyword = (id === 'this') || (id === 'else') || (id === 'case') || (id === 'void') || (id === 'with');
  266. break;
  267. case 5:
  268. keyword = (id === 'while') || (id === 'break') || (id === 'catch') || (id === 'throw');
  269. break;
  270. case 6:
  271. keyword = (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch');
  272. break;
  273. case 7:
  274. keyword = (id === 'default') || (id === 'finally');
  275. break;
  276. case 8:
  277. keyword = (id === 'function') || (id === 'continue') || (id === 'debugger');
  278. break;
  279. case 10:
  280. keyword = (id === 'instanceof');
  281. break;
  282. }
  283. if (keyword) {
  284. return true;
  285. }
  286. switch (id) {
  287. // Future reserved words.
  288. // 'const' is specialized as Keyword in V8.
  289. case 'const':
  290. return true;
  291. // For compatiblity to SpiderMonkey and ES.next
  292. case 'yield':
  293. case 'let':
  294. return true;
  295. }
  296. if (strict && isStrictModeReservedWord(id)) {
  297. return true;
  298. }
  299. return isFutureReservedWord(id);
  300. }
  301. // 7.4 Comments
  302. function skipComment() {
  303. var ch, blockComment, lineComment;
  304. blockComment = false;
  305. lineComment = false;
  306. while (index < length) {
  307. ch = source[index];
  308. if (lineComment) {
  309. ch = source[index++];
  310. if (isLineTerminator(ch)) {
  311. lineComment = false;
  312. if (ch === '\r' && source[index] === '\n') {
  313. ++index;
  314. }
  315. ++lineNumber;
  316. lineStart = index;
  317. }
  318. } else if (blockComment) {
  319. if (isLineTerminator(ch)) {
  320. if (ch === '\r' && source[index + 1] === '\n') {
  321. ++index;
  322. }
  323. ++lineNumber;
  324. ++index;
  325. lineStart = index;
  326. if (index >= length) {
  327. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  328. }
  329. } else {
  330. ch = source[index++];
  331. if (index >= length) {
  332. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  333. }
  334. if (ch === '*') {
  335. ch = source[index];
  336. if (ch === '/') {
  337. ++index;
  338. blockComment = false;
  339. }
  340. }
  341. }
  342. } else if (ch === '/') {
  343. ch = source[index + 1];
  344. if (ch === '/') {
  345. index += 2;
  346. lineComment = true;
  347. } else if (ch === '*') {
  348. index += 2;
  349. blockComment = true;
  350. if (index >= length) {
  351. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  352. }
  353. } else {
  354. break;
  355. }
  356. } else if (isWhiteSpace(ch)) {
  357. ++index;
  358. } else if (isLineTerminator(ch)) {
  359. ++index;
  360. if (ch === '\r' && source[index] === '\n') {
  361. ++index;
  362. }
  363. ++lineNumber;
  364. lineStart = index;
  365. } else {
  366. break;
  367. }
  368. }
  369. }
  370. function scanHexEscape(prefix) {
  371. var i, len, ch, code = 0;
  372. len = (prefix === 'u') ? 4 : 2;
  373. for (i = 0; i < len; ++i) {
  374. if (index < length && isHexDigit(source[index])) {
  375. ch = source[index++];
  376. code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
  377. } else {
  378. return '';
  379. }
  380. }
  381. return String.fromCharCode(code);
  382. }
  383. function scanIdentifier() {
  384. var ch, start, id, restore;
  385. ch = source[index];
  386. if (!isIdentifierStart(ch)) {
  387. return;
  388. }
  389. start = index;
  390. if (ch === '\\') {
  391. ++index;
  392. if (source[index] !== 'u') {
  393. return;
  394. }
  395. ++index;
  396. restore = index;
  397. ch = scanHexEscape('u');
  398. if (ch) {
  399. if (ch === '\\' || !isIdentifierStart(ch)) {
  400. return;
  401. }
  402. id = ch;
  403. } else {
  404. index = restore;
  405. id = 'u';
  406. }
  407. } else {
  408. id = source[index++];
  409. }
  410. while (index < length) {
  411. ch = source[index];
  412. if (!isIdentifierPart(ch)) {
  413. break;
  414. }
  415. if (ch === '\\') {
  416. ++index;
  417. if (source[index] !== 'u') {
  418. return;
  419. }
  420. ++index;
  421. restore = index;
  422. ch = scanHexEscape('u');
  423. if (ch) {
  424. if (ch === '\\' || !isIdentifierPart(ch)) {
  425. return;
  426. }
  427. id += ch;
  428. } else {
  429. index = restore;
  430. id += 'u';
  431. }
  432. } else {
  433. id += source[index++];
  434. }
  435. }
  436. // There is no keyword or literal with only one character.
  437. // Thus, it must be an identifier.
  438. if (id.length === 1) {
  439. return {
  440. type: Token.Identifier,
  441. value: id,
  442. lineNumber: lineNumber,
  443. lineStart: lineStart,
  444. range: [start, index]
  445. };
  446. }
  447. if (isKeyword(id)) {
  448. return {
  449. type: Token.Keyword,
  450. value: id,
  451. lineNumber: lineNumber,
  452. lineStart: lineStart,
  453. range: [start, index]
  454. };
  455. }
  456. // 7.8.1 Null Literals
  457. if (id === 'null') {
  458. return {
  459. type: Token.NullLiteral,
  460. value: id,
  461. lineNumber: lineNumber,
  462. lineStart: lineStart,
  463. range: [start, index]
  464. };
  465. }
  466. // 7.8.2 Boolean Literals
  467. if (id === 'true' || id === 'false') {
  468. return {
  469. type: Token.BooleanLiteral,
  470. value: id,
  471. lineNumber: lineNumber,
  472. lineStart: lineStart,
  473. range: [start, index]
  474. };
  475. }
  476. return {
  477. type: Token.Identifier,
  478. value: id,
  479. lineNumber: lineNumber,
  480. lineStart: lineStart,
  481. range: [start, index]
  482. };
  483. }
  484. // 7.7 Punctuators
  485. function scanPunctuator() {
  486. var start = index,
  487. ch1 = source[index],
  488. ch2,
  489. ch3,
  490. ch4;
  491. // Check for most common single-character punctuators.
  492. if (ch1 === ';' || ch1 === '{' || ch1 === '}') {
  493. ++index;
  494. return {
  495. type: Token.Punctuator,
  496. value: ch1,
  497. lineNumber: lineNumber,
  498. lineStart: lineStart,
  499. range: [start, index]
  500. };
  501. }
  502. if (ch1 === ',' || ch1 === '(' || ch1 === ')') {
  503. ++index;
  504. return {
  505. type: Token.Punctuator,
  506. value: ch1,
  507. lineNumber: lineNumber,
  508. lineStart: lineStart,
  509. range: [start, index]
  510. };
  511. }
  512. // Dot (.) can also start a floating-point number, hence the need
  513. // to check the next character.
  514. ch2 = source[index + 1];
  515. if (ch1 === '.' && !isDecimalDigit(ch2)) {
  516. return {
  517. type: Token.Punctuator,
  518. value: source[index++],
  519. lineNumber: lineNumber,
  520. lineStart: lineStart,
  521. range: [start, index]
  522. };
  523. }
  524. // Peek more characters.
  525. ch3 = source[index + 2];
  526. ch4 = source[index + 3];
  527. // 4-character punctuator: >>>=
  528. if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
  529. if (ch4 === '=') {
  530. index += 4;
  531. return {
  532. type: Token.Punctuator,
  533. value: '>>>=',
  534. lineNumber: lineNumber,
  535. lineStart: lineStart,
  536. range: [start, index]
  537. };
  538. }
  539. }
  540. // 3-character punctuators: === !== >>> <<= >>=
  541. if (ch1 === '=' && ch2 === '=' && ch3 === '=') {
  542. index += 3;
  543. return {
  544. type: Token.Punctuator,
  545. value: '===',
  546. lineNumber: lineNumber,
  547. lineStart: lineStart,
  548. range: [start, index]
  549. };
  550. }
  551. if (ch1 === '!' && ch2 === '=' && ch3 === '=') {
  552. index += 3;
  553. return {
  554. type: Token.Punctuator,
  555. value: '!==',
  556. lineNumber: lineNumber,
  557. lineStart: lineStart,
  558. range: [start, index]
  559. };
  560. }
  561. if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
  562. index += 3;
  563. return {
  564. type: Token.Punctuator,
  565. value: '>>>',
  566. lineNumber: lineNumber,
  567. lineStart: lineStart,
  568. range: [start, index]
  569. };
  570. }
  571. if (ch1 === '<' && ch2 === '<' && ch3 === '=') {
  572. index += 3;
  573. return {
  574. type: Token.Punctuator,
  575. value: '<<=',
  576. lineNumber: lineNumber,
  577. lineStart: lineStart,
  578. range: [start, index]
  579. };
  580. }
  581. if (ch1 === '>' && ch2 === '>' && ch3 === '=') {
  582. index += 3;
  583. return {
  584. type: Token.Punctuator,
  585. value: '>>=',
  586. lineNumber: lineNumber,
  587. lineStart: lineStart,
  588. range: [start, index]
  589. };
  590. }
  591. // 2-character punctuators: <= >= == != ++ -- << >> && ||
  592. // += -= *= %= &= |= ^= /=
  593. if (ch2 === '=') {
  594. if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
  595. index += 2;
  596. return {
  597. type: Token.Punctuator,
  598. value: ch1 + ch2,
  599. lineNumber: lineNumber,
  600. lineStart: lineStart,
  601. range: [start, index]
  602. };
  603. }
  604. }
  605. if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) {
  606. if ('+-<>&|'.indexOf(ch2) >= 0) {
  607. index += 2;
  608. return {
  609. type: Token.Punctuator,
  610. value: ch1 + ch2,
  611. lineNumber: lineNumber,
  612. lineStart: lineStart,
  613. range: [start, index]
  614. };
  615. }
  616. }
  617. // The remaining 1-character punctuators.
  618. if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) {
  619. return {
  620. type: Token.Punctuator,
  621. value: source[index++],
  622. lineNumber: lineNumber,
  623. lineStart: lineStart,
  624. range: [start, index]
  625. };
  626. }
  627. }
  628. // 7.8.3 Numeric Literals
  629. function scanNumericLiteral() {
  630. var number, start, ch;
  631. ch = source[index];
  632. assert(isDecimalDigit(ch) || (ch === '.'),
  633. 'Numeric literal must start with a decimal digit or a decimal point');
  634. start = index;
  635. number = '';
  636. if (ch !== '.') {
  637. number = source[index++];
  638. ch = source[index];
  639. // Hex number starts with '0x'.
  640. // Octal number starts with '0'.
  641. if (number === '0') {
  642. if (ch === 'x' || ch === 'X') {
  643. number += source[index++];
  644. while (index < length) {
  645. ch = source[index];
  646. if (!isHexDigit(ch)) {
  647. break;
  648. }
  649. number += source[index++];
  650. }
  651. if (number.length <= 2) {
  652. // only 0x
  653. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  654. }
  655. if (index < length) {
  656. ch = source[index];
  657. if (isIdentifierStart(ch)) {
  658. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  659. }
  660. }
  661. return {
  662. type: Token.NumericLiteral,
  663. value: parseInt(number, 16),
  664. lineNumber: lineNumber,
  665. lineStart: lineStart,
  666. range: [start, index]
  667. };
  668. } else if (isOctalDigit(ch)) {
  669. number += source[index++];
  670. while (index < length) {
  671. ch = source[index];
  672. if (!isOctalDigit(ch)) {
  673. break;
  674. }
  675. number += source[index++];
  676. }
  677. if (index < length) {
  678. ch = source[index];
  679. if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
  680. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  681. }
  682. }
  683. return {
  684. type: Token.NumericLiteral,
  685. value: parseInt(number, 8),
  686. octal: true,
  687. lineNumber: lineNumber,
  688. lineStart: lineStart,
  689. range: [start, index]
  690. };
  691. }
  692. // decimal number starts with '0' such as '09' is illegal.
  693. if (isDecimalDigit(ch)) {
  694. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  695. }
  696. }
  697. while (index < length) {
  698. ch = source[index];
  699. if (!isDecimalDigit(ch)) {
  700. break;
  701. }
  702. number += source[index++];
  703. }
  704. }
  705. if (ch === '.') {
  706. number += source[index++];
  707. while (index < length) {
  708. ch = source[index];
  709. if (!isDecimalDigit(ch)) {
  710. break;
  711. }
  712. number += source[index++];
  713. }
  714. }
  715. if (ch === 'e' || ch === 'E') {
  716. number += source[index++];
  717. ch = source[index];
  718. if (ch === '+' || ch === '-') {
  719. number += source[index++];
  720. }
  721. ch = source[index];
  722. if (isDecimalDigit(ch)) {
  723. number += source[index++];
  724. while (index < length) {
  725. ch = source[index];
  726. if (!isDecimalDigit(ch)) {
  727. break;
  728. }
  729. number += source[index++];
  730. }
  731. } else {
  732. ch = 'character ' + ch;
  733. if (index >= length) {
  734. ch = '<end>';
  735. }
  736. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  737. }
  738. }
  739. if (index < length) {
  740. ch = source[index];
  741. if (isIdentifierStart(ch)) {
  742. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  743. }
  744. }
  745. return {
  746. type: Token.NumericLiteral,
  747. value: parseFloat(number),
  748. lineNumber: lineNumber,
  749. lineStart: lineStart,
  750. range: [start, index]
  751. };
  752. }
  753. // 7.8.4 String Literals
  754. function scanStringLiteral() {
  755. var str = '', quote, start, ch, code, unescaped, restore, octal = false;
  756. quote = source[index];
  757. assert((quote === '\'' || quote === '"'),
  758. 'String literal must starts with a quote');
  759. start = index;
  760. ++index;
  761. while (index < length) {
  762. ch = source[index++];
  763. if (ch === quote) {
  764. quote = '';
  765. break;
  766. } else if (ch === '\\') {
  767. ch = source[index++];
  768. if (!isLineTerminator(ch)) {
  769. switch (ch) {
  770. case 'n':
  771. str += '\n';
  772. break;
  773. case 'r':
  774. str += '\r';
  775. break;
  776. case 't':
  777. str += '\t';
  778. break;
  779. case 'u':
  780. case 'x':
  781. restore = index;
  782. unescaped = scanHexEscape(ch);
  783. if (unescaped) {
  784. str += unescaped;
  785. } else {
  786. index = restore;
  787. str += ch;
  788. }
  789. break;
  790. case 'b':
  791. str += '\b';
  792. break;
  793. case 'f':
  794. str += '\f';
  795. break;
  796. case 'v':
  797. str += '\v';
  798. break;
  799. default:
  800. if (isOctalDigit(ch)) {
  801. code = '01234567'.indexOf(ch);
  802. // \0 is not octal escape sequence
  803. if (code !== 0) {
  804. octal = true;
  805. }
  806. if (index < length && isOctalDigit(source[index])) {
  807. octal = true;
  808. code = code * 8 + '01234567'.indexOf(source[index++]);
  809. // 3 digits are only allowed when string starts
  810. // with 0, 1, 2, 3
  811. if ('0123'.indexOf(ch) >= 0 &&
  812. index < length &&
  813. isOctalDigit(source[index])) {
  814. code = code * 8 + '01234567'.indexOf(source[index++]);
  815. }
  816. }
  817. str += String.fromCharCode(code);
  818. } else {
  819. str += ch;
  820. }
  821. break;
  822. }
  823. } else {
  824. ++lineNumber;
  825. if (ch === '\r' && source[index] === '\n') {
  826. ++index;
  827. }
  828. }
  829. } else if (isLineTerminator(ch)) {
  830. break;
  831. } else {
  832. str += ch;
  833. }
  834. }
  835. if (quote !== '') {
  836. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  837. }
  838. return {
  839. type: Token.StringLiteral,
  840. value: str,
  841. octal: octal,
  842. lineNumber: lineNumber,
  843. lineStart: lineStart,
  844. range: [start, index]
  845. };
  846. }
  847. function scanRegExp() {
  848. var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false;
  849. buffer = null;
  850. skipComment();
  851. start = index;
  852. ch = source[index];
  853. assert(ch === '/', 'Regular expression literal must start with a slash');
  854. str = source[index++];
  855. while (index < length) {
  856. ch = source[index++];
  857. str += ch;
  858. if (classMarker) {
  859. if (ch === ']') {
  860. classMarker = false;
  861. }
  862. } else {
  863. if (ch === '\\') {
  864. ch = source[index++];
  865. // ECMA-262 7.8.5
  866. if (isLineTerminator(ch)) {
  867. throwError({}, Messages.UnterminatedRegExp);
  868. }
  869. str += ch;
  870. } else if (ch === '/') {
  871. terminated = true;
  872. break;
  873. } else if (ch === '[') {
  874. classMarker = true;
  875. } else if (isLineTerminator(ch)) {
  876. throwError({}, Messages.UnterminatedRegExp);
  877. }
  878. }
  879. }
  880. if (!terminated) {
  881. throwError({}, Messages.UnterminatedRegExp);
  882. }
  883. // Exclude leading and trailing slash.
  884. pattern = str.substr(1, str.length - 2);
  885. flags = '';
  886. while (index < length) {
  887. ch = source[index];
  888. if (!isIdentifierPart(ch)) {
  889. break;
  890. }
  891. ++index;
  892. if (ch === '\\' && index < length) {
  893. ch = source[index];
  894. if (ch === 'u') {
  895. ++index;
  896. restore = index;
  897. ch = scanHexEscape('u');
  898. if (ch) {
  899. flags += ch;
  900. str += '\\u';
  901. for (; restore < index; ++restore) {
  902. str += source[restore];
  903. }
  904. } else {
  905. index = restore;
  906. flags += 'u';
  907. str += '\\u';
  908. }
  909. } else {
  910. str += '\\';
  911. }
  912. } else {
  913. flags += ch;
  914. str += ch;
  915. }
  916. }
  917. try {
  918. value = new RegExp(pattern, flags);
  919. } catch (e) {
  920. throwError({}, Messages.InvalidRegExp);
  921. }
  922. return {
  923. literal: str,
  924. value: value,
  925. range: [start, index]
  926. };
  927. }
  928. function isIdentifierName(token) {
  929. return token.type === Token.Identifier ||
  930. token.type === Token.Keyword ||
  931. token.type === Token.BooleanLiteral ||
  932. token.type === Token.NullLiteral;
  933. }
  934. function advance() {
  935. var ch, token;
  936. skipComment();
  937. if (index >= length) {
  938. return {
  939. type: Token.EOF,
  940. lineNumber: lineNumber,
  941. lineStart: lineStart,
  942. range: [index, index]
  943. };
  944. }
  945. token = scanPunctuator();
  946. if (typeof token !== 'undefined') {
  947. return token;
  948. }
  949. ch = source[index];
  950. if (ch === '\'' || ch === '"') {
  951. return scanStringLiteral();
  952. }
  953. if (ch === '.' || isDecimalDigit(ch)) {
  954. return scanNumericLiteral();
  955. }
  956. token = scanIdentifier();
  957. if (typeof token !== 'undefined') {
  958. return token;
  959. }
  960. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  961. }
  962. function lex() {
  963. var token;
  964. if (buffer) {
  965. index = buffer.range[1];
  966. lineNumber = buffer.lineNumber;
  967. lineStart = buffer.lineStart;
  968. token = buffer;
  969. buffer = null;
  970. return token;
  971. }
  972. buffer = null;
  973. return advance();
  974. }
  975. function lookahead() {
  976. var pos, line, start;
  977. if (buffer !== null) {
  978. return buffer;
  979. }
  980. pos = index;
  981. line = lineNumber;
  982. start = lineStart;
  983. buffer = advance();
  984. index = pos;
  985. lineNumber = line;
  986. lineStart = start;
  987. return buffer;
  988. }
  989. // Return true if there is a line terminator before the next token.
  990. function peekLineTerminator() {
  991. var pos, line, start, found;
  992. pos = index;
  993. line = lineNumber;
  994. start = lineStart;
  995. skipComment();
  996. found = lineNumber !== line;
  997. index = pos;
  998. lineNumber = line;
  999. lineStart = start;
  1000. return found;
  1001. }
  1002. // Throw an exception
  1003. function throwError(token, messageFormat) {
  1004. var error,
  1005. args = Array.prototype.slice.call(arguments, 2),
  1006. msg = messageFormat.replace(
  1007. /%(\d)/g,
  1008. function (whole, index) {
  1009. return args[index] || '';
  1010. }
  1011. );
  1012. if (typeof token.lineNumber === 'number') {
  1013. error = new Error('Line ' + token.lineNumber + ': ' + msg);
  1014. error.index = token.range[0];
  1015. error.lineNumber = token.lineNumber;
  1016. error.column = token.range[0] - lineStart + 1;
  1017. } else {
  1018. error = new Error('Line ' + lineNumber + ': ' + msg);
  1019. error.index = index;
  1020. error.lineNumber = lineNumber;
  1021. error.column = index - lineStart + 1;
  1022. }
  1023. throw error;
  1024. }
  1025. function throwErrorTolerant() {
  1026. try {
  1027. throwError.apply(null, arguments);
  1028. } catch (e) {
  1029. if (extra.errors) {
  1030. extra.errors.push(e);
  1031. } else {
  1032. throw e;
  1033. }
  1034. }
  1035. }
  1036. // Throw an exception because of the token.
  1037. function throwUnexpected(token) {
  1038. if (token.type === Token.EOF) {
  1039. throwError(token, Messages.UnexpectedEOS);
  1040. }
  1041. if (token.type === Token.NumericLiteral) {
  1042. throwError(token, Messages.UnexpectedNumber);
  1043. }
  1044. if (token.type === Token.StringLiteral) {
  1045. throwError(token, Messages.UnexpectedString);
  1046. }
  1047. if (token.type === Token.Identifier) {
  1048. throwError(token, Messages.UnexpectedIdentifier);
  1049. }
  1050. if (token.type === Token.Keyword) {
  1051. if (isFutureReservedWord(token.value)) {
  1052. throwError(token, Messages.UnexpectedReserved);
  1053. } else if (strict && isStrictModeReservedWord(token.value)) {
  1054. throwErrorTolerant(token, Messages.StrictReservedWord);
  1055. return;
  1056. }
  1057. throwError(token, Messages.UnexpectedToken, token.value);
  1058. }
  1059. // BooleanLiteral, NullLiteral, or Punctuator.
  1060. throwError(token, Messages.UnexpectedToken, token.value);
  1061. }
  1062. // Expect the next token to match the specified punctuator.
  1063. // If not, an exception will be thrown.
  1064. function expect(value) {
  1065. var token = lex();
  1066. if (token.type !== Token.Punctuator || token.value !== value) {
  1067. throwUnexpected(token);
  1068. }
  1069. }
  1070. // Expect the next token to match the specified keyword.
  1071. // If not, an exception will be thrown.
  1072. function expectKeyword(keyword) {
  1073. var token = lex();
  1074. if (token.type !== Token.Keyword || token.value !== keyword) {
  1075. throwUnexpected(token);
  1076. }
  1077. }
  1078. // Return true if the next token matches the specified punctuator.
  1079. function match(value) {
  1080. var token = lookahead();
  1081. return token.type === Token.Punctuator && token.value === value;
  1082. }
  1083. // Return true if the next token matches the specified keyword
  1084. function matchKeyword(keyword) {
  1085. var token = lookahead();
  1086. return token.type === Token.Keyword && token.value === keyword;
  1087. }
  1088. // Return true if the next token is an assignment operator
  1089. function matchAssign() {
  1090. var token = lookahead(),
  1091. op = token.value;
  1092. if (token.type !== Token.Punctuator) {
  1093. return false;
  1094. }
  1095. return op === '=' ||
  1096. op === '*=' ||
  1097. op === '/=' ||
  1098. op === '%=' ||
  1099. op === '+=' ||
  1100. op === '-=' ||
  1101. op === '<<=' ||
  1102. op === '>>=' ||
  1103. op === '>>>=' ||
  1104. op === '&=' ||
  1105. op === '^=' ||
  1106. op === '|=';
  1107. }
  1108. function consumeSemicolon() {
  1109. var token, line;
  1110. // Catch the very common case first.
  1111. if (source[index] === ';') {
  1112. lex();
  1113. return;
  1114. }
  1115. line = lineNumber;
  1116. skipComment();
  1117. if (lineNumber !== line) {
  1118. return;
  1119. }
  1120. if (match(';')) {
  1121. lex();
  1122. return;
  1123. }
  1124. token = lookahead();
  1125. if (token.type !== Token.EOF && !match('}')) {
  1126. throwUnexpected(token);
  1127. }
  1128. }
  1129. // Return true if provided expression is LeftHandSideExpression
  1130. function isLeftHandSide(expr) {
  1131. return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
  1132. }
  1133. // 11.1.4 Array Initialiser
  1134. function parseArrayInitialiser() {
  1135. var elements = [];
  1136. expect('[');
  1137. while (!match(']')) {
  1138. if (match(',')) {
  1139. lex();
  1140. elements.push(null);
  1141. } else {
  1142. elements.push(parseAssignmentExpression());
  1143. if (!match(']')) {
  1144. expect(',');
  1145. }
  1146. }
  1147. }
  1148. expect(']');
  1149. return {
  1150. type: Syntax.ArrayExpression,
  1151. elements: elements
  1152. };
  1153. }
  1154. // 11.1.5 Object Initialiser
  1155. function parsePropertyFunction(param, first) {
  1156. var previousStrict, body;
  1157. previousStrict = strict;
  1158. body = parseFunctionSourceElements();
  1159. if (first && strict && isRestrictedWord(param[0].name)) {
  1160. throwErrorTolerant(first, Messages.StrictParamName);
  1161. }
  1162. strict = previousStrict;
  1163. return {
  1164. type: Syntax.FunctionExpression,
  1165. id: null,
  1166. params: param,
  1167. defaults: [],
  1168. body: body,
  1169. rest: null,
  1170. generator: false,
  1171. expression: false
  1172. };
  1173. }
  1174. function parseObjectPropertyKey() {
  1175. var token = lex();
  1176. // Note: This function is called only from parseObjectProperty(), where
  1177. // EOF and Punctuator tokens are already filtered out.
  1178. if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
  1179. if (strict && token.octal) {
  1180. throwErrorTolerant(token, Messages.StrictOctalLiteral);
  1181. }
  1182. return createLiteral(token);
  1183. }
  1184. return {
  1185. type: Syntax.Identifier,
  1186. name: token.value
  1187. };
  1188. }
  1189. function parseObjectProperty() {
  1190. var token, key, id, param;
  1191. token = lookahead();
  1192. if (token.type === Token.Identifier) {
  1193. id = parseObjectPropertyKey();
  1194. // Property Assignment: Getter and Setter.
  1195. if (token.value === 'get' && !match(':')) {
  1196. key = parseObjectPropertyKey();
  1197. expect('(');
  1198. expect(')');
  1199. return {
  1200. type: Syntax.Property,
  1201. key: key,
  1202. value: parsePropertyFunction([]),
  1203. kind: 'get'
  1204. };
  1205. } else if (token.value === 'set' && !match(':')) {
  1206. key = parseObjectPropertyKey();
  1207. expect('(');
  1208. token = lookahead();
  1209. if (token.type !== Token.Identifier) {
  1210. throwUnexpected(lex());
  1211. }
  1212. param = [ parseVariableIdentifier() ];
  1213. expect(')');
  1214. return {
  1215. type: Syntax.Property,
  1216. key: key,
  1217. value: parsePropertyFunction(param, token),
  1218. kind: 'set'
  1219. };
  1220. } else {
  1221. expect(':');
  1222. return {
  1223. type: Syntax.Property,
  1224. key: id,
  1225. value: parseAssignmentExpression(),
  1226. kind: 'init'
  1227. };
  1228. }
  1229. } else if (token.type === Token.EOF || token.type === Token.Punctuator) {
  1230. throwUnexpected(token);
  1231. } else {
  1232. key = parseObjectPropertyKey();
  1233. expect(':');
  1234. return {
  1235. type: Syntax.Property,
  1236. key: key,
  1237. value: parseAssignmentExpression(),
  1238. kind: 'init'
  1239. };
  1240. }
  1241. }
  1242. function parseObjectInitialiser() {
  1243. var properties = [], property, name, kind, map = {}, toString = String;
  1244. expect('{');
  1245. while (!match('}')) {
  1246. property = parseObjectProperty();
  1247. if (property.key.type === Syntax.Identifier) {
  1248. name = property.key.name;
  1249. } else {
  1250. name = toString(property.key.value);
  1251. }
  1252. kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
  1253. if (Object.prototype.hasOwnProperty.call(map, name)) {
  1254. if (map[name] === PropertyKind.Data) {
  1255. if (strict && kind === PropertyKind.Data) {
  1256. throwErrorTolerant({}, Messages.StrictDuplicateProperty);
  1257. } else if (kind !== PropertyKind.Data) {
  1258. throwErrorTolerant({}, Messages.AccessorDataProperty);
  1259. }
  1260. } else {
  1261. if (kind === PropertyKind.Data) {
  1262. throwErrorTolerant({}, Messages.AccessorDataProperty);
  1263. } else if (map[name] & kind) {
  1264. throwErrorTolerant({}, Messages.AccessorGetSet);
  1265. }
  1266. }
  1267. map[name] |= kind;
  1268. } else {
  1269. map[name] = kind;
  1270. }
  1271. properties.push(property);
  1272. if (!match('}')) {
  1273. expect(',');
  1274. }
  1275. }
  1276. expect('}');
  1277. return {
  1278. type: Syntax.ObjectExpression,
  1279. properties: properties
  1280. };
  1281. }
  1282. // 11.1.6 The Grouping Operator
  1283. function parseGroupExpression() {
  1284. var expr;
  1285. expect('(');
  1286. expr = parseExpression();
  1287. expect(')');
  1288. return expr;
  1289. }
  1290. // 11.1 Primary Expressions
  1291. function parsePrimaryExpression() {
  1292. var token = lookahead(),
  1293. type = token.type;
  1294. if (type === Token.Identifier) {
  1295. return {
  1296. type: Syntax.Identifier,
  1297. name: lex().value
  1298. };
  1299. }
  1300. if (type === Token.StringLiteral || type === Token.NumericLiteral) {
  1301. if (strict && token.octal) {
  1302. throwErrorTolerant(token, Messages.StrictOctalLiteral);
  1303. }
  1304. return createLiteral(lex());
  1305. }
  1306. if (type === Token.Keyword) {
  1307. if (matchKeyword('this')) {
  1308. lex();
  1309. return {
  1310. type: Syntax.ThisExpression
  1311. };
  1312. }
  1313. if (matchKeyword('function')) {
  1314. return parseFunctionExpression();
  1315. }
  1316. }
  1317. if (type === Token.BooleanLiteral) {
  1318. lex();
  1319. token.value = (token.value === 'true');
  1320. return createLiteral(token);
  1321. }
  1322. if (type === Token.NullLiteral) {
  1323. lex();
  1324. token.value = null;
  1325. return createLiteral(token);
  1326. }
  1327. if (match('[')) {
  1328. return parseArrayInitialiser();
  1329. }
  1330. if (match('{')) {
  1331. return parseObjectInitialiser();
  1332. }
  1333. if (match('(')) {
  1334. return parseGroupExpression();
  1335. }
  1336. if (match('/') || match('/=')) {
  1337. return createLiteral(scanRegExp());
  1338. }
  1339. return throwUnexpected(lex());
  1340. }
  1341. // 11.2 Left-Hand-Side Expressions
  1342. function parseArguments() {
  1343. var args = [];
  1344. expect('(');
  1345. if (!match(')')) {
  1346. while (index < length) {
  1347. args.push(parseAssignmentExpression());
  1348. if (match(')')) {
  1349. break;
  1350. }
  1351. expect(',');
  1352. }
  1353. }
  1354. expect(')');
  1355. return args;
  1356. }
  1357. function parseNonComputedProperty() {
  1358. var token = lex();
  1359. if (!isIdentifierName(token)) {
  1360. throwUnexpected(token);
  1361. }
  1362. return {
  1363. type: Syntax.Identifier,
  1364. name: token.value
  1365. };
  1366. }
  1367. function parseNonComputedMember() {
  1368. expect('.');
  1369. return parseNonComputedProperty();
  1370. }
  1371. function parseComputedMember() {
  1372. var expr;
  1373. expect('[');
  1374. expr = parseExpression();
  1375. expect(']');
  1376. return expr;
  1377. }
  1378. function parseNewExpression() {
  1379. var expr;
  1380. expectKeyword('new');
  1381. expr = {
  1382. type: Syntax.NewExpression,
  1383. callee: parseLeftHandSideExpression(),
  1384. 'arguments': []
  1385. };
  1386. if (match('(')) {
  1387. expr['arguments'] = parseArguments();
  1388. }
  1389. return expr;
  1390. }
  1391. function parseLeftHandSideExpressionAllowCall() {
  1392. var expr;
  1393. expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
  1394. while (match('.') || match('[') || match('(')) {
  1395. if (match('(')) {
  1396. expr = {
  1397. type: Syntax.CallExpression,
  1398. callee: expr,
  1399. 'arguments': parseArguments()
  1400. };
  1401. } else if (match('[')) {
  1402. expr = {
  1403. type: Syntax.MemberExpression,
  1404. computed: true,
  1405. object: expr,
  1406. property: parseComputedMember()
  1407. };
  1408. } else {
  1409. expr = {
  1410. type: Syntax.MemberExpression,
  1411. computed: false,
  1412. object: expr,
  1413. property: parseNonComputedMember()
  1414. };
  1415. }
  1416. }
  1417. return expr;
  1418. }
  1419. function parseLeftHandSideExpression() {
  1420. var expr;
  1421. expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
  1422. while (match('.') || match('[')) {
  1423. if (match('[')) {
  1424. expr = {
  1425. type: Syntax.MemberExpression,
  1426. computed: true,
  1427. object: expr,
  1428. property: parseComputedMember()
  1429. };
  1430. } else {
  1431. expr = {
  1432. type: Syntax.MemberExpression,
  1433. computed: false,
  1434. object: expr,
  1435. property: parseNonComputedMember()
  1436. };
  1437. }
  1438. }
  1439. return expr;
  1440. }
  1441. // 11.3 Postfix Expressions
  1442. function parsePostfixExpression() {
  1443. var expr = parseLeftHandSideExpressionAllowCall(), token;
  1444. token = lookahead();
  1445. if (token.type !== Token.Punctuator) {
  1446. return expr;
  1447. }
  1448. if ((match('++') || match('--')) && !peekLineTerminator()) {
  1449. // 11.3.1, 11.3.2
  1450. if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
  1451. throwErrorTolerant({}, Messages.StrictLHSPostfix);
  1452. }
  1453. if (!isLeftHandSide(expr)) {
  1454. throwError({}, Messages.InvalidLHSInAssignment);
  1455. }
  1456. expr = {
  1457. type: Syntax.UpdateExpression,
  1458. operator: lex().value,
  1459. argument: expr,
  1460. prefix: false
  1461. };
  1462. }
  1463. return expr;
  1464. }
  1465. // 11.4 Unary Operators
  1466. function parseUnaryExpression() {
  1467. var token, expr;
  1468. token = lookahead();
  1469. if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
  1470. return parsePostfixExpression();
  1471. }
  1472. if (match('++') || match('--')) {
  1473. token = lex();
  1474. expr = parseUnaryExpression();
  1475. // 11.4.4, 11.4.5
  1476. if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
  1477. throwErrorTolerant({}, Messages.StrictLHSPrefix);
  1478. }
  1479. if (!isLeftHandSide(expr)) {
  1480. throwError({}, Messages.InvalidLHSInAssignment);
  1481. }
  1482. expr = {
  1483. type: Syntax.UpdateExpression,
  1484. operator: token.value,
  1485. argument: expr,
  1486. prefix: true
  1487. };
  1488. return expr;
  1489. }
  1490. if (match('+') || match('-') || match('~') || match('!')) {
  1491. expr = {
  1492. type: Syntax.UnaryExpression,
  1493. operator: lex().value,
  1494. argument: parseUnaryExpression()
  1495. };
  1496. return expr;
  1497. }
  1498. if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
  1499. expr = {
  1500. type: Syntax.UnaryExpression,
  1501. operator: lex().value,
  1502. argument: parseUnaryExpression()
  1503. };
  1504. if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
  1505. throwErrorTolerant({}, Messages.StrictDelete);
  1506. }
  1507. return expr;
  1508. }
  1509. return parsePostfixExpression();
  1510. }
  1511. // 11.5 Multiplicative Operators
  1512. function parseMultiplicativeExpression() {
  1513. var expr = parseUnaryExpression();
  1514. while (match('*') || match('/') || match('%')) {
  1515. expr = {
  1516. type: Syntax.BinaryExpression,
  1517. operator: lex().value,
  1518. left: expr,
  1519. right: parseUnaryExpression()
  1520. };
  1521. }
  1522. return expr;
  1523. }
  1524. // 11.6 Additive Operators
  1525. function parseAdditiveExpression() {
  1526. var expr = parseMultiplicativeExpression();
  1527. while (match('+') || match('-')) {
  1528. expr = {
  1529. type: Syntax.BinaryExpression,
  1530. operator: lex().value,
  1531. left: expr,
  1532. right: parseMultiplicativeExpression()
  1533. };
  1534. }
  1535. return expr;
  1536. }
  1537. // 11.7 Bitwise Shift Operators
  1538. function parseShiftExpression() {
  1539. var expr = parseAdditiveExpression();
  1540. while (match('<<') || match('>>') || match('>>>')) {
  1541. expr = {
  1542. type: Syntax.BinaryExpression,
  1543. operator: lex().value,
  1544. left: expr,
  1545. right: parseAdditiveExpression()
  1546. };
  1547. }
  1548. return expr;
  1549. }
  1550. // 11.8 Relational Operators
  1551. function parseRelationalExpression() {
  1552. var expr, previousAllowIn;
  1553. previousAllowIn = state.allowIn;
  1554. state.allowIn = true;
  1555. expr = parseShiftExpression();
  1556. while (match('<') || match('>') || match('<=') || match('>=') || (previousAllowIn && matchKeyword('in')) || matchKeyword('instanceof')) {
  1557. expr = {
  1558. type: Syntax.BinaryExpression,
  1559. operator: lex().value,
  1560. left: expr,
  1561. right: parseShiftExpression()
  1562. };
  1563. }
  1564. state.allowIn = previousAllowIn;
  1565. return expr;
  1566. }
  1567. // 11.9 Equality Operators
  1568. function parseEqualityExpression() {
  1569. var expr = parseRelationalExpression();
  1570. while (match('==') || match('!=') || match('===') || match('!==')) {
  1571. expr = {
  1572. type: Syntax.BinaryExpression,
  1573. operator: lex().value,
  1574. left: expr,
  1575. right: parseRelationalExpression()
  1576. };
  1577. }
  1578. return expr;
  1579. }
  1580. // 11.10 Binary Bitwise Operators
  1581. function parseBitwiseANDExpression() {
  1582. var expr = parseEqualityExpression();
  1583. while (match('&')) {
  1584. lex();
  1585. expr = {
  1586. type: Syntax.BinaryExpression,
  1587. operator: '&',
  1588. left: expr,
  1589. right: parseEqualityExpression()
  1590. };
  1591. }
  1592. return expr;
  1593. }
  1594. function parseBitwiseXORExpression() {
  1595. var expr = parseBitwiseANDExpression();
  1596. while (match('^')) {
  1597. lex();
  1598. expr = {
  1599. type: Syntax.BinaryExpression,
  1600. operator: '^',
  1601. left: expr,
  1602. right: parseBitwiseANDExpression()
  1603. };
  1604. }
  1605. return expr;
  1606. }
  1607. function parseBitwiseORExpression() {
  1608. var expr = parseBitwiseXORExpression();
  1609. while (match('|')) {
  1610. lex();
  1611. expr = {
  1612. type: Syntax.BinaryExpression,
  1613. operator: '|',
  1614. left: expr,
  1615. right: parseBitwiseXORExpression()
  1616. };
  1617. }
  1618. return expr;
  1619. }
  1620. // 11.11 Binary Logical Operators
  1621. function parseLogicalANDExpression() {
  1622. var expr = parseBitwiseORExpression();
  1623. while (match('&&')) {
  1624. lex();
  1625. expr = {
  1626. type: Syntax.LogicalExpression,
  1627. operator: '&&',
  1628. left: expr,
  1629. right: parseBitwiseORExpression()
  1630. };
  1631. }
  1632. return expr;
  1633. }
  1634. function parseLogicalORExpression() {
  1635. var expr = parseLogicalANDExpression();
  1636. while (match('||')) {
  1637. lex();
  1638. expr = {
  1639. type: Syntax.LogicalExpression,
  1640. operator: '||',
  1641. left: expr,
  1642. right: parseLogicalANDExpression()
  1643. };
  1644. }
  1645. return expr;
  1646. }
  1647. // 11.12 Conditional Operator
  1648. function parseConditionalExpression() {
  1649. var expr, previousAllowIn, consequent;
  1650. expr = parseLogicalORExpression();
  1651. if (match('?')) {
  1652. lex();
  1653. previousAllowIn = state.allowIn;
  1654. state.allowIn = true;
  1655. consequent = parseAssignmentExpression();
  1656. state.allowIn = previousAllowIn;
  1657. expect(':');
  1658. expr = {
  1659. type: Syntax.ConditionalExpression,
  1660. test: expr,
  1661. consequent: consequent,
  1662. alternate: parseAssignmentExpression()
  1663. };
  1664. }
  1665. return expr;
  1666. }
  1667. // 11.13 Assignment Operators
  1668. function parseAssignmentExpression() {
  1669. var token, expr;
  1670. token = lookahead();
  1671. expr = parseConditionalExpression();
  1672. if (matchAssign()) {
  1673. // LeftHandSideExpression
  1674. if (!isLeftHandSide(expr)) {
  1675. throwError({}, Messages.InvalidLHSInAssignment);
  1676. }
  1677. // 11.13.1
  1678. if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
  1679. throwErrorTolerant(token, Messages.StrictLHSAssignment);
  1680. }
  1681. expr = {
  1682. type: Syntax.AssignmentExpression,
  1683. operator: lex().value,
  1684. left: expr,
  1685. right: parseAssignmentExpression()
  1686. };
  1687. }
  1688. return expr;
  1689. }
  1690. // 11.14 Comma Operator
  1691. function parseExpression() {
  1692. var expr = parseAssignmentExpression();
  1693. if (match(',')) {
  1694. expr = {
  1695. type: Syntax.SequenceExpression,
  1696. expressions: [ expr ]
  1697. };
  1698. while (index < length) {
  1699. if (!match(',')) {
  1700. break;
  1701. }
  1702. lex();
  1703. expr.expressions.push(parseAssignmentExpression());
  1704. }
  1705. }
  1706. return expr;
  1707. }
  1708. // 12.1 Block
  1709. function parseStatementList() {
  1710. var list = [],
  1711. statement;
  1712. while (index < length) {
  1713. if (match('}')) {
  1714. break;
  1715. }
  1716. statement = parseSourceElement();
  1717. if (typeof statement === 'undefined') {
  1718. break;
  1719. }
  1720. list.push(statement);
  1721. }
  1722. return list;
  1723. }
  1724. function parseBlock() {
  1725. var block;
  1726. expect('{');
  1727. block = parseStatementList();
  1728. expect('}');
  1729. return {
  1730. type: Syntax.BlockStatement,
  1731. body: block
  1732. };
  1733. }
  1734. // 12.2 Variable Statement
  1735. function parseVariableIdentifier() {
  1736. var token = lex();
  1737. if (token.type !== Token.Identifier) {
  1738. throwUnexpected(token);
  1739. }
  1740. return {
  1741. type: Syntax.Identifier,
  1742. name: token.value
  1743. };
  1744. }
  1745. function parseVariableDeclaration(kind) {
  1746. var id = parseVariableIdentifier(),
  1747. init = null;
  1748. // 12.2.1
  1749. if (strict && isRestrictedWord(id.name)) {
  1750. throwErrorTolerant({}, Messages.StrictVarName);
  1751. }
  1752. if (kind === 'const') {
  1753. expect('=');
  1754. init = parseAssignmentExpression();
  1755. } else if (match('=')) {
  1756. lex();
  1757. init = parseAssignmentExpression();
  1758. }
  1759. return {
  1760. type: Syntax.VariableDeclarator,
  1761. id: id,
  1762. init: init
  1763. };
  1764. }
  1765. function parseVariableDeclarationList(kind) {
  1766. var list = [];
  1767. while (index < length) {
  1768. list.push(parseVariableDeclaration(kind));
  1769. if (!match(',')) {
  1770. break;
  1771. }
  1772. lex();
  1773. }
  1774. return list;
  1775. }
  1776. function parseVariableStatement() {
  1777. var declarations;
  1778. expectKeyword('var');
  1779. declarations = parseVariableDeclarationList();
  1780. consumeSemicolon();
  1781. return {
  1782. type: Syntax.VariableDeclaration,
  1783. declarations: declarations,
  1784. kind: 'var'
  1785. };
  1786. }
  1787. // kind may be `const` or `let`
  1788. // Both are experimental and not in the specification yet.
  1789. // see http://wiki.ecmascript.org/doku.php?id=harmony:const
  1790. // and http://wiki.ecmascript.org/doku.php?id=harmony:let
  1791. function parseConstLetDeclaration(kind) {
  1792. var declarations;
  1793. expectKeyword(kind);
  1794. declarations = parseVariableDeclarationList(kind);
  1795. consumeSemicolon();
  1796. return {
  1797. type: Syntax.VariableDeclaration,
  1798. declarations: declarations,
  1799. kind: kind
  1800. };
  1801. }
  1802. // 12.3 Empty Statement
  1803. function parseEmptyStatement() {
  1804. expect(';');
  1805. return {
  1806. type: Syntax.EmptyStatement
  1807. };
  1808. }
  1809. // 12.4 Expression Statement
  1810. function parseExpressionStatement() {
  1811. var expr = parseExpression();
  1812. consumeSemicolon();
  1813. return {
  1814. type: Syntax.ExpressionStatement,
  1815. expression: expr
  1816. };
  1817. }
  1818. // 12.5 If statement
  1819. function parseIfStatement() {
  1820. var test, consequent, alternate;
  1821. expectKeyword('if');
  1822. expect('(');
  1823. test = parseExpression();
  1824. expect(')');
  1825. consequent = parseStatement();
  1826. if (matchKeyword('else')) {
  1827. lex();
  1828. alternate = parseStatement();
  1829. } else {
  1830. alternate = null;
  1831. }
  1832. return {
  1833. type: Syntax.IfStatement,
  1834. test: test,
  1835. consequent: consequent,
  1836. alternate: alternate
  1837. };
  1838. }
  1839. // 12.6 Iteration Statements
  1840. function parseDoWhileStatement() {
  1841. var body, test, oldInIteration;
  1842. expectKeyword('do');
  1843. oldInIteration = state.inIteration;
  1844. state.inIteration = true;
  1845. body = parseStatement();
  1846. state.inIteration = oldInIteration;
  1847. expectKeyword('while');
  1848. expect('(');
  1849. test = parseExpression();
  1850. expect(')');
  1851. if (match(';')) {
  1852. lex();
  1853. }
  1854. return {
  1855. type: Syntax.DoWhileStatement,
  1856. body: body,
  1857. test: test
  1858. };
  1859. }
  1860. function parseWhileStatement() {
  1861. var test, body, oldInIteration;
  1862. expectKeyword('while');
  1863. expect('(');
  1864. test = parseExpression();
  1865. expect(')');
  1866. oldInIteration = state.inIteration;
  1867. state.inIteration = true;
  1868. body = parseStatement();
  1869. state.inIteration = oldInIteration;
  1870. return {
  1871. type: Syntax.WhileStatement,
  1872. test: test,
  1873. body: body
  1874. };
  1875. }
  1876. function parseForVariableDeclaration() {
  1877. var token = lex();
  1878. return {
  1879. type: Syntax.VariableDeclaration,
  1880. declarations: parseVariableDeclarationList(),
  1881. kind: token.value
  1882. };
  1883. }
  1884. function parseForStatement() {
  1885. var init, test, update, left, right, body, oldInIteration;
  1886. init = test = update = null;
  1887. expectKeyword('for');
  1888. expect('(');
  1889. if (match(';')) {
  1890. lex();
  1891. } else {
  1892. if (matchKeyword('var') || matchKeyword('let')) {
  1893. state.allowIn = false;
  1894. init = parseForVariableDeclaration();
  1895. state.allowIn = true;
  1896. if (init.declarations.length === 1 && matchKeyword('in')) {
  1897. lex();
  1898. left = init;
  1899. right = parseExpression();
  1900. init = null;
  1901. }
  1902. } else {
  1903. state.allowIn = false;
  1904. init = parseExpression();
  1905. state.allowIn = true;
  1906. if (matchKeyword('in')) {
  1907. // LeftHandSideExpression
  1908. if (!isLeftHandSide(init)) {
  1909. throwError({}, Messages.InvalidLHSInForIn);
  1910. }
  1911. lex();
  1912. left = init;
  1913. right = parseExpression();
  1914. init = null;
  1915. }
  1916. }
  1917. if (typeof left === 'undefined') {
  1918. expect(';');
  1919. }
  1920. }
  1921. if (typeof left === 'undefined') {
  1922. if (!match(';')) {
  1923. test = parseExpression();
  1924. }
  1925. expect(';');
  1926. if (!match(')')) {
  1927. update = parseExpression();
  1928. }
  1929. }
  1930. expect(')');
  1931. oldInIteration = state.inIteration;
  1932. state.inIteration = true;
  1933. body = parseStatement();
  1934. state.inIteration = oldInIteration;
  1935. if (typeof left === 'undefined') {
  1936. return {
  1937. type: Syntax.ForStatement,
  1938. init: init,
  1939. test: test,
  1940. update: update,
  1941. body: body
  1942. };
  1943. }
  1944. return {
  1945. type: Syntax.ForInStatement,
  1946. left: left,
  1947. right: right,
  1948. body: body,
  1949. each: false
  1950. };
  1951. }
  1952. // 12.7 The continue statement
  1953. function parseContinueStatement() {
  1954. var token, label = null;
  1955. expectKeyword('continue');
  1956. // Optimize the most common form: 'continue;'.
  1957. if (source[index] === ';') {
  1958. lex();
  1959. if (!state.inIteration) {
  1960. throwError({}, Messages.IllegalContinue);
  1961. }
  1962. return {
  1963. type: Syntax.ContinueStatement,
  1964. label: null
  1965. };
  1966. }
  1967. if (peekLineTerminator()) {
  1968. if (!state.inIteration) {
  1969. throwError({}, Messages.IllegalContinue);
  1970. }
  1971. return {
  1972. type: Syntax.ContinueStatement,
  1973. label: null
  1974. };
  1975. }
  1976. token = lookahead();
  1977. if (token.type === Token.Identifier) {
  1978. label = parseVariableIdentifier();
  1979. if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
  1980. throwError({}, Messages.UnknownLabel, label.name);
  1981. }
  1982. }
  1983. consumeSemicolon();
  1984. if (label === null && !state.inIteration) {
  1985. throwError({}, Messages.IllegalContinue);
  1986. }
  1987. return {
  1988. type: Syntax.ContinueStatement,
  1989. label: label
  1990. };
  1991. }
  1992. // 12.8 The break statement
  1993. function parseBreakStatement() {
  1994. var token, label = null;
  1995. expectKeyword('break');
  1996. // Optimize the most common form: 'break;'.
  1997. if (source[index] === ';') {
  1998. lex();
  1999. if (!(state.inIteration || state.inSwitch)) {
  2000. throwError({}, Messages.IllegalBreak);
  2001. }
  2002. return {
  2003. type: Syntax.BreakStatement,
  2004. label: null
  2005. };
  2006. }
  2007. if (peekLineTerminator()) {
  2008. if (!(state.inIteration || state.inSwitch)) {
  2009. throwError({}, Messages.IllegalBreak);
  2010. }
  2011. return {
  2012. type: Syntax.BreakStatement,
  2013. label: null
  2014. };
  2015. }
  2016. token = lookahead();
  2017. if (token.type === Token.Identifier) {
  2018. label = parseVariableIdentifier();
  2019. if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
  2020. throwError({}, Messages.UnknownLabel, label.name);
  2021. }
  2022. }
  2023. consumeSemicolon();
  2024. if (label === null && !(state.inIteration || state.inSwitch)) {
  2025. throwError({}, Messages.IllegalBreak);
  2026. }
  2027. return {
  2028. type: Syntax.BreakStatement,
  2029. label: label
  2030. };
  2031. }
  2032. // 12.9 The return statement
  2033. function parseReturnStatement() {
  2034. var token, argument = null;
  2035. expectKeyword('return');
  2036. if (!state.inFunctionBody) {
  2037. throwErrorTolerant({}, Messages.IllegalReturn);
  2038. }
  2039. // 'return' followed by a space and an identifier is very common.
  2040. if (source[index] === ' ') {
  2041. if (isIdentifierStart(source[index + 1])) {
  2042. argument = parseExpression();
  2043. consumeSemicolon();
  2044. return {
  2045. type: Syntax.ReturnStatement,
  2046. argument: argument
  2047. };
  2048. }
  2049. }
  2050. if (peekLineTerminator()) {
  2051. return {
  2052. type: Syntax.ReturnStatement,
  2053. argument: null
  2054. };
  2055. }
  2056. if (!match(';')) {
  2057. token = lookahead();
  2058. if (!match('}') && token.type !== Token.EOF) {
  2059. argument = parseExpression();
  2060. }
  2061. }
  2062. consumeSemicolon();
  2063. return {
  2064. type: Syntax.ReturnStatement,
  2065. argument: argument
  2066. };
  2067. }
  2068. // 12.10 The with statement
  2069. function parseWithStatement() {
  2070. var object, body;
  2071. if (strict) {
  2072. throwErrorTolerant({}, Messages.StrictModeWith);
  2073. }
  2074. expectKeyword('with');
  2075. expect('(');
  2076. object = parseExpression();
  2077. expect(')');
  2078. body = parseStatement();
  2079. return {
  2080. type: Syntax.WithStatement,
  2081. object: object,
  2082. body: body
  2083. };
  2084. }
  2085. // 12.10 The swith statement
  2086. function parseSwitchCase() {
  2087. var test,
  2088. consequent = [],
  2089. statement;
  2090. if (matchKeyword('default')) {
  2091. lex();
  2092. test = null;
  2093. } else {
  2094. expectKeyword('case');
  2095. test = parseExpression();
  2096. }
  2097. expect(':');
  2098. while (index < length) {
  2099. if (match('}') || matchKeyword('default') || matchKeyword('case')) {
  2100. break;
  2101. }
  2102. statement = parseStatement();
  2103. if (typeof statement === 'undefined') {
  2104. break;
  2105. }
  2106. consequent.push(statement);
  2107. }
  2108. return {
  2109. type: Syntax.SwitchCase,
  2110. test: test,
  2111. consequent: consequent
  2112. };
  2113. }
  2114. function parseSwitchStatement() {
  2115. var discriminant, cases, clause, oldInSwitch, defaultFound;
  2116. expectKeyword('switch');
  2117. expect('(');
  2118. discriminant = parseExpression();
  2119. expect(')');
  2120. expect('{');
  2121. if (match('}')) {
  2122. lex();
  2123. return {
  2124. type: Syntax.SwitchStatement,
  2125. discriminant: discriminant
  2126. };
  2127. }
  2128. cases = [];
  2129. oldInSwitch = state.inSwitch;
  2130. state.inSwitch = true;
  2131. defaultFound = false;
  2132. while (index < length) {
  2133. if (match('}')) {
  2134. break;
  2135. }
  2136. clause = parseSwitchCase();
  2137. if (clause.test === null) {
  2138. if (defaultFound) {
  2139. throwError({}, Messages.MultipleDefaultsInSwitch);
  2140. }
  2141. defaultFound = true;
  2142. }
  2143. cases.push(clause);
  2144. }
  2145. state.inSwitch = oldInSwitch;
  2146. expect('}');
  2147. return {
  2148. type: Syntax.SwitchStatement,
  2149. discriminant: discriminant,
  2150. cases: cases
  2151. };
  2152. }
  2153. // 12.13 The throw statement
  2154. function parseThrowStatement() {
  2155. var argument;
  2156. expectKeyword('throw');
  2157. if (peekLineTerminator()) {
  2158. throwError({}, Messages.NewlineAfterThrow);
  2159. }
  2160. argument = parseExpression();
  2161. consumeSemicolon();
  2162. return {
  2163. type: Syntax.ThrowStatement,
  2164. argument: argument
  2165. };
  2166. }
  2167. // 12.14 The try statement
  2168. function parseCatchClause() {
  2169. var param;
  2170. expectKeyword('catch');
  2171. expect('(');
  2172. if (!match(')')) {
  2173. param = parseExpression();
  2174. // 12.14.1
  2175. if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) {
  2176. throwErrorTolerant({}, Messages.StrictCatchVariable);
  2177. }
  2178. }
  2179. expect(')');
  2180. return {
  2181. type: Syntax.CatchClause,
  2182. param: param,
  2183. body: parseBlock()
  2184. };
  2185. }
  2186. function parseTryStatement() {
  2187. var block, handlers = [], finalizer = null;
  2188. expectKeyword('try');
  2189. block = parseBlock();
  2190. if (matchKeyword('catch')) {
  2191. handlers.push(parseCatchClause());
  2192. }
  2193. if (matchKeyword('finally')) {
  2194. lex();
  2195. finalizer = parseBlock();
  2196. }
  2197. if (handlers.length === 0 && !finalizer) {
  2198. throwError({}, Messages.NoCatchOrFinally);
  2199. }
  2200. return {
  2201. type: Syntax.TryStatement,
  2202. block: block,
  2203. guardedHandlers: [],
  2204. handlers: handlers,
  2205. finalizer: finalizer
  2206. };
  2207. }
  2208. // 12.15 The debugger statement
  2209. function parseDebuggerStatement() {
  2210. expectKeyword('debugger');
  2211. consumeSemicolon();
  2212. return {
  2213. type: Syntax.DebuggerStatement
  2214. };
  2215. }
  2216. // 12 Statements
  2217. function parseStatement() {
  2218. var token = lookahead(),
  2219. expr,
  2220. labeledBody;
  2221. if (token.type === Token.EOF) {
  2222. throwUnexpected(token);
  2223. }
  2224. if (token.type === Token.Punctuator) {
  2225. switch (token.value) {
  2226. case ';':
  2227. return parseEmptyStatement();
  2228. case '{':
  2229. return parseBlock();
  2230. case '(':
  2231. return parseExpressionStatement();
  2232. default:
  2233. break;
  2234. }
  2235. }
  2236. if (token.type === Token.Keyword) {
  2237. switch (token.value) {
  2238. case 'break':
  2239. return parseBreakStatement();
  2240. case 'continue':
  2241. return parseContinueStatement();
  2242. case 'debugger':
  2243. return parseDebuggerStatement();
  2244. case 'do':
  2245. return parseDoWhileStatement();
  2246. case 'for':
  2247. return parseForStatement();
  2248. case 'function':
  2249. return parseFunctionDeclaration();
  2250. case 'if':
  2251. return parseIfStatement();
  2252. case 'return':
  2253. return parseReturnStatement();
  2254. case 'switch':
  2255. return parseSwitchStatement();
  2256. case 'throw':
  2257. return parseThrowStatement();
  2258. case 'try':
  2259. return parseTryStatement();
  2260. case 'var':
  2261. return parseVariableStatement();
  2262. case 'while':
  2263. return parseWhileStatement();
  2264. case 'with':
  2265. return parseWithStatement();
  2266. default:
  2267. break;
  2268. }
  2269. }
  2270. expr = parseExpression();
  2271. // 12.12 Labelled Statements
  2272. if ((expr.type === Syntax.Identifier) && match(':')) {
  2273. lex();
  2274. if (Object.prototype.hasOwnProperty.call(state.labelSet, expr.name)) {
  2275. throwError({}, Messages.Redeclaration, 'Label', expr.name);
  2276. }
  2277. state.labelSet[expr.name] = true;
  2278. labeledBody = parseStatement();
  2279. delete state.labelSet[expr.name];
  2280. return {
  2281. type: Syntax.LabeledStatement,
  2282. label: expr,
  2283. body: labeledBody
  2284. };
  2285. }
  2286. consumeSemicolon();
  2287. return {
  2288. type: Syntax.ExpressionStatement,
  2289. expression: expr
  2290. };
  2291. }
  2292. // 13 Function Definition
  2293. function parseFunctionSourceElements() {
  2294. var sourceElement, sourceElements = [], token, directive, firstRestricted,
  2295. oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody;
  2296. expect('{');
  2297. while (index < length) {
  2298. token = lookahead();
  2299. if (token.type !== Token.StringLiteral) {
  2300. break;
  2301. }
  2302. sourceElement = parseSourceElement();
  2303. sourceElements.push(sourceElement);
  2304. if (sourceElement.expression.type !== Syntax.Literal) {
  2305. // this is not directive
  2306. break;
  2307. }
  2308. directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
  2309. if (directive === 'use strict') {
  2310. strict = true;
  2311. if (firstRestricted) {
  2312. throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
  2313. }
  2314. } else {
  2315. if (!firstRestricted && token.octal) {
  2316. firstRestricted = token;
  2317. }
  2318. }
  2319. }
  2320. oldLabelSet = state.labelSet;
  2321. oldInIteration = state.inIteration;
  2322. oldInSwitch = state.inSwitch;
  2323. oldInFunctionBody = state.inFunctionBody;
  2324. state.labelSet = {};
  2325. state.inIteration = false;
  2326. state.inSwitch = false;
  2327. state.inFunctionBody = true;
  2328. while (index < length) {
  2329. if (match('}')) {
  2330. break;
  2331. }
  2332. sourceElement = parseSourceElement();
  2333. if (typeof sourceElement === 'undefined') {
  2334. break;
  2335. }
  2336. sourceElements.push(sourceElement);
  2337. }
  2338. expect('}');
  2339. state.labelSet = oldLabelSet;
  2340. state.inIteration = oldInIteration;
  2341. state.inSwitch = oldInSwitch;
  2342. state.inFunctionBody = oldInFunctionBody;
  2343. return {
  2344. type: Syntax.BlockStatement,
  2345. body: sourceElements
  2346. };
  2347. }
  2348. function parseFunctionDeclaration() {
  2349. var id, param, params = [], body, token, stricted, firstRestricted, message, previousStrict, paramSet;
  2350. expectKeyword('function');
  2351. token = lookahead();
  2352. id = parseVariableIdentifier();
  2353. if (strict) {
  2354. if (isRestrictedWord(token.value)) {
  2355. throwErrorTolerant(token, Messages.StrictFunctionName);
  2356. }
  2357. } else {
  2358. if (isRestrictedWord(token.value)) {
  2359. firstRestricted = token;
  2360. message = Messages.StrictFunctionName;
  2361. } else if (isStrictModeReservedWord(token.value)) {
  2362. firstRestricted = token;
  2363. message = Messages.StrictReservedWord;
  2364. }
  2365. }
  2366. expect('(');
  2367. if (!match(')')) {
  2368. paramSet = {};
  2369. while (index < length) {
  2370. token = lookahead();
  2371. param = parseVariableIdentifier();
  2372. if (strict) {
  2373. if (isRestrictedWord(token.value)) {
  2374. stricted = token;
  2375. message = Messages.StrictParamName;
  2376. }
  2377. if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
  2378. stricted = token;
  2379. message = Messages.StrictParamDupe;
  2380. }
  2381. } else if (!firstRestricted) {
  2382. if (isRestrictedWord(token.value)) {
  2383. firstRestricted = token;
  2384. message = Messages.StrictParamName;
  2385. } else if (isStrictModeReservedWord(token.value)) {
  2386. firstRestricted = token;
  2387. message = Messages.StrictReservedWord;
  2388. } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
  2389. firstRestricted = token;
  2390. message = Messages.StrictParamDupe;
  2391. }
  2392. }
  2393. params.push(param);
  2394. paramSet[param.name] = true;
  2395. if (match(')')) {
  2396. break;
  2397. }
  2398. expect(',');
  2399. }
  2400. }
  2401. expect(')');
  2402. previousStrict = strict;
  2403. body = parseFunctionSourceElements();
  2404. if (strict && firstRestricted) {
  2405. throwError(firstRestricted, message);
  2406. }
  2407. if (strict && stricted) {
  2408. throwErrorTolerant(stricted, message);
  2409. }
  2410. strict = previousStrict;
  2411. return {
  2412. type: Syntax.FunctionDeclaration,
  2413. id: id,
  2414. params: params,
  2415. defaults: [],
  2416. body: body,
  2417. rest: null,
  2418. generator: false,
  2419. expression: false
  2420. };
  2421. }
  2422. function parseFunctionExpression() {
  2423. var token, id = null, stricted, firstRestricted, message, param, params = [], body, previousStrict, paramSet;
  2424. expectKeyword('function');
  2425. if (!match('(')) {
  2426. token = lookahead();
  2427. id = parseVariableIdentifier();
  2428. if (strict) {
  2429. if (isRestrictedWord(token.value)) {
  2430. throwErrorTolerant(token, Messages.StrictFunctionName);
  2431. }
  2432. } else {
  2433. if (isRestrictedWord(token.value)) {
  2434. firstRestricted = token;
  2435. message = Messages.StrictFunctionName;
  2436. } else if (isStrictModeReservedWord(token.value)) {
  2437. firstRestricted = token;
  2438. message = Messages.StrictReservedWord;
  2439. }
  2440. }
  2441. }
  2442. expect('(');
  2443. if (!match(')')) {
  2444. paramSet = {};
  2445. while (index < length) {
  2446. token = lookahead();
  2447. param = parseVariableIdentifier();
  2448. if (strict) {
  2449. if (isRestrictedWord(token.value)) {
  2450. stricted = token;
  2451. message = Messages.StrictParamName;
  2452. }
  2453. if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
  2454. stricted = token;
  2455. message = Messages.StrictParamDupe;
  2456. }
  2457. } else if (!firstRestricted) {
  2458. if (isRestrictedWord(token.value)) {
  2459. firstRestricted = token;
  2460. message = Messages.StrictParamName;
  2461. } else if (isStrictModeReservedWord(token.value)) {
  2462. firstRestricted = token;
  2463. message = Messages.StrictReservedWord;
  2464. } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
  2465. firstRestricted = token;
  2466. message = Messages.StrictParamDupe;
  2467. }
  2468. }
  2469. params.push(param);
  2470. paramSet[param.name] = true;
  2471. if (match(')')) {
  2472. break;
  2473. }
  2474. expect(',');
  2475. }
  2476. }
  2477. expect(')');
  2478. previousStrict = strict;
  2479. body = parseFunctionSourceElements();
  2480. if (strict && firstRestricted) {
  2481. throwError(firstRestricted, message);
  2482. }
  2483. if (strict && stricted) {
  2484. throwErrorTolerant(stricted, message);
  2485. }
  2486. strict = previousStrict;
  2487. return {
  2488. type: Syntax.FunctionExpression,
  2489. id: id,
  2490. params: params,
  2491. defaults: [],
  2492. body: body,
  2493. rest: null,
  2494. generator: false,
  2495. expression: false
  2496. };
  2497. }
  2498. // 14 Program
  2499. function parseSourceElement() {
  2500. var token = lookahead();
  2501. if (token.type === Token.Keyword) {
  2502. switch (token.value) {
  2503. case 'const':
  2504. case 'let':
  2505. return parseConstLetDeclaration(token.value);
  2506. case 'function':
  2507. return parseFunctionDeclaration();
  2508. default:
  2509. return parseStatement();
  2510. }
  2511. }
  2512. if (token.type !== Token.EOF) {
  2513. return parseStatement();
  2514. }
  2515. }
  2516. function parseSourceElements() {
  2517. var sourceElement, sourceElements = [], token, directive, firstRestricted;
  2518. while (index < length) {
  2519. token = lookahead();
  2520. if (token.type !== Token.StringLiteral) {
  2521. break;
  2522. }
  2523. sourceElement = parseSourceElement();
  2524. sourceElements.push(sourceElement);
  2525. if (sourceElement.expression.type !== Syntax.Literal) {
  2526. // this is not directive
  2527. break;
  2528. }
  2529. directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
  2530. if (directive === 'use strict') {
  2531. strict = true;
  2532. if (firstRestricted) {
  2533. throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
  2534. }
  2535. } else {
  2536. if (!firstRestricted && token.octal) {
  2537. firstRestricted = token;
  2538. }
  2539. }
  2540. }
  2541. while (index < length) {
  2542. sourceElement = parseSourceElement();
  2543. if (typeof sourceElement === 'undefined') {
  2544. break;
  2545. }
  2546. sourceElements.push(sourceElement);
  2547. }
  2548. return sourceElements;
  2549. }
  2550. function parseProgram() {
  2551. var program;
  2552. strict = false;
  2553. program = {
  2554. type: Syntax.Program,
  2555. body: parseSourceElements()
  2556. };
  2557. return program;
  2558. }
  2559. // The following functions are needed only when the option to preserve
  2560. // the comments is active.
  2561. function addComment(type, value, start, end, loc) {
  2562. assert(typeof start === 'number', 'Comment must have valid position');
  2563. // Because the way the actual token is scanned, often the comments
  2564. // (if any) are skipped twice during the lexical analysis.
  2565. // Thus, we need to skip adding a comment if the comment array already
  2566. // handled it.
  2567. if (extra.comments.length > 0) {
  2568. if (extra.comments[extra.comments.length - 1].range[1] > start) {
  2569. return;
  2570. }
  2571. }
  2572. extra.comments.push({
  2573. type: type,
  2574. value: value,
  2575. range: [start, end],
  2576. loc: loc
  2577. });
  2578. }
  2579. function scanComment() {
  2580. var comment, ch, loc, start, blockComment, lineComment;
  2581. comment = '';
  2582. blockComment = false;
  2583. lineComment = false;
  2584. while (index < length) {
  2585. ch = source[index];
  2586. if (lineComment) {
  2587. ch = source[index++];
  2588. if (isLineTerminator(ch)) {
  2589. loc.end = {
  2590. line: lineNumber,
  2591. column: index - lineStart - 1
  2592. };
  2593. lineComment = false;
  2594. addComment('Line', comment, start, index - 1, loc);
  2595. if (ch === '\r' && source[index] === '\n') {
  2596. ++index;
  2597. }
  2598. ++lineNumber;
  2599. lineStart = index;
  2600. comment = '';
  2601. } else if (index >= length) {
  2602. lineComment = false;
  2603. comment += ch;
  2604. loc.end = {
  2605. line: lineNumber,
  2606. column: length - lineStart
  2607. };
  2608. addComment('Line', comment, start, length, loc);
  2609. } else {
  2610. comment += ch;
  2611. }
  2612. } else if (blockComment) {
  2613. if (isLineTerminator(ch)) {
  2614. if (ch === '\r' && source[index + 1] === '\n') {
  2615. ++index;
  2616. comment += '\r\n';
  2617. } else {
  2618. comment += ch;
  2619. }
  2620. ++lineNumber;
  2621. ++index;
  2622. lineStart = index;
  2623. if (index >= length) {
  2624. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  2625. }
  2626. } else {
  2627. ch = source[index++];
  2628. if (index >= length) {
  2629. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  2630. }
  2631. comment += ch;
  2632. if (ch === '*') {
  2633. ch = source[index];
  2634. if (ch === '/') {
  2635. comment = comment.substr(0, comment.length - 1);
  2636. blockComment = false;
  2637. ++index;
  2638. loc.end = {
  2639. line: lineNumber,
  2640. column: index - lineStart
  2641. };
  2642. addComment('Block', comment, start, index, loc);
  2643. comment = '';
  2644. }
  2645. }
  2646. }
  2647. } else if (ch === '/') {
  2648. ch = source[index + 1];
  2649. if (ch === '/') {
  2650. loc = {
  2651. start: {
  2652. line: lineNumber,
  2653. column: index - lineStart
  2654. }
  2655. };
  2656. start = index;
  2657. index += 2;
  2658. lineComment = true;
  2659. if (index >= length) {
  2660. loc.end = {
  2661. line: lineNumber,
  2662. column: index - lineStart
  2663. };
  2664. lineComment = false;
  2665. addComment('Line', comment, start, index, loc);
  2666. }
  2667. } else if (ch === '*') {
  2668. start = index;
  2669. index += 2;
  2670. blockComment = true;
  2671. loc = {
  2672. start: {
  2673. line: lineNumber,
  2674. column: index - lineStart - 2
  2675. }
  2676. };
  2677. if (index >= length) {
  2678. throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  2679. }
  2680. } else {
  2681. break;
  2682. }
  2683. } else if (isWhiteSpace(ch)) {
  2684. ++index;
  2685. } else if (isLineTerminator(ch)) {
  2686. ++index;
  2687. if (ch === '\r' && source[index] === '\n') {
  2688. ++index;
  2689. }
  2690. ++lineNumber;
  2691. lineStart = index;
  2692. } else {
  2693. break;
  2694. }
  2695. }
  2696. }
  2697. function filterCommentLocation() {
  2698. var i, entry, comment, comments = [];
  2699. for (i = 0; i < extra.comments.length; ++i) {
  2700. entry = extra.comments[i];
  2701. comment = {
  2702. type: entry.type,
  2703. value: entry.value
  2704. };
  2705. if (extra.range) {
  2706. comment.range = entry.range;
  2707. }
  2708. if (extra.loc) {
  2709. comment.loc = entry.loc;
  2710. }
  2711. comments.push(comment);
  2712. }
  2713. extra.comments = comments;
  2714. }
  2715. function collectToken() {
  2716. var start, loc, token, range, value;
  2717. skipComment();
  2718. start = index;
  2719. loc = {
  2720. start: {
  2721. line: lineNumber,
  2722. column: index - lineStart
  2723. }
  2724. };
  2725. token = extra.advance();
  2726. loc.end = {
  2727. line: lineNumber,
  2728. column: index - lineStart
  2729. };
  2730. if (token.type !== Token.EOF) {
  2731. range = [token.range[0], token.range[1]];
  2732. value = sliceSource(token.range[0], token.range[1]);
  2733. extra.tokens.push({
  2734. type: TokenName[token.type],
  2735. value: value,
  2736. range: range,
  2737. loc: loc
  2738. });
  2739. }
  2740. return token;
  2741. }
  2742. function collectRegex() {
  2743. var pos, loc, regex, token;
  2744. skipComment();
  2745. pos = index;
  2746. loc = {
  2747. start: {
  2748. line: lineNumber,
  2749. column: index - lineStart
  2750. }
  2751. };
  2752. regex = extra.scanRegExp();
  2753. loc.end = {
  2754. line: lineNumber,
  2755. column: index - lineStart
  2756. };
  2757. // Pop the previous token, which is likely '/' or '/='
  2758. if (extra.tokens.length > 0) {
  2759. token = extra.tokens[extra.tokens.length - 1];
  2760. if (token.range[0] === pos && token.type === 'Punctuator') {
  2761. if (token.value === '/' || token.value === '/=') {
  2762. extra.tokens.pop();
  2763. }
  2764. }
  2765. }
  2766. extra.tokens.push({
  2767. type: 'RegularExpression',
  2768. value: regex.literal,
  2769. range: [pos, index],
  2770. loc: loc
  2771. });
  2772. return regex;
  2773. }
  2774. function filterTokenLocation() {
  2775. var i, entry, token, tokens = [];
  2776. for (i = 0; i < extra.tokens.length; ++i) {
  2777. entry = extra.tokens[i];
  2778. token = {
  2779. type: entry.type,
  2780. value: entry.value
  2781. };
  2782. if (extra.range) {
  2783. token.range = entry.range;
  2784. }
  2785. if (extra.loc) {
  2786. token.loc = entry.loc;
  2787. }
  2788. tokens.push(token);
  2789. }
  2790. extra.tokens = tokens;
  2791. }
  2792. function createLiteral(token) {
  2793. return {
  2794. type: Syntax.Literal,
  2795. value: token.value
  2796. };
  2797. }
  2798. function createRawLiteral(token) {
  2799. return {
  2800. type: Syntax.Literal,
  2801. value: token.value,
  2802. raw: sliceSource(token.range[0], token.range[1])
  2803. };
  2804. }
  2805. function createLocationMarker() {
  2806. var marker = {};
  2807. marker.range = [index, index];
  2808. marker.loc = {
  2809. start: {
  2810. line: lineNumber,
  2811. column: index - lineStart
  2812. },
  2813. end: {
  2814. line: lineNumber,
  2815. column: index - lineStart
  2816. }
  2817. };
  2818. marker.end = function () {
  2819. this.range[1] = index;
  2820. this.loc.end.line = lineNumber;
  2821. this.loc.end.column = index - lineStart;
  2822. };
  2823. marker.applyGroup = function (node) {
  2824. if (extra.range) {
  2825. node.groupRange = [this.range[0], this.range[1]];
  2826. }
  2827. if (extra.loc) {
  2828. node.groupLoc = {
  2829. start: {
  2830. line: this.loc.start.line,
  2831. column: this.loc.start.column
  2832. },
  2833. end: {
  2834. line: this.loc.end.line,
  2835. column: this.loc.end.column
  2836. }
  2837. };
  2838. }
  2839. };
  2840. marker.apply = function (node) {
  2841. if (extra.range) {
  2842. node.range = [this.range[0], this.range[1]];
  2843. }
  2844. if (extra.loc) {
  2845. node.loc = {
  2846. start: {
  2847. line: this.loc.start.line,
  2848. column: this.loc.start.column
  2849. },
  2850. end: {
  2851. line: this.loc.end.line,
  2852. column: this.loc.end.column
  2853. }
  2854. };
  2855. }
  2856. };
  2857. return marker;
  2858. }
  2859. function trackGroupExpression() {
  2860. var marker, expr;
  2861. skipComment();
  2862. marker = createLocationMarker();
  2863. expect('(');
  2864. expr = parseExpression();
  2865. expect(')');
  2866. marker.end();
  2867. marker.applyGroup(expr);
  2868. return expr;
  2869. }
  2870. function trackLeftHandSideExpression() {
  2871. var marker, expr;
  2872. skipComment();
  2873. marker = createLocationMarker();
  2874. expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
  2875. while (match('.') || match('[')) {
  2876. if (match('[')) {
  2877. expr = {
  2878. type: Syntax.MemberExpression,
  2879. computed: true,
  2880. object: expr,
  2881. property: parseComputedMember()
  2882. };
  2883. marker.end();
  2884. marker.apply(expr);
  2885. } else {
  2886. expr = {
  2887. type: Syntax.MemberExpression,
  2888. computed: false,
  2889. object: expr,
  2890. property: parseNonComputedMember()
  2891. };
  2892. marker.end();
  2893. marker.apply(expr);
  2894. }
  2895. }
  2896. return expr;
  2897. }
  2898. function trackLeftHandSideExpressionAllowCall() {
  2899. var marker, expr;
  2900. skipComment();
  2901. marker = createLocationMarker();
  2902. expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
  2903. while (match('.') || match('[') || match('(')) {
  2904. if (match('(')) {
  2905. expr = {
  2906. type: Syntax.CallExpression,
  2907. callee: expr,
  2908. 'arguments': parseArguments()
  2909. };
  2910. marker.end();
  2911. marker.apply(expr);
  2912. } else if (match('[')) {
  2913. expr = {
  2914. type: Syntax.MemberExpression,
  2915. computed: true,
  2916. object: expr,
  2917. property: parseComputedMember()
  2918. };
  2919. marker.end();
  2920. marker.apply(expr);
  2921. } else {
  2922. expr = {
  2923. type: Syntax.MemberExpression,
  2924. computed: false,
  2925. object: expr,
  2926. property: parseNonComputedMember()
  2927. };
  2928. marker.end();
  2929. marker.apply(expr);
  2930. }
  2931. }
  2932. return expr;
  2933. }
  2934. function filterGroup(node) {
  2935. var n, i, entry;
  2936. n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {};
  2937. for (i in node) {
  2938. if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') {
  2939. entry = node[i];
  2940. if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) {
  2941. n[i] = entry;
  2942. } else {
  2943. n[i] = filterGroup(entry);
  2944. }
  2945. }
  2946. }
  2947. return n;
  2948. }
  2949. function wrapTrackingFunction(range, loc) {
  2950. return function (parseFunction) {
  2951. function isBinary(node) {
  2952. return node.type === Syntax.LogicalExpression ||
  2953. node.type === Syntax.BinaryExpression;
  2954. }
  2955. function visit(node) {
  2956. var start, end;
  2957. if (isBinary(node.left)) {
  2958. visit(node.left);
  2959. }
  2960. if (isBinary(node.right)) {
  2961. visit(node.right);
  2962. }
  2963. if (range) {
  2964. if (node.left.groupRange || node.right.groupRange) {
  2965. start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0];
  2966. end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1];
  2967. node.range = [start, end];
  2968. } else if (typeof node.range === 'undefined') {
  2969. start = node.left.range[0];
  2970. end = node.right.range[1];
  2971. node.range = [start, end];
  2972. }
  2973. }
  2974. if (loc) {
  2975. if (node.left.groupLoc || node.right.groupLoc) {
  2976. start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start;
  2977. end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end;
  2978. node.loc = {
  2979. start: start,
  2980. end: end
  2981. };
  2982. } else if (typeof node.loc === 'undefined') {
  2983. node.loc = {
  2984. start: node.left.loc.start,
  2985. end: node.right.loc.end
  2986. };
  2987. }
  2988. }
  2989. }
  2990. return function () {
  2991. var marker, node;
  2992. skipComment();
  2993. marker = createLocationMarker();
  2994. node = parseFunction.apply(null, arguments);
  2995. marker.end();
  2996. if (range && typeof node.range === 'undefined') {
  2997. marker.apply(node);
  2998. }
  2999. if (loc && typeof node.loc === 'undefined') {
  3000. marker.apply(node);
  3001. }
  3002. if (isBinary(node)) {
  3003. visit(node);
  3004. }
  3005. return node;
  3006. };
  3007. };
  3008. }
  3009. function patch() {
  3010. var wrapTracking;
  3011. if (extra.comments) {
  3012. extra.skipComment = skipComment;
  3013. skipComment = scanComment;
  3014. }
  3015. if (extra.raw) {
  3016. extra.createLiteral = createLiteral;
  3017. createLiteral = createRawLiteral;
  3018. }
  3019. if (extra.range || extra.loc) {
  3020. extra.parseGroupExpression = parseGroupExpression;
  3021. extra.parseLeftHandSideExpression = parseLeftHandSideExpression;
  3022. extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall;
  3023. parseGroupExpression = trackGroupExpression;
  3024. parseLeftHandSideExpression = trackLeftHandSideExpression;
  3025. parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall;
  3026. wrapTracking = wrapTrackingFunction(extra.range, extra.loc);
  3027. extra.parseAdditiveExpression = parseAdditiveExpression;
  3028. extra.parseAssignmentExpression = parseAssignmentExpression;
  3029. extra.parseBitwiseANDExpression = parseBitwiseANDExpression;
  3030. extra.parseBitwiseORExpression = parseBitwiseORExpression;
  3031. extra.parseBitwiseXORExpression = parseBitwiseXORExpression;
  3032. extra.parseBlock = parseBlock;
  3033. extra.parseFunctionSourceElements = parseFunctionSourceElements;
  3034. extra.parseCatchClause = parseCatchClause;
  3035. extra.parseComputedMember = parseComputedMember;
  3036. extra.parseConditionalExpression = parseConditionalExpression;
  3037. extra.parseConstLetDeclaration = parseConstLetDeclaration;
  3038. extra.parseEqualityExpression = parseEqualityExpression;
  3039. extra.parseExpression = parseExpression;
  3040. extra.parseForVariableDeclaration = parseForVariableDeclaration;
  3041. extra.parseFunctionDeclaration = parseFunctionDeclaration;
  3042. extra.parseFunctionExpression = parseFunctionExpression;
  3043. extra.parseLogicalANDExpression = parseLogicalANDExpression;
  3044. extra.parseLogicalORExpression = parseLogicalORExpression;
  3045. extra.parseMultiplicativeExpression = parseMultiplicativeExpression;
  3046. extra.parseNewExpression = parseNewExpression;
  3047. extra.parseNonComputedProperty = parseNonComputedProperty;
  3048. extra.parseObjectProperty = parseObjectProperty;
  3049. extra.parseObjectPropertyKey = parseObjectPropertyKey;
  3050. extra.parsePostfixExpression = parsePostfixExpression;
  3051. extra.parsePrimaryExpression = parsePrimaryExpression;
  3052. extra.parseProgram = parseProgram;
  3053. extra.parsePropertyFunction = parsePropertyFunction;
  3054. extra.parseRelationalExpression = parseRelationalExpression;
  3055. extra.parseStatement = parseStatement;
  3056. extra.parseShiftExpression = parseShiftExpression;
  3057. extra.parseSwitchCase = parseSwitchCase;
  3058. extra.parseUnaryExpression = parseUnaryExpression;
  3059. extra.parseVariableDeclaration = parseVariableDeclaration;
  3060. extra.parseVariableIdentifier = parseVariableIdentifier;
  3061. parseAdditiveExpression = wrapTracking(extra.parseAdditiveExpression);
  3062. parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression);
  3063. parseBitwiseANDExpression = wrapTracking(extra.parseBitwiseANDExpression);
  3064. parseBitwiseORExpression = wrapTracking(extra.parseBitwiseORExpression);
  3065. parseBitwiseXORExpression = wrapTracking(extra.parseBitwiseXORExpression);
  3066. parseBlock = wrapTracking(extra.parseBlock);
  3067. parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements);
  3068. parseCatchClause = wrapTracking(extra.parseCatchClause);
  3069. parseComputedMember = wrapTracking(extra.parseComputedMember);
  3070. parseConditionalExpression = wrapTracking(extra.parseConditionalExpression);
  3071. parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration);
  3072. parseEqualityExpression = wrapTracking(extra.parseEqualityExpression);
  3073. parseExpression = wrapTracking(extra.parseExpression);
  3074. parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration);
  3075. parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration);
  3076. parseFunctionExpression = wrapTracking(extra.parseFunctionExpression);
  3077. parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression);
  3078. parseLogicalANDExpression = wrapTracking(extra.parseLogicalANDExpression);
  3079. parseLogicalORExpression = wrapTracking(extra.parseLogicalORExpression);
  3080. parseMultiplicativeExpression = wrapTracking(extra.parseMultiplicativeExpression);
  3081. parseNewExpression = wrapTracking(extra.parseNewExpression);
  3082. parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty);
  3083. parseObjectProperty = wrapTracking(extra.parseObjectProperty);
  3084. parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey);
  3085. parsePostfixExpression = wrapTracking(extra.parsePostfixExpression);
  3086. parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression);
  3087. parseProgram = wrapTracking(extra.parseProgram);
  3088. parsePropertyFunction = wrapTracking(extra.parsePropertyFunction);
  3089. parseRelationalExpression = wrapTracking(extra.parseRelationalExpression);
  3090. parseStatement = wrapTracking(extra.parseStatement);
  3091. parseShiftExpression = wrapTracking(extra.parseShiftExpression);
  3092. parseSwitchCase = wrapTracking(extra.parseSwitchCase);
  3093. parseUnaryExpression = wrapTracking(extra.parseUnaryExpression);
  3094. parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration);
  3095. parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier);
  3096. }
  3097. if (typeof extra.tokens !== 'undefined') {
  3098. extra.advance = advance;
  3099. extra.scanRegExp = scanRegExp;
  3100. advance = collectToken;
  3101. scanRegExp = collectRegex;
  3102. }
  3103. }
  3104. function unpatch() {
  3105. if (typeof extra.skipComment === 'function') {
  3106. skipComment = extra.skipComment;
  3107. }
  3108. if (extra.raw) {
  3109. createLiteral = extra.createLiteral;
  3110. }
  3111. if (extra.range || extra.loc) {
  3112. parseAdditiveExpression = extra.parseAdditiveExpression;
  3113. parseAssignmentExpression = extra.parseAssignmentExpression;
  3114. parseBitwiseANDExpression = extra.parseBitwiseANDExpression;
  3115. parseBitwiseORExpression = extra.parseBitwiseORExpression;
  3116. parseBitwiseXORExpression = extra.parseBitwiseXORExpression;
  3117. parseBlock = extra.parseBlock;
  3118. parseFunctionSourceElements = extra.parseFunctionSourceElements;
  3119. parseCatchClause = extra.parseCatchClause;
  3120. parseComputedMember = extra.parseComputedMember;
  3121. parseConditionalExpression = extra.parseConditionalExpression;
  3122. parseConstLetDeclaration = extra.parseConstLetDeclaration;
  3123. parseEqualityExpression = extra.parseEqualityExpression;
  3124. parseExpression = extra.parseExpression;
  3125. parseForVariableDeclaration = extra.parseForVariableDeclaration;
  3126. parseFunctionDeclaration = extra.parseFunctionDeclaration;
  3127. parseFunctionExpression = extra.parseFunctionExpression;
  3128. parseGroupExpression = extra.parseGroupExpression;
  3129. parseLeftHandSideExpression = extra.parseLeftHandSideExpression;
  3130. parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall;
  3131. parseLogicalANDExpression = extra.parseLogicalANDExpression;
  3132. parseLogicalORExpression = extra.parseLogicalORExpression;
  3133. parseMultiplicativeExpression = extra.parseMultiplicativeExpression;
  3134. parseNewExpression = extra.parseNewExpression;
  3135. parseNonComputedProperty = extra.parseNonComputedProperty;
  3136. parseObjectProperty = extra.parseObjectProperty;
  3137. parseObjectPropertyKey = extra.parseObjectPropertyKey;
  3138. parsePrimaryExpression = extra.parsePrimaryExpression;
  3139. parsePostfixExpression = extra.parsePostfixExpression;
  3140. parseProgram = extra.parseProgram;
  3141. parsePropertyFunction = extra.parsePropertyFunction;
  3142. parseRelationalExpression = extra.parseRelationalExpression;
  3143. parseStatement = extra.parseStatement;
  3144. parseShiftExpression = extra.parseShiftExpression;
  3145. parseSwitchCase = extra.parseSwitchCase;
  3146. parseUnaryExpression = extra.parseUnaryExpression;
  3147. parseVariableDeclaration = extra.parseVariableDeclaration;
  3148. parseVariableIdentifier = extra.parseVariableIdentifier;
  3149. }
  3150. if (typeof extra.scanRegExp === 'function') {
  3151. advance = extra.advance;
  3152. scanRegExp = extra.scanRegExp;
  3153. }
  3154. }
  3155. function stringToArray(str) {
  3156. var length = str.length,
  3157. result = [],
  3158. i;
  3159. for (i = 0; i < length; ++i) {
  3160. result[i] = str.charAt(i);
  3161. }
  3162. return result;
  3163. }
  3164. function parse(code, options) {
  3165. var program, toString;
  3166. toString = String;
  3167. if (typeof code !== 'string' && !(code instanceof String)) {
  3168. code = toString(code);
  3169. }
  3170. source = code;
  3171. index = 0;
  3172. lineNumber = (source.length > 0) ? 1 : 0;
  3173. lineStart = 0;
  3174. length = source.length;
  3175. buffer = null;
  3176. state = {
  3177. allowIn: true,
  3178. labelSet: {},
  3179. inFunctionBody: false,
  3180. inIteration: false,
  3181. inSwitch: false
  3182. };
  3183. extra = {};
  3184. if (typeof options !== 'undefined') {
  3185. extra.range = (typeof options.range === 'boolean') && options.range;
  3186. extra.loc = (typeof options.loc === 'boolean') && options.loc;
  3187. extra.raw = (typeof options.raw === 'boolean') && options.raw;
  3188. if (typeof options.tokens === 'boolean' && options.tokens) {
  3189. extra.tokens = [];
  3190. }
  3191. if (typeof options.comment === 'boolean' && options.comment) {
  3192. extra.comments = [];
  3193. }
  3194. if (typeof options.tolerant === 'boolean' && options.tolerant) {
  3195. extra.errors = [];
  3196. }
  3197. }
  3198. if (length > 0) {
  3199. if (typeof source[0] === 'undefined') {
  3200. // Try first to convert to a string. This is good as fast path
  3201. // for old IE which understands string indexing for string
  3202. // literals only and not for string object.
  3203. if (code instanceof String) {
  3204. source = code.valueOf();
  3205. }
  3206. // Force accessing the characters via an array.
  3207. if (typeof source[0] === 'undefined') {
  3208. source = stringToArray(code);
  3209. }
  3210. }
  3211. }
  3212. patch();
  3213. try {
  3214. program = parseProgram();
  3215. if (typeof extra.comments !== 'undefined') {
  3216. filterCommentLocation();
  3217. program.comments = extra.comments;
  3218. }
  3219. if (typeof extra.tokens !== 'undefined') {
  3220. filterTokenLocation();
  3221. program.tokens = extra.tokens;
  3222. }
  3223. if (typeof extra.errors !== 'undefined') {
  3224. program.errors = extra.errors;
  3225. }
  3226. if (extra.range || extra.loc) {
  3227. program.body = filterGroup(program.body);
  3228. }
  3229. } catch (e) {
  3230. throw e;
  3231. } finally {
  3232. unpatch();
  3233. extra = {};
  3234. }
  3235. return program;
  3236. }
  3237. // Sync with package.json.
  3238. exports.version = '1.0.2';
  3239. exports.parse = parse;
  3240. // Deep copy.
  3241. exports.Syntax = (function () {
  3242. var name, types = {};
  3243. if (typeof Object.create === 'function') {
  3244. types = Object.create(null);
  3245. }
  3246. for (name in Syntax) {
  3247. if (Syntax.hasOwnProperty(name)) {
  3248. types[name] = Syntax[name];
  3249. }
  3250. }
  3251. if (typeof Object.freeze === 'function') {
  3252. Object.freeze(types);
  3253. }
  3254. return types;
  3255. }());
  3256. }));
  3257. /* vim: set sw=4 ts=4 et tw=80 : */
  3258. })(null);
  3259. (function(require,module){
  3260. var parse = require('esprima').parse;
  3261. var objectKeys = Object.keys || function (obj) {
  3262. var keys = [];
  3263. for (var key in obj) keys.push(key);
  3264. return keys;
  3265. };
  3266. var forEach = function (xs, fn) {
  3267. if (xs.forEach) return xs.forEach(fn);
  3268. for (var i = 0; i < xs.length; i++) {
  3269. fn.call(xs, xs[i], i, xs);
  3270. }
  3271. };
  3272. var isArray = Array.isArray || function (xs) {
  3273. return Object.prototype.toString.call(xs) === '[object Array]';
  3274. };
  3275. module.exports = function (src, opts, fn) {
  3276. if (typeof opts === 'function') {
  3277. fn = opts;
  3278. opts = {};
  3279. }
  3280. if (typeof src === 'object') {
  3281. opts = src;
  3282. src = opts.source;
  3283. delete opts.source;
  3284. }
  3285. src = src === undefined ? opts.source : src;
  3286. opts.range = true;
  3287. if (typeof src !== 'string') src = String(src);
  3288. var ast = parse(src, opts);
  3289. var result = {
  3290. chunks : src.split(''),
  3291. toString : function () { return result.chunks.join('') },
  3292. inspect : function () { return result.toString() }
  3293. };
  3294. var index = 0;
  3295. (function walk (node, parent) {
  3296. insertHelpers(node, parent, result.chunks);
  3297. forEach(objectKeys(node), function (key) {
  3298. if (key === 'parent') return;
  3299. var child = node[key];
  3300. if (isArray(child)) {
  3301. forEach(child, function (c) {
  3302. if (c && typeof c.type === 'string') {
  3303. walk(c, node);
  3304. }
  3305. });
  3306. }
  3307. else if (child && typeof child.type === 'string') {
  3308. insertHelpers(child, node, result.chunks);
  3309. walk(child, node);
  3310. }
  3311. });
  3312. fn(node);
  3313. })(ast, undefined);
  3314. return result;
  3315. };
  3316. function insertHelpers (node, parent, chunks) {
  3317. if (!node.range) return;
  3318. node.parent = parent;
  3319. node.source = function () {
  3320. return chunks.slice(
  3321. node.range[0], node.range[1]
  3322. ).join('');
  3323. };
  3324. if (node.update && typeof node.update === 'object') {
  3325. var prev = node.update;
  3326. forEach(objectKeys(prev), function (key) {
  3327. update[key] = prev[key];
  3328. });
  3329. node.update = update;
  3330. }
  3331. else {
  3332. node.update = update;
  3333. }
  3334. function update (s) {
  3335. chunks[node.range[0]] = s;
  3336. for (var i = node.range[0] + 1; i < node.range[1]; i++) {
  3337. chunks[i] = '';
  3338. }
  3339. };
  3340. }
  3341. window.falafel = module.exports;})(function(){return {parse: esprima.parse};},{exports: {}});
  3342. var inBrowser = typeof window !== 'undefined' && this === window;
  3343. var parseAndModify = (inBrowser ? window.falafel : require("falafel"));
  3344. (inBrowser ? window : exports).blanket = (function(){
  3345. var linesToAddTracking = [
  3346. "ExpressionStatement",
  3347. "BreakStatement" ,
  3348. "ContinueStatement" ,
  3349. "VariableDeclaration",
  3350. "ReturnStatement" ,
  3351. "ThrowStatement" ,
  3352. "TryStatement" ,
  3353. "FunctionDeclaration" ,
  3354. "IfStatement" ,
  3355. "WhileStatement" ,
  3356. "DoWhileStatement" ,
  3357. "ForStatement" ,
  3358. "ForInStatement" ,
  3359. "SwitchStatement" ,
  3360. "WithStatement"
  3361. ],
  3362. linesToAddBrackets = [
  3363. "IfStatement" ,
  3364. "WhileStatement" ,
  3365. "DoWhileStatement" ,
  3366. "ForStatement" ,
  3367. "ForInStatement" ,
  3368. "WithStatement"
  3369. ],
  3370. __blanket,
  3371. copynumber = Math.floor(Math.random()*1000),
  3372. coverageInfo = {},options = {
  3373. reporter: null,
  3374. adapter:null,
  3375. filter: null,
  3376. customVariable: null,
  3377. orderedLoading: true,
  3378. loader: null,
  3379. ignoreScriptError: false,
  3380. existingRequireJS:false,
  3381. autoStart: false,
  3382. timeout: 180,
  3383. ignoreCors: false,
  3384. branchTracking: false,
  3385. sourceURL: false,
  3386. debug:false,
  3387. engineOnly:false,
  3388. testReadyCallback:null,
  3389. commonJS:false,
  3390. instrumentCache:false
  3391. };
  3392. if (inBrowser && typeof window.blanket !== 'undefined'){
  3393. __blanket = window.blanket.noConflict();
  3394. }
  3395. _blanket = {
  3396. noConflict: function(){
  3397. if (__blanket){
  3398. return __blanket;
  3399. }
  3400. return _blanket;
  3401. },
  3402. _getCopyNumber: function(){
  3403. //internal method
  3404. //for differentiating between instances
  3405. return copynumber;
  3406. },
  3407. extend: function(obj) {
  3408. //borrowed from underscore
  3409. _blanket._extend(_blanket,obj);
  3410. },
  3411. _extend: function(dest,source){
  3412. if (source) {
  3413. for (var prop in source) {
  3414. if ( dest[prop] instanceof Object && typeof dest[prop] !== "function"){
  3415. _blanket._extend(dest[prop],source[prop]);
  3416. }else{
  3417. dest[prop] = source[prop];
  3418. }
  3419. }
  3420. }
  3421. },
  3422. getCovVar: function(){
  3423. var opt = _blanket.options("customVariable");
  3424. if (opt){
  3425. if (_blanket.options("debug")) {console.log("BLANKET-Using custom tracking variable:",opt);}
  3426. return inBrowser ? "window."+opt : opt;
  3427. }
  3428. return inBrowser ? "window._$blanket" : "_$jscoverage";
  3429. },
  3430. options: function(key,value){
  3431. if (typeof key !== "string"){
  3432. _blanket._extend(options,key);
  3433. }else if (typeof value === 'undefined'){
  3434. return options[key];
  3435. }else{
  3436. options[key]=value;
  3437. }
  3438. },
  3439. instrument: function(config, next){
  3440. //check instrumented hash table,
  3441. //return instrumented code if available.
  3442. var inFile = config.inputFile,
  3443. inFileName = config.inputFileName;
  3444. //check instrument cache
  3445. if (_blanket.options("instrumentCache") && sessionStorage && sessionStorage.getItem("blanket_instrument_store-"+inFileName)){
  3446. if (_blanket.options("debug")) {console.log("BLANKET-Reading instrumentation from cache: ",inFileName);}
  3447. next(sessionStorage.getItem("blanket_instrument_store-"+inFileName));
  3448. }else{
  3449. var sourceArray = _blanket._prepareSource(inFile);
  3450. _blanket._trackingArraySetup=[];
  3451. var instrumented = parseAndModify(inFile,{loc:true,comment:true}, _blanket._addTracking(inFileName));
  3452. instrumented = _blanket._trackingSetup(inFileName,sourceArray)+instrumented;
  3453. if (_blanket.options("sourceURL")){
  3454. instrumented += "\n//@ sourceURL="+inFileName.replace("http://","");
  3455. }
  3456. if (_blanket.options("debug")) {console.log("BLANKET-Instrumented file: ",inFileName);}
  3457. if (_blanket.options("instrumentCache") && sessionStorage){
  3458. if (_blanket.options("debug")) {console.log("BLANKET-Saving instrumentation to cache: ",inFileName);}
  3459. sessionStorage.setItem("blanket_instrument_store-"+inFileName,instrumented);
  3460. }
  3461. next(instrumented);
  3462. }
  3463. },
  3464. _trackingArraySetup: [],
  3465. _branchingArraySetup: [],
  3466. _prepareSource: function(source){
  3467. return source.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/(\r\n|\n|\r)/gm,"\n").split('\n');
  3468. },
  3469. _trackingSetup: function(filename,sourceArray){
  3470. var branches = _blanket.options("branchTracking");
  3471. var sourceString = sourceArray.join("',\n'");
  3472. var intro = "";
  3473. var covVar = _blanket.getCovVar();
  3474. intro += "if (typeof "+covVar+" === 'undefined') "+covVar+" = {};\n";
  3475. if (branches){
  3476. intro += "var _$branchFcn=function(f,l,c,r){ ";
  3477. intro += "if (!!r) { ";
  3478. intro += covVar+"[f].branchData[l][c][0] = "+covVar+"[f].branchData[l][c][0] || [];";
  3479. intro += covVar+"[f].branchData[l][c][0].push(r); }";
  3480. intro += "else { ";
  3481. intro += covVar+"[f].branchData[l][c][1] = "+covVar+"[f].branchData[l][c][1] || [];";
  3482. intro += covVar+"[f].branchData[l][c][1].push(r); }";
  3483. intro += "return r;};\n";
  3484. }
  3485. intro += "if (typeof "+covVar+"['"+filename+"'] === 'undefined'){";
  3486. intro += covVar+"['"+filename+"']=[];\n";
  3487. if (branches){
  3488. intro += covVar+"['"+filename+"'].branchData=[];\n";
  3489. }
  3490. intro += covVar+"['"+filename+"'].source=['"+sourceString+"'];\n";
  3491. //initialize array values
  3492. _blanket._trackingArraySetup.sort(function(a,b){
  3493. return parseInt(a,10) > parseInt(b,10);
  3494. }).forEach(function(item){
  3495. intro += covVar+"['"+filename+"']["+item+"]=0;\n";
  3496. });
  3497. if (branches){
  3498. _blanket._branchingArraySetup.sort(function(a,b){
  3499. return a.line > b.line;
  3500. }).sort(function(a,b){
  3501. return a.column > b.column;
  3502. }).forEach(function(item){
  3503. if (item.file === filename){
  3504. intro += "if (typeof "+ covVar+"['"+filename+"'].branchData["+item.line+"] === 'undefined'){\n";
  3505. intro += covVar+"['"+filename+"'].branchData["+item.line+"]=[];\n";
  3506. intro += "}";
  3507. intro += covVar+"['"+filename+"'].branchData["+item.line+"]["+item.column+"] = [];\n";
  3508. intro += covVar+"['"+filename+"'].branchData["+item.line+"]["+item.column+"].consequent = "+JSON.stringify(item.consequent)+";\n";
  3509. intro += covVar+"['"+filename+"'].branchData["+item.line+"]["+item.column+"].alternate = "+JSON.stringify(item.alternate)+";\n";
  3510. }
  3511. });
  3512. }
  3513. intro += "}";
  3514. return intro;
  3515. },
  3516. _blockifyIf: function(node){
  3517. if (linesToAddBrackets.indexOf(node.type) > -1){
  3518. var bracketsExistObject = node.consequent || node.body;
  3519. var bracketsExistAlt = node.alternate;
  3520. if( bracketsExistAlt && bracketsExistAlt.type !== "BlockStatement") {
  3521. bracketsExistAlt.update("{\n"+bracketsExistAlt.source()+"}\n");
  3522. }
  3523. if( bracketsExistObject && bracketsExistObject.type !== "BlockStatement") {
  3524. bracketsExistObject.update("{\n"+bracketsExistObject.source()+"}\n");
  3525. }
  3526. }
  3527. },
  3528. _trackBranch: function(node,filename){
  3529. //recursive on consequent and alternative
  3530. var line = node.loc.start.line;
  3531. var col = node.loc.start.column;
  3532. _blanket._branchingArraySetup.push({
  3533. line: line,
  3534. column: col,
  3535. file:filename,
  3536. consequent: node.consequent.loc,
  3537. alternate: node.alternate.loc
  3538. });
  3539. var source = node.source();
  3540. var updated = "_$branchFcn"+
  3541. "('"+filename+"',"+line+","+col+","+source.slice(0,source.indexOf("?"))+
  3542. ")"+source.slice(source.indexOf("?"));
  3543. node.update(updated);
  3544. },
  3545. _addTracking: function (filename) {
  3546. //falafel doesn't take a file name
  3547. //so we include the filename in a closure
  3548. //and return the function to falafel
  3549. var covVar = _blanket.getCovVar();
  3550. return function(node){
  3551. _blanket._blockifyIf(node);
  3552. if (linesToAddTracking.indexOf(node.type) > -1 && node.parent.type !== "LabeledStatement") {
  3553. _blanket._checkDefs(node,filename);
  3554. if (node.type === "VariableDeclaration" &&
  3555. (node.parent.type === "ForStatement" || node.parent.type === "ForInStatement")){
  3556. return;
  3557. }
  3558. if (node.loc && node.loc.start){
  3559. node.update(covVar+"['"+filename+"']["+node.loc.start.line+"]++;\n"+node.source());
  3560. _blanket._trackingArraySetup.push(node.loc.start.line);
  3561. }else{
  3562. //I don't think we can handle a node with no location
  3563. throw new Error("The instrumenter encountered a node with no location: "+Object.keys(node));
  3564. }
  3565. }else if (_blanket.options("branchTracking") && node.type === "ConditionalExpression"){
  3566. _blanket._trackBranch(node,filename);
  3567. }
  3568. };
  3569. },
  3570. _checkDefs: function(node,filename){
  3571. // Make sure developers don't redefine window. if they do, inform them it is wrong.
  3572. if (inBrowser){
  3573. if (node.type === "VariableDeclaration" && node.declarations) {
  3574. node.declarations.forEach(function(declaration) {
  3575. if (declaration.id.name === "window") {
  3576. throw new Error("Instrumentation error, you cannot redefine the 'window' variable in " + filename + ":" + node.loc.start.line);
  3577. }
  3578. });
  3579. }
  3580. if (node.type === "FunctionDeclaration" && node.params) {
  3581. node.params.forEach(function(param) {
  3582. if (param.name === "window") {
  3583. throw new Error("Instrumentation error, you cannot redefine the 'window' variable in " + filename + ":" + node.loc.start.line);
  3584. }
  3585. });
  3586. }
  3587. //Make sure developers don't redefine the coverage variable
  3588. if (node.type === "ExpressionStatement" &&
  3589. node.expression && node.expression.left &&
  3590. node.expression.left.object && node.expression.left.property &&
  3591. node.expression.left.object.name +
  3592. "." + node.expression.left.property.name === _blanket.getCovVar()) {
  3593. throw new Error("Instrumentation error, you cannot redefine the coverage variable in " + filename + ":" + node.loc.start.line);
  3594. }
  3595. }else{
  3596. //Make sure developers don't redefine the coverage variable in node
  3597. if (node.type === "ExpressionStatement" &&
  3598. node.expression && node.expression.left &&
  3599. !node.expression.left.object && !node.expression.left.property &&
  3600. node.expression.left.name === _blanket.getCovVar()) {
  3601. throw new Error("Instrumentation error, you cannot redefine the coverage variable in " + filename + ":" + node.loc.start.line);
  3602. }
  3603. }
  3604. },
  3605. setupCoverage: function(){
  3606. coverageInfo.instrumentation = "blanket";
  3607. coverageInfo.stats = {
  3608. "suites": 0,
  3609. "tests": 0,
  3610. "passes": 0,
  3611. "pending": 0,
  3612. "failures": 0,
  3613. "start": new Date()
  3614. };
  3615. },
  3616. _checkIfSetup: function(){
  3617. if (!coverageInfo.stats){
  3618. throw new Error("You must call blanket.setupCoverage() first.");
  3619. }
  3620. },
  3621. onTestStart: function(){
  3622. if (_blanket.options("debug")) {console.log("BLANKET-Test event started");}
  3623. this._checkIfSetup();
  3624. coverageInfo.stats.tests++;
  3625. coverageInfo.stats.pending++;
  3626. },
  3627. onTestDone: function(total,passed){
  3628. this._checkIfSetup();
  3629. if(passed === total){
  3630. coverageInfo.stats.passes++;
  3631. }else{
  3632. coverageInfo.stats.failures++;
  3633. }
  3634. coverageInfo.stats.pending--;
  3635. },
  3636. onModuleStart: function(){
  3637. this._checkIfSetup();
  3638. coverageInfo.stats.suites++;
  3639. },
  3640. onTestsDone: function(){
  3641. if (_blanket.options("debug")) {console.log("BLANKET-Test event done");}
  3642. this._checkIfSetup();
  3643. coverageInfo.stats.end = new Date();
  3644. if (inBrowser){
  3645. this.report(coverageInfo);
  3646. }else{
  3647. if (!_blanket.options("branchTracking")){
  3648. delete (inBrowser ? window : global)[_blanket.getCovVar()].branchFcn;
  3649. }
  3650. this.options("reporter").call(this,coverageInfo);
  3651. }
  3652. }
  3653. };
  3654. return _blanket;
  3655. })();
  3656. (function(_blanket){
  3657. var oldOptions = _blanket.options;
  3658. _blanket.extend({
  3659. outstandingRequireFiles:[],
  3660. options: function(key,value){
  3661. var newVal={};
  3662. if (typeof key !== "string"){
  3663. //key is key/value map
  3664. oldOptions(key);
  3665. newVal = key;
  3666. }else if (typeof value === 'undefined'){
  3667. //accessor
  3668. return oldOptions(key);
  3669. }else{
  3670. //setter
  3671. oldOptions(key,value);
  3672. newVal[key] = value;
  3673. }
  3674. if (newVal.adapter){
  3675. _blanket._loadFile(newVal.adapter);
  3676. }
  3677. if (newVal.loader){
  3678. _blanket._loadFile(newVal.loader);
  3679. }
  3680. },
  3681. requiringFile: function(filename,done){
  3682. if (typeof filename === "undefined"){
  3683. _blanket.outstandingRequireFiles=[];
  3684. }else if (typeof done === "undefined"){
  3685. _blanket.outstandingRequireFiles.push(filename);
  3686. }else{
  3687. _blanket.outstandingRequireFiles.splice(_blanket.outstandingRequireFiles.indexOf(filename),1);
  3688. }
  3689. },
  3690. requireFilesLoaded: function(){
  3691. return _blanket.outstandingRequireFiles.length === 0;
  3692. },
  3693. showManualLoader: function(){
  3694. if (document.getElementById("blanketLoaderDialog")){
  3695. return;
  3696. }
  3697. //copied from http://blog.avtex.com/2012/01/26/cross-browser-css-only-modal-box/
  3698. var loader = "<div class='blanketDialogOverlay'>";
  3699. loader += "&nbsp;</div>";
  3700. loader += "<div class='blanketDialogVerticalOffset'>";
  3701. loader += "<div class='blanketDialogBox'>";
  3702. loader += "<b>Error:</b> Blanket.js encountered a cross origin request error while instrumenting the source files. ";
  3703. loader += "<br><br>This is likely caused by the source files being referenced locally (using the file:// protocol). ";
  3704. 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).";
  3705. loader += "<br>";
  3706. if (typeof FileReader !== "undefined"){
  3707. loader += "<br>Or, try the experimental loader. When prompted, simply click on the directory containing all the source files you want covered.";
  3708. loader += "<a href='javascript:document.getElementById(\"fileInput\").click();'>Start Loader</a>";
  3709. 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'/>";
  3710. }
  3711. loader += "<br><span style='float:right;cursor:pointer;' onclick=document.getElementById('blanketLoaderDialog').style.display='none';>Close</span>";
  3712. loader += "<div style='clear:both'></div>";
  3713. loader += "</div></div>";
  3714. var css = ".blanketDialogWrapper {";
  3715. css += "display:block;";
  3716. css += "position:fixed;";
  3717. css += "z-index:40001; }";
  3718. css += ".blanketDialogOverlay {";
  3719. css += "position:fixed;";
  3720. css += "width:100%;";
  3721. css += "height:100%;";
  3722. css += "background-color:black;";
  3723. css += "opacity:.5; ";
  3724. css += "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)'; ";
  3725. css += "filter:alpha(opacity=50); ";
  3726. css += "z-index:40001; }";
  3727. css += ".blanketDialogVerticalOffset { ";
  3728. css += "position:fixed;";
  3729. css += "top:30%;";
  3730. css += "width:100%;";
  3731. css += "z-index:40002; }";
  3732. css += ".blanketDialogBox { ";
  3733. css += "width:405px; ";
  3734. css += "position:relative;";
  3735. css += "margin:0 auto;";
  3736. css += "background-color:white;";
  3737. css += "padding:10px;";
  3738. css += "border:1px solid black; }";
  3739. var dom = document.createElement("style");
  3740. dom.innerHTML = css;
  3741. document.head.appendChild(dom);
  3742. var div = document.createElement("div");
  3743. div.id = "blanketLoaderDialog";
  3744. div.className = "blanketDialogWrapper";
  3745. div.innerHTML = loader;
  3746. document.body.insertBefore(div,document.body.firstChild);
  3747. },
  3748. manualFileLoader: function(files){
  3749. var toArray =Array.prototype.slice;
  3750. files = toArray.call(files).filter(function(item){
  3751. return item.type !== "";
  3752. });
  3753. var sessionLength = files.length-1;
  3754. var sessionIndx=0;
  3755. var sessionArray = {};
  3756. if (sessionStorage["blanketSessionLoader"]){
  3757. sessionArray = JSON.parse(sessionStorage["blanketSessionLoader"]);
  3758. }
  3759. var fileLoader = function(event){
  3760. var fileContent = event.currentTarget.result;
  3761. var file = files[sessionIndx];
  3762. var filename = file.webkitRelativePath && file.webkitRelativePath !== '' ? file.webkitRelativePath : file.name;
  3763. sessionArray[filename] = fileContent;
  3764. sessionIndx++;
  3765. if (sessionIndx === sessionLength){
  3766. sessionStorage.setItem("blanketSessionLoader", JSON.stringify(sessionArray));
  3767. document.location.reload();
  3768. }else{
  3769. readFile(files[sessionIndx]);
  3770. }
  3771. };
  3772. function readFile(file){
  3773. var reader = new FileReader();
  3774. reader.onload = fileLoader;
  3775. reader.readAsText(file);
  3776. }
  3777. readFile(files[sessionIndx]);
  3778. },
  3779. _loadFile: function(path){
  3780. if (typeof path !== "undefined"){
  3781. var request = new XMLHttpRequest();
  3782. request.open('GET', path, false);
  3783. request.send();
  3784. var script = document.createElement("script");
  3785. script.type = "text/javascript";
  3786. script.text = request.responseText;
  3787. (document.body || document.getElementsByTagName('head')[0]).appendChild(script);
  3788. }
  3789. },
  3790. hasAdapter: function(callback){
  3791. return _blanket.options("adapter") !== null;
  3792. },
  3793. report: function(coverage_data){
  3794. if (!document.getElementById("blanketLoaderDialog")){
  3795. //all found, clear it
  3796. _blanket.blanketSession = null;
  3797. }
  3798. coverage_data.files = window._$blanket;
  3799. var require = blanket.options("commonJS") ? blanket._commonjs.require : window.require;
  3800. // Check if we have any covered files that requires reporting
  3801. // otherwise just exit gracefully.
  3802. if (!coverage_data.files || !Object.keys(coverage_data.files).length) {
  3803. if (_blanket.options("debug")) {console.log("BLANKET-Reporting No files were instrumented.");}
  3804. return;
  3805. }
  3806. if (typeof coverage_data.files.branchFcn !== "undefined"){
  3807. delete coverage_data.files.branchFcn;
  3808. }
  3809. if (typeof _blanket.options("reporter") === "string"){
  3810. require([_blanket.options("reporter").replace(".js","")],function(r){
  3811. r(coverage_data,_blanket.options("reporter_options"));
  3812. });
  3813. }else if (typeof _blanket.options("reporter") === "function"){
  3814. _blanket.options("reporter")(coverage_data);
  3815. }else if (typeof _blanket.defaultReporter === 'function'){
  3816. _blanket.defaultReporter(coverage_data);
  3817. }else{
  3818. throw new Error("no reporter defined.");
  3819. }
  3820. },
  3821. _bindStartTestRunner: function(bindEvent,startEvent){
  3822. if (bindEvent){
  3823. bindEvent(startEvent);
  3824. }else{
  3825. window.addEventListener("load",startEvent,false);
  3826. }
  3827. },
  3828. _loadSourceFiles: function(callback){
  3829. console.log("ls1:"+new Date().getTime());
  3830. var require = blanket.options("commonJS") ? blanket._commonjs.require : window.require;
  3831. function copy(o){
  3832. var _copy = Object.create( Object.getPrototypeOf(o) );
  3833. var propNames = Object.getOwnPropertyNames(o);
  3834. propNames.forEach(function(name){
  3835. var desc = Object.getOwnPropertyDescriptor(o, name);
  3836. Object.defineProperty(_copy, name, desc);
  3837. });
  3838. return _copy;
  3839. }
  3840. if (_blanket.options("debug")) {console.log("BLANKET-Collecting page scripts");}
  3841. var scripts = _blanket.utils.collectPageScripts();
  3842. //_blanket.options("filter",scripts);
  3843. if (scripts.length === 0){
  3844. callback();
  3845. }else{
  3846. //check session state
  3847. if (sessionStorage["blanketSessionLoader"]){
  3848. _blanket.blanketSession = JSON.parse(sessionStorage["blanketSessionLoader"]);
  3849. }
  3850. var requireConfig = {
  3851. paths: {},
  3852. shim: {},
  3853. waitSeconds: _blanket.options("timeout")
  3854. };
  3855. var lastDep = {
  3856. deps: []
  3857. };
  3858. var isOrdered = _blanket.options("orderedLoading");
  3859. var initialGet=[];
  3860. scripts.forEach(function(file,indx){
  3861. //for whatever reason requirejs
  3862. //prefers when we don't use the full path
  3863. //so we just use a custom name
  3864. var requireKey = "blanket_"+indx;
  3865. initialGet.push(requireKey);
  3866. requireConfig.paths[requireKey] = file;
  3867. if (isOrdered){
  3868. if (indx > 0){
  3869. requireConfig.shim[requireKey] = copy(lastDep);
  3870. }
  3871. lastDep.deps = [requireKey];
  3872. }
  3873. });
  3874. require.config(requireConfig);
  3875. var filt = initialGet;
  3876. require(filt, function(){
  3877. callback();
  3878. });
  3879. }
  3880. console.log("ls2:"+new Date().getTime());
  3881. },
  3882. beforeStartTestRunner: function(opts){
  3883. opts = opts || {};
  3884. opts.checkRequirejs = typeof opts.checkRequirejs === "undefined" ? true : opts.checkRequirejs;
  3885. opts.callback = opts.callback || function() { };
  3886. opts.coverage = typeof opts.coverage === "undefined" ? true : opts.coverage;
  3887. if (opts.coverage) {
  3888. _blanket._bindStartTestRunner(opts.bindEvent,
  3889. function(){
  3890. _blanket._loadSourceFiles(function() {
  3891. var allLoaded = function(){
  3892. return opts.condition ? opts.condition() : _blanket.requireFilesLoaded();
  3893. };
  3894. var check = function() {
  3895. if (allLoaded()) {
  3896. if (_blanket.options("debug")) {console.log("BLANKET-All files loaded, init start test runner callback.");}
  3897. var cb = _blanket.options("testReadyCallback");
  3898. if (cb){
  3899. if (typeof cb === "function"){
  3900. cb(opts.callback);
  3901. }else if (typeof cb === "string"){
  3902. eval(cb);
  3903. opts.callback();
  3904. }
  3905. }else{
  3906. opts.callback();
  3907. }
  3908. } else {
  3909. setTimeout(check, 13);
  3910. }
  3911. };
  3912. check();
  3913. });
  3914. });
  3915. }else{
  3916. opts.callback();
  3917. }
  3918. },
  3919. utils: {
  3920. qualifyURL: function (url) {
  3921. //http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
  3922. var a = document.createElement('a');
  3923. a.href = url;
  3924. return a.href;
  3925. }
  3926. }
  3927. });
  3928. })(blanket);
  3929. blanket.setupRequireJS=function(context){
  3930. /** vim: et:ts=4:sw=4:sts=4
  3931. * @license RequireJS 2.1.4 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
  3932. * Available via the MIT or new BSD license.
  3933. * see: http://github.com/jrburke/requirejs for details
  3934. */
  3935. //Not using strict: uneven strict support in browsers, #392, and causes
  3936. //problems with requirejs.exec()/transpiler plugins that may not be strict.
  3937. /*jslint regexp: true, nomen: true, sloppy: true */
  3938. /*global window, navigator, document, importScripts, setTimeout, opera */
  3939. var requirejs, require, define;
  3940. (function (global) {
  3941. var req, s, head, baseElement, dataMain, src,
  3942. interactiveScript, currentlyAddingScript, mainScript, subPath,
  3943. version = '2.1.4',
  3944. commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
  3945. cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
  3946. jsSuffixRegExp = /\.js$/,
  3947. currDirRegExp = /^\.\//,
  3948. op = Object.prototype,
  3949. ostring = op.toString,
  3950. hasOwn = op.hasOwnProperty,
  3951. ap = Array.prototype,
  3952. apsp = ap.splice,
  3953. isBrowser = !!(typeof window !== 'undefined' && navigator && document),
  3954. isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
  3955. //PS3 indicates loaded and complete, but need to wait for complete
  3956. //specifically. Sequence is 'loading', 'loaded', execution,
  3957. // then 'complete'. The UA check is unfortunate, but not sure how
  3958. //to feature test w/o causing perf issues.
  3959. readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
  3960. /^complete$/ : /^(complete|loaded)$/,
  3961. defContextName = '_',
  3962. //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
  3963. isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]',
  3964. contexts = {},
  3965. cfg = {},
  3966. globalDefQueue = [],
  3967. useInteractive = false;
  3968. function isFunction(it) {
  3969. return ostring.call(it) === '[object Function]';
  3970. }
  3971. function isArray(it) {
  3972. return ostring.call(it) === '[object Array]';
  3973. }
  3974. /**
  3975. * Helper function for iterating over an array. If the func returns
  3976. * a true value, it will break out of the loop.
  3977. */
  3978. function each(ary, func) {
  3979. if (ary) {
  3980. var i;
  3981. for (i = 0; i < ary.length; i += 1) {
  3982. if (ary[i] && func(ary[i], i, ary)) {
  3983. break;
  3984. }
  3985. }
  3986. }
  3987. }
  3988. /**
  3989. * Helper function for iterating over an array backwards. If the func
  3990. * returns a true value, it will break out of the loop.
  3991. */
  3992. function eachReverse(ary, func) {
  3993. if (ary) {
  3994. var i;
  3995. for (i = ary.length - 1; i > -1; i -= 1) {
  3996. if (ary[i] && func(ary[i], i, ary)) {
  3997. break;
  3998. }
  3999. }
  4000. }
  4001. }
  4002. function hasProp(obj, prop) {
  4003. return hasOwn.call(obj, prop);
  4004. }
  4005. function getOwn(obj, prop) {
  4006. return hasProp(obj, prop) && obj[prop];
  4007. }
  4008. /**
  4009. * Cycles over properties in an object and calls a function for each
  4010. * property value. If the function returns a truthy value, then the
  4011. * iteration is stopped.
  4012. */
  4013. function eachProp(obj, func) {
  4014. var prop;
  4015. for (prop in obj) {
  4016. if (hasProp(obj, prop)) {
  4017. if (func(obj[prop], prop)) {
  4018. break;
  4019. }
  4020. }
  4021. }
  4022. }
  4023. /**
  4024. * Simple function to mix in properties from source into target,
  4025. * but only if target does not already have a property of the same name.
  4026. */
  4027. function mixin(target, source, force, deepStringMixin) {
  4028. if (source) {
  4029. eachProp(source, function (value, prop) {
  4030. if (force || !hasProp(target, prop)) {
  4031. if (deepStringMixin && typeof value !== 'string') {
  4032. if (!target[prop]) {
  4033. target[prop] = {};
  4034. }
  4035. mixin(target[prop], value, force, deepStringMixin);
  4036. } else {
  4037. target[prop] = value;
  4038. }
  4039. }
  4040. });
  4041. }
  4042. return target;
  4043. }
  4044. //Similar to Function.prototype.bind, but the 'this' object is specified
  4045. //first, since it is easier to read/figure out what 'this' will be.
  4046. function bind(obj, fn) {
  4047. return function () {
  4048. return fn.apply(obj, arguments);
  4049. };
  4050. }
  4051. function scripts() {
  4052. return document.getElementsByTagName('script');
  4053. }
  4054. //Allow getting a global that expressed in
  4055. //dot notation, like 'a.b.c'.
  4056. function getGlobal(value) {
  4057. if (!value) {
  4058. return value;
  4059. }
  4060. var g = global;
  4061. each(value.split('.'), function (part) {
  4062. g = g[part];
  4063. });
  4064. return g;
  4065. }
  4066. /**
  4067. * Constructs an error with a pointer to an URL with more information.
  4068. * @param {String} id the error ID that maps to an ID on a web page.
  4069. * @param {String} message human readable error.
  4070. * @param {Error} [err] the original error, if there is one.
  4071. *
  4072. * @returns {Error}
  4073. */
  4074. function makeError(id, msg, err, requireModules) {
  4075. var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
  4076. e.requireType = id;
  4077. e.requireModules = requireModules;
  4078. if (err) {
  4079. e.originalError = err;
  4080. }
  4081. return e;
  4082. }
  4083. if (typeof define !== 'undefined') {
  4084. //If a define is already in play via another AMD loader,
  4085. //do not overwrite.
  4086. return;
  4087. }
  4088. if (typeof requirejs !== 'undefined') {
  4089. if (isFunction(requirejs)) {
  4090. //Do not overwrite and existing requirejs instance.
  4091. return;
  4092. }
  4093. cfg = requirejs;
  4094. requirejs = undefined;
  4095. }
  4096. //Allow for a require config object
  4097. if (typeof require !== 'undefined' && !isFunction(require)) {
  4098. //assume it is a config object.
  4099. cfg = require;
  4100. require = undefined;
  4101. }
  4102. function newContext(contextName) {
  4103. var inCheckLoaded, Module, context, handlers,
  4104. checkLoadedTimeoutId,
  4105. config = {
  4106. waitSeconds: 7,
  4107. baseUrl: './',
  4108. paths: {},
  4109. pkgs: {},
  4110. shim: {},
  4111. map: {},
  4112. config: {}
  4113. },
  4114. registry = {},
  4115. undefEvents = {},
  4116. defQueue = [],
  4117. defined = {},
  4118. urlFetched = {},
  4119. requireCounter = 1,
  4120. unnormalizedCounter = 1;
  4121. /**
  4122. * Trims the . and .. from an array of path segments.
  4123. * It will keep a leading path segment if a .. will become
  4124. * the first path segment, to help with module name lookups,
  4125. * which act like paths, but can be remapped. But the end result,
  4126. * all paths that use this function should look normalized.
  4127. * NOTE: this method MODIFIES the input array.
  4128. * @param {Array} ary the array of path segments.
  4129. */
  4130. function trimDots(ary) {
  4131. var i, part;
  4132. for (i = 0; ary[i]; i += 1) {
  4133. part = ary[i];
  4134. if (part === '.') {
  4135. ary.splice(i, 1);
  4136. i -= 1;
  4137. } else if (part === '..') {
  4138. if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
  4139. //End of the line. Keep at least one non-dot
  4140. //path segment at the front so it can be mapped
  4141. //correctly to disk. Otherwise, there is likely
  4142. //no path mapping for a path starting with '..'.
  4143. //This can still fail, but catches the most reasonable
  4144. //uses of ..
  4145. break;
  4146. } else if (i > 0) {
  4147. ary.splice(i - 1, 2);
  4148. i -= 2;
  4149. }
  4150. }
  4151. }
  4152. }
  4153. /**
  4154. * Given a relative module name, like ./something, normalize it to
  4155. * a real name that can be mapped to a path.
  4156. * @param {String} name the relative name
  4157. * @param {String} baseName a real name that the name arg is relative
  4158. * to.
  4159. * @param {Boolean} applyMap apply the map config to the value. Should
  4160. * only be done if this normalization is for a dependency ID.
  4161. * @returns {String} normalized name
  4162. */
  4163. function normalize(name, baseName, applyMap) {
  4164. var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment,
  4165. foundMap, foundI, foundStarMap, starI,
  4166. baseParts = baseName && baseName.split('/'),
  4167. normalizedBaseParts = baseParts,
  4168. map = config.map,
  4169. starMap = map && map['*'];
  4170. //Adjust any relative paths.
  4171. if (name && name.charAt(0) === '.') {
  4172. //If have a base name, try to normalize against it,
  4173. //otherwise, assume it is a top-level require that will
  4174. //be relative to baseUrl in the end.
  4175. if (baseName) {
  4176. if (getOwn(config.pkgs, baseName)) {
  4177. //If the baseName is a package name, then just treat it as one
  4178. //name to concat the name with.
  4179. normalizedBaseParts = baseParts = [baseName];
  4180. } else {
  4181. //Convert baseName to array, and lop off the last part,
  4182. //so that . matches that 'directory' and not name of the baseName's
  4183. //module. For instance, baseName of 'one/two/three', maps to
  4184. //'one/two/three.js', but we want the directory, 'one/two' for
  4185. //this normalization.
  4186. normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
  4187. }
  4188. name = normalizedBaseParts.concat(name.split('/'));
  4189. trimDots(name);
  4190. //Some use of packages may use a . path to reference the
  4191. //'main' module name, so normalize for that.
  4192. pkgConfig = getOwn(config.pkgs, (pkgName = name[0]));
  4193. name = name.join('/');
  4194. if (pkgConfig && name === pkgName + '/' + pkgConfig.main) {
  4195. name = pkgName;
  4196. }
  4197. } else if (name.indexOf('./') === 0) {
  4198. // No baseName, so this is ID is resolved relative
  4199. // to baseUrl, pull off the leading dot.
  4200. name = name.substring(2);
  4201. }
  4202. }
  4203. //Apply map config if available.
  4204. if (applyMap && (baseParts || starMap) && map) {
  4205. nameParts = name.split('/');
  4206. for (i = nameParts.length; i > 0; i -= 1) {
  4207. nameSegment = nameParts.slice(0, i).join('/');
  4208. if (baseParts) {
  4209. //Find the longest baseName segment match in the config.
  4210. //So, do joins on the biggest to smallest lengths of baseParts.
  4211. for (j = baseParts.length; j > 0; j -= 1) {
  4212. mapValue = getOwn(map, baseParts.slice(0, j).join('/'));
  4213. //baseName segment has config, find if it has one for
  4214. //this name.
  4215. if (mapValue) {
  4216. mapValue = getOwn(mapValue, nameSegment);
  4217. if (mapValue) {
  4218. //Match, update name to the new value.
  4219. foundMap = mapValue;
  4220. foundI = i;
  4221. break;
  4222. }
  4223. }
  4224. }
  4225. }
  4226. if (foundMap) {
  4227. break;
  4228. }
  4229. //Check for a star map match, but just hold on to it,
  4230. //if there is a shorter segment match later in a matching
  4231. //config, then favor over this star map.
  4232. if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) {
  4233. foundStarMap = getOwn(starMap, nameSegment);
  4234. starI = i;
  4235. }
  4236. }
  4237. if (!foundMap && foundStarMap) {
  4238. foundMap = foundStarMap;
  4239. foundI = starI;
  4240. }
  4241. if (foundMap) {
  4242. nameParts.splice(0, foundI, foundMap);
  4243. name = nameParts.join('/');
  4244. }
  4245. }
  4246. return name;
  4247. }
  4248. function removeScript(name) {
  4249. if (isBrowser) {
  4250. each(scripts(), function (scriptNode) {
  4251. if (scriptNode.getAttribute('data-requiremodule') === name &&
  4252. scriptNode.getAttribute('data-requirecontext') === context.contextName) {
  4253. scriptNode.parentNode.removeChild(scriptNode);
  4254. return true;
  4255. }
  4256. });
  4257. }
  4258. }
  4259. function hasPathFallback(id) {
  4260. var pathConfig = getOwn(config.paths, id);
  4261. if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
  4262. removeScript(id);
  4263. //Pop off the first array value, since it failed, and
  4264. //retry
  4265. pathConfig.shift();
  4266. context.require.undef(id);
  4267. context.require([id]);
  4268. return true;
  4269. }
  4270. }
  4271. //Turns a plugin!resource to [plugin, resource]
  4272. //with the plugin being undefined if the name
  4273. //did not have a plugin prefix.
  4274. function splitPrefix(name) {
  4275. var prefix,
  4276. index = name ? name.indexOf('!') : -1;
  4277. if (index > -1) {
  4278. prefix = name.substring(0, index);
  4279. name = name.substring(index + 1, name.length);
  4280. }
  4281. return [prefix, name];
  4282. }
  4283. /**
  4284. * Creates a module mapping that includes plugin prefix, module
  4285. * name, and path. If parentModuleMap is provided it will
  4286. * also normalize the name via require.normalize()
  4287. *
  4288. * @param {String} name the module name
  4289. * @param {String} [parentModuleMap] parent module map
  4290. * for the module name, used to resolve relative names.
  4291. * @param {Boolean} isNormalized: is the ID already normalized.
  4292. * This is true if this call is done for a define() module ID.
  4293. * @param {Boolean} applyMap: apply the map config to the ID.
  4294. * Should only be true if this map is for a dependency.
  4295. *
  4296. * @returns {Object}
  4297. */
  4298. function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
  4299. var url, pluginModule, suffix, nameParts,
  4300. prefix = null,
  4301. parentName = parentModuleMap ? parentModuleMap.name : null,
  4302. originalName = name,
  4303. isDefine = true,
  4304. normalizedName = '';
  4305. //If no name, then it means it is a require call, generate an
  4306. //internal name.
  4307. if (!name) {
  4308. isDefine = false;
  4309. name = '_@r' + (requireCounter += 1);
  4310. }
  4311. nameParts = splitPrefix(name);
  4312. prefix = nameParts[0];
  4313. name = nameParts[1];
  4314. if (prefix) {
  4315. prefix = normalize(prefix, parentName, applyMap);
  4316. pluginModule = getOwn(defined, prefix);
  4317. }
  4318. //Account for relative paths if there is a base name.
  4319. if (name) {
  4320. if (prefix) {
  4321. if (pluginModule && pluginModule.normalize) {
  4322. //Plugin is loaded, use its normalize method.
  4323. normalizedName = pluginModule.normalize(name, function (name) {
  4324. return normalize(name, parentName, applyMap);
  4325. });
  4326. } else {
  4327. normalizedName = normalize(name, parentName, applyMap);
  4328. }
  4329. } else {
  4330. //A regular module.
  4331. normalizedName = normalize(name, parentName, applyMap);
  4332. //Normalized name may be a plugin ID due to map config
  4333. //application in normalize. The map config values must
  4334. //already be normalized, so do not need to redo that part.
  4335. nameParts = splitPrefix(normalizedName);
  4336. prefix = nameParts[0];
  4337. normalizedName = nameParts[1];
  4338. isNormalized = true;
  4339. url = context.nameToUrl(normalizedName);
  4340. }
  4341. }
  4342. //If the id is a plugin id that cannot be determined if it needs
  4343. //normalization, stamp it with a unique ID so two matching relative
  4344. //ids that may conflict can be separate.
  4345. suffix = prefix && !pluginModule && !isNormalized ?
  4346. '_unnormalized' + (unnormalizedCounter += 1) :
  4347. '';
  4348. return {
  4349. prefix: prefix,
  4350. name: normalizedName,
  4351. parentMap: parentModuleMap,
  4352. unnormalized: !!suffix,
  4353. url: url,
  4354. originalName: originalName,
  4355. isDefine: isDefine,
  4356. id: (prefix ?
  4357. prefix + '!' + normalizedName :
  4358. normalizedName) + suffix
  4359. };
  4360. }
  4361. function getModule(depMap) {
  4362. var id = depMap.id,
  4363. mod = getOwn(registry, id);
  4364. if (!mod) {
  4365. mod = registry[id] = new context.Module(depMap);
  4366. }
  4367. return mod;
  4368. }
  4369. function on(depMap, name, fn) {
  4370. var id = depMap.id,
  4371. mod = getOwn(registry, id);
  4372. if (hasProp(defined, id) &&
  4373. (!mod || mod.defineEmitComplete)) {
  4374. if (name === 'defined') {
  4375. fn(defined[id]);
  4376. }
  4377. } else {
  4378. getModule(depMap).on(name, fn);
  4379. }
  4380. }
  4381. function onError(err, errback) {
  4382. var ids = err.requireModules,
  4383. notified = false;
  4384. if (errback) {
  4385. errback(err);
  4386. } else {
  4387. each(ids, function (id) {
  4388. var mod = getOwn(registry, id);
  4389. if (mod) {
  4390. //Set error on module, so it skips timeout checks.
  4391. mod.error = err;
  4392. if (mod.events.error) {
  4393. notified = true;
  4394. mod.emit('error', err);
  4395. }
  4396. }
  4397. });
  4398. if (!notified) {
  4399. req.onError(err);
  4400. }
  4401. }
  4402. }
  4403. /**
  4404. * Internal method to transfer globalQueue items to this context's
  4405. * defQueue.
  4406. */
  4407. function takeGlobalQueue() {
  4408. //Push all the globalDefQueue items into the context's defQueue
  4409. if (globalDefQueue.length) {
  4410. //Array splice in the values since the context code has a
  4411. //local var ref to defQueue, so cannot just reassign the one
  4412. //on context.
  4413. apsp.apply(defQueue,
  4414. [defQueue.length - 1, 0].concat(globalDefQueue));
  4415. globalDefQueue = [];
  4416. }
  4417. }
  4418. handlers = {
  4419. 'require': function (mod) {
  4420. if (mod.require) {
  4421. return mod.require;
  4422. } else {
  4423. return (mod.require = context.makeRequire(mod.map));
  4424. }
  4425. },
  4426. 'exports': function (mod) {
  4427. mod.usingExports = true;
  4428. if (mod.map.isDefine) {
  4429. if (mod.exports) {
  4430. return mod.exports;
  4431. } else {
  4432. return (mod.exports = defined[mod.map.id] = {});
  4433. }
  4434. }
  4435. },
  4436. 'module': function (mod) {
  4437. if (mod.module) {
  4438. return mod.module;
  4439. } else {
  4440. return (mod.module = {
  4441. id: mod.map.id,
  4442. uri: mod.map.url,
  4443. config: function () {
  4444. return (config.config && getOwn(config.config, mod.map.id)) || {};
  4445. },
  4446. exports: defined[mod.map.id]
  4447. });
  4448. }
  4449. }
  4450. };
  4451. function cleanRegistry(id) {
  4452. //Clean up machinery used for waiting modules.
  4453. delete registry[id];
  4454. }
  4455. function breakCycle(mod, traced, processed) {
  4456. var id = mod.map.id;
  4457. if (mod.error) {
  4458. mod.emit('error', mod.error);
  4459. } else {
  4460. traced[id] = true;
  4461. each(mod.depMaps, function (depMap, i) {
  4462. var depId = depMap.id,
  4463. dep = getOwn(registry, depId);
  4464. //Only force things that have not completed
  4465. //being defined, so still in the registry,
  4466. //and only if it has not been matched up
  4467. //in the module already.
  4468. if (dep && !mod.depMatched[i] && !processed[depId]) {
  4469. if (getOwn(traced, depId)) {
  4470. mod.defineDep(i, defined[depId]);
  4471. mod.check(); //pass false?
  4472. } else {
  4473. breakCycle(dep, traced, processed);
  4474. }
  4475. }
  4476. });
  4477. processed[id] = true;
  4478. }
  4479. }
  4480. function checkLoaded() {
  4481. var map, modId, err, usingPathFallback,
  4482. waitInterval = config.waitSeconds * 1000,
  4483. //It is possible to disable the wait interval by using waitSeconds of 0.
  4484. expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
  4485. noLoads = [],
  4486. reqCalls = [],
  4487. stillLoading = false,
  4488. needCycleCheck = true;
  4489. //Do not bother if this call was a result of a cycle break.
  4490. if (inCheckLoaded) {
  4491. return;
  4492. }
  4493. inCheckLoaded = true;
  4494. //Figure out the state of all the modules.
  4495. eachProp(registry, function (mod) {
  4496. map = mod.map;
  4497. modId = map.id;
  4498. //Skip things that are not enabled or in error state.
  4499. if (!mod.enabled) {
  4500. return;
  4501. }
  4502. if (!map.isDefine) {
  4503. reqCalls.push(mod);
  4504. }
  4505. if (!mod.error) {
  4506. //If the module should be executed, and it has not
  4507. //been inited and time is up, remember it.
  4508. if (!mod.inited && expired) {
  4509. if (hasPathFallback(modId)) {
  4510. usingPathFallback = true;
  4511. stillLoading = true;
  4512. } else {
  4513. noLoads.push(modId);
  4514. removeScript(modId);
  4515. }
  4516. } else if (!mod.inited && mod.fetched && map.isDefine) {
  4517. stillLoading = true;
  4518. if (!map.prefix) {
  4519. //No reason to keep looking for unfinished
  4520. //loading. If the only stillLoading is a
  4521. //plugin resource though, keep going,
  4522. //because it may be that a plugin resource
  4523. //is waiting on a non-plugin cycle.
  4524. return (needCycleCheck = false);
  4525. }
  4526. }
  4527. }
  4528. });
  4529. if (expired && noLoads.length) {
  4530. //If wait time expired, throw error of unloaded modules.
  4531. err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads);
  4532. err.contextName = context.contextName;
  4533. return onError(err);
  4534. }
  4535. //Not expired, check for a cycle.
  4536. if (needCycleCheck) {
  4537. each(reqCalls, function (mod) {
  4538. breakCycle(mod, {}, {});
  4539. });
  4540. }
  4541. //If still waiting on loads, and the waiting load is something
  4542. //other than a plugin resource, or there are still outstanding
  4543. //scripts, then just try back later.
  4544. if ((!expired || usingPathFallback) && stillLoading) {
  4545. //Something is still waiting to load. Wait for it, but only
  4546. //if a timeout is not already in effect.
  4547. if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
  4548. checkLoadedTimeoutId = setTimeout(function () {
  4549. checkLoadedTimeoutId = 0;
  4550. checkLoaded();
  4551. }, 50);
  4552. }
  4553. }
  4554. inCheckLoaded = false;
  4555. }
  4556. Module = function (map) {
  4557. this.events = getOwn(undefEvents, map.id) || {};
  4558. this.map = map;
  4559. this.shim = getOwn(config.shim, map.id);
  4560. this.depExports = [];
  4561. this.depMaps = [];
  4562. this.depMatched = [];
  4563. this.pluginMaps = {};
  4564. this.depCount = 0;
  4565. /* this.exports this.factory
  4566. this.depMaps = [],
  4567. this.enabled, this.fetched
  4568. */
  4569. };
  4570. Module.prototype = {
  4571. init: function (depMaps, factory, errback, options) {
  4572. options = options || {};
  4573. //Do not do more inits if already done. Can happen if there
  4574. //are multiple define calls for the same module. That is not
  4575. //a normal, common case, but it is also not unexpected.
  4576. if (this.inited) {
  4577. return;
  4578. }
  4579. this.factory = factory;
  4580. if (errback) {
  4581. //Register for errors on this module.
  4582. this.on('error', errback);
  4583. } else if (this.events.error) {
  4584. //If no errback already, but there are error listeners
  4585. //on this module, set up an errback to pass to the deps.
  4586. errback = bind(this, function (err) {
  4587. this.emit('error', err);
  4588. });
  4589. }
  4590. //Do a copy of the dependency array, so that
  4591. //source inputs are not modified. For example
  4592. //"shim" deps are passed in here directly, and
  4593. //doing a direct modification of the depMaps array
  4594. //would affect that config.
  4595. this.depMaps = depMaps && depMaps.slice(0);
  4596. this.errback = errback;
  4597. //Indicate this module has be initialized
  4598. this.inited = true;
  4599. this.ignore = options.ignore;
  4600. //Could have option to init this module in enabled mode,
  4601. //or could have been previously marked as enabled. However,
  4602. //the dependencies are not known until init is called. So
  4603. //if enabled previously, now trigger dependencies as enabled.
  4604. if (options.enabled || this.enabled) {
  4605. //Enable this module and dependencies.
  4606. //Will call this.check()
  4607. this.enable();
  4608. } else {
  4609. this.check();
  4610. }
  4611. },
  4612. defineDep: function (i, depExports) {
  4613. //Because of cycles, defined callback for a given
  4614. //export can be called more than once.
  4615. if (!this.depMatched[i]) {
  4616. this.depMatched[i] = true;
  4617. this.depCount -= 1;
  4618. this.depExports[i] = depExports;
  4619. }
  4620. },
  4621. fetch: function () {
  4622. if (this.fetched) {
  4623. return;
  4624. }
  4625. this.fetched = true;
  4626. context.startTime = (new Date()).getTime();
  4627. var map = this.map;
  4628. //If the manager is for a plugin managed resource,
  4629. //ask the plugin to load it now.
  4630. if (this.shim) {
  4631. context.makeRequire(this.map, {
  4632. enableBuildCallback: true
  4633. })(this.shim.deps || [], bind(this, function () {
  4634. return map.prefix ? this.callPlugin() : this.load();
  4635. }));
  4636. } else {
  4637. //Regular dependency.
  4638. return map.prefix ? this.callPlugin() : this.load();
  4639. }
  4640. },
  4641. load: function () {
  4642. var url = this.map.url;
  4643. //Regular dependency.
  4644. if (!urlFetched[url]) {
  4645. urlFetched[url] = true;
  4646. context.load(this.map.id, url);
  4647. }
  4648. },
  4649. /**
  4650. * Checks is the module is ready to define itself, and if so,
  4651. * define it.
  4652. */
  4653. check: function () {
  4654. if (!this.enabled || this.enabling) {
  4655. return;
  4656. }
  4657. var err, cjsModule,
  4658. id = this.map.id,
  4659. depExports = this.depExports,
  4660. exports = this.exports,
  4661. factory = this.factory;
  4662. if (!this.inited) {
  4663. this.fetch();
  4664. } else if (this.error) {
  4665. this.emit('error', this.error);
  4666. } else if (!this.defining) {
  4667. //The factory could trigger another require call
  4668. //that would result in checking this module to
  4669. //define itself again. If already in the process
  4670. //of doing that, skip this work.
  4671. this.defining = true;
  4672. if (this.depCount < 1 && !this.defined) {
  4673. if (isFunction(factory)) {
  4674. //If there is an error listener, favor passing
  4675. //to that instead of throwing an error.
  4676. if (this.events.error) {
  4677. try {
  4678. exports = context.execCb(id, factory, depExports, exports);
  4679. } catch (e) {
  4680. err = e;
  4681. }
  4682. } else {
  4683. exports = context.execCb(id, factory, depExports, exports);
  4684. }
  4685. if (this.map.isDefine) {
  4686. //If setting exports via 'module' is in play,
  4687. //favor that over return value and exports. After that,
  4688. //favor a non-undefined return value over exports use.
  4689. cjsModule = this.module;
  4690. if (cjsModule &&
  4691. cjsModule.exports !== undefined &&
  4692. //Make sure it is not already the exports value
  4693. cjsModule.exports !== this.exports) {
  4694. exports = cjsModule.exports;
  4695. } else if (exports === undefined && this.usingExports) {
  4696. //exports already set the defined value.
  4697. exports = this.exports;
  4698. }
  4699. }
  4700. if (err) {
  4701. err.requireMap = this.map;
  4702. err.requireModules = [this.map.id];
  4703. err.requireType = 'define';
  4704. return onError((this.error = err));
  4705. }
  4706. } else {
  4707. //Just a literal value
  4708. exports = factory;
  4709. }
  4710. this.exports = exports;
  4711. if (this.map.isDefine && !this.ignore) {
  4712. defined[id] = exports;
  4713. if (req.onResourceLoad) {
  4714. req.onResourceLoad(context, this.map, this.depMaps);
  4715. }
  4716. }
  4717. //Clean up
  4718. delete registry[id];
  4719. this.defined = true;
  4720. }
  4721. //Finished the define stage. Allow calling check again
  4722. //to allow define notifications below in the case of a
  4723. //cycle.
  4724. this.defining = false;
  4725. if (this.defined && !this.defineEmitted) {
  4726. this.defineEmitted = true;
  4727. this.emit('defined', this.exports);
  4728. this.defineEmitComplete = true;
  4729. }
  4730. }
  4731. },
  4732. callPlugin: function () {
  4733. var map = this.map,
  4734. id = map.id,
  4735. //Map already normalized the prefix.
  4736. pluginMap = makeModuleMap(map.prefix);
  4737. //Mark this as a dependency for this plugin, so it
  4738. //can be traced for cycles.
  4739. this.depMaps.push(pluginMap);
  4740. on(pluginMap, 'defined', bind(this, function (plugin) {
  4741. var load, normalizedMap, normalizedMod,
  4742. name = this.map.name,
  4743. parentName = this.map.parentMap ? this.map.parentMap.name : null,
  4744. localRequire = context.makeRequire(map.parentMap, {
  4745. enableBuildCallback: true
  4746. });
  4747. //If current map is not normalized, wait for that
  4748. //normalized name to load instead of continuing.
  4749. if (this.map.unnormalized) {
  4750. //Normalize the ID if the plugin allows it.
  4751. if (plugin.normalize) {
  4752. name = plugin.normalize(name, function (name) {
  4753. return normalize(name, parentName, true);
  4754. }) || '';
  4755. }
  4756. //prefix and name should already be normalized, no need
  4757. //for applying map config again either.
  4758. normalizedMap = makeModuleMap(map.prefix + '!' + name,
  4759. this.map.parentMap);
  4760. on(normalizedMap,
  4761. 'defined', bind(this, function (value) {
  4762. this.init([], function () { return value; }, null, {
  4763. enabled: true,
  4764. ignore: true
  4765. });
  4766. }));
  4767. normalizedMod = getOwn(registry, normalizedMap.id);
  4768. if (normalizedMod) {
  4769. //Mark this as a dependency for this plugin, so it
  4770. //can be traced for cycles.
  4771. this.depMaps.push(normalizedMap);
  4772. if (this.events.error) {
  4773. normalizedMod.on('error', bind(this, function (err) {
  4774. this.emit('error', err);
  4775. }));
  4776. }
  4777. normalizedMod.enable();
  4778. }
  4779. return;
  4780. }
  4781. load = bind(this, function (value) {
  4782. this.init([], function () { return value; }, null, {
  4783. enabled: true
  4784. });
  4785. });
  4786. load.error = bind(this, function (err) {
  4787. this.inited = true;
  4788. this.error = err;
  4789. err.requireModules = [id];
  4790. //Remove temp unnormalized modules for this module,
  4791. //since they will never be resolved otherwise now.
  4792. eachProp(registry, function (mod) {
  4793. if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
  4794. cleanRegistry(mod.map.id);
  4795. }
  4796. });
  4797. onError(err);
  4798. });
  4799. //Allow plugins to load other code without having to know the
  4800. //context or how to 'complete' the load.
  4801. load.fromText = bind(this, function (text, textAlt) {
  4802. /*jslint evil: true */
  4803. var moduleName = map.name,
  4804. moduleMap = makeModuleMap(moduleName),
  4805. hasInteractive = useInteractive;
  4806. //As of 2.1.0, support just passing the text, to reinforce
  4807. //fromText only being called once per resource. Still
  4808. //support old style of passing moduleName but discard
  4809. //that moduleName in favor of the internal ref.
  4810. if (textAlt) {
  4811. text = textAlt;
  4812. }
  4813. //Turn off interactive script matching for IE for any define
  4814. //calls in the text, then turn it back on at the end.
  4815. if (hasInteractive) {
  4816. useInteractive = false;
  4817. }
  4818. //Prime the system by creating a module instance for
  4819. //it.
  4820. getModule(moduleMap);
  4821. //Transfer any config to this other module.
  4822. if (hasProp(config.config, id)) {
  4823. config.config[moduleName] = config.config[id];
  4824. }
  4825. try {
  4826. req.exec(text);
  4827. } catch (e) {
  4828. return onError(makeError('fromtexteval',
  4829. 'fromText eval for ' + id +
  4830. ' failed: ' + e,
  4831. e,
  4832. [id]));
  4833. }
  4834. if (hasInteractive) {
  4835. useInteractive = true;
  4836. }
  4837. //Mark this as a dependency for the plugin
  4838. //resource
  4839. this.depMaps.push(moduleMap);
  4840. //Support anonymous modules.
  4841. context.completeLoad(moduleName);
  4842. //Bind the value of that module to the value for this
  4843. //resource ID.
  4844. localRequire([moduleName], load);
  4845. });
  4846. //Use parentName here since the plugin's name is not reliable,
  4847. //could be some weird string with no path that actually wants to
  4848. //reference the parentName's path.
  4849. plugin.load(map.name, localRequire, load, config);
  4850. }));
  4851. context.enable(pluginMap, this);
  4852. this.pluginMaps[pluginMap.id] = pluginMap;
  4853. },
  4854. enable: function () {
  4855. this.enabled = true;
  4856. //Set flag mentioning that the module is enabling,
  4857. //so that immediate calls to the defined callbacks
  4858. //for dependencies do not trigger inadvertent load
  4859. //with the depCount still being zero.
  4860. this.enabling = true;
  4861. //Enable each dependency
  4862. each(this.depMaps, bind(this, function (depMap, i) {
  4863. var id, mod, handler;
  4864. if (typeof depMap === 'string') {
  4865. //Dependency needs to be converted to a depMap
  4866. //and wired up to this module.
  4867. depMap = makeModuleMap(depMap,
  4868. (this.map.isDefine ? this.map : this.map.parentMap),
  4869. false,
  4870. !this.skipMap);
  4871. this.depMaps[i] = depMap;
  4872. handler = getOwn(handlers, depMap.id);
  4873. if (handler) {
  4874. this.depExports[i] = handler(this);
  4875. return;
  4876. }
  4877. this.depCount += 1;
  4878. on(depMap, 'defined', bind(this, function (depExports) {
  4879. this.defineDep(i, depExports);
  4880. this.check();
  4881. }));
  4882. if (this.errback) {
  4883. on(depMap, 'error', this.errback);
  4884. }
  4885. }
  4886. id = depMap.id;
  4887. mod = registry[id];
  4888. //Skip special modules like 'require', 'exports', 'module'
  4889. //Also, don't call enable if it is already enabled,
  4890. //important in circular dependency cases.
  4891. if (!hasProp(handlers, id) && mod && !mod.enabled) {
  4892. context.enable(depMap, this);
  4893. }
  4894. }));
  4895. //Enable each plugin that is used in
  4896. //a dependency
  4897. eachProp(this.pluginMaps, bind(this, function (pluginMap) {
  4898. var mod = getOwn(registry, pluginMap.id);
  4899. if (mod && !mod.enabled) {
  4900. context.enable(pluginMap, this);
  4901. }
  4902. }));
  4903. this.enabling = false;
  4904. this.check();
  4905. },
  4906. on: function (name, cb) {
  4907. var cbs = this.events[name];
  4908. if (!cbs) {
  4909. cbs = this.events[name] = [];
  4910. }
  4911. cbs.push(cb);
  4912. },
  4913. emit: function (name, evt) {
  4914. each(this.events[name], function (cb) {
  4915. cb(evt);
  4916. });
  4917. if (name === 'error') {
  4918. //Now that the error handler was triggered, remove
  4919. //the listeners, since this broken Module instance
  4920. //can stay around for a while in the registry.
  4921. delete this.events[name];
  4922. }
  4923. }
  4924. };
  4925. function callGetModule(args) {
  4926. //Skip modules already defined.
  4927. if (!hasProp(defined, args[0])) {
  4928. getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
  4929. }
  4930. }
  4931. function removeListener(node, func, name, ieName) {
  4932. //Favor detachEvent because of IE9
  4933. //issue, see attachEvent/addEventListener comment elsewhere
  4934. //in this file.
  4935. if (node.detachEvent && !isOpera) {
  4936. //Probably IE. If not it will throw an error, which will be
  4937. //useful to know.
  4938. if (ieName) {
  4939. node.detachEvent(ieName, func);
  4940. }
  4941. } else {
  4942. node.removeEventListener(name, func, false);
  4943. }
  4944. }
  4945. /**
  4946. * Given an event from a script node, get the requirejs info from it,
  4947. * and then removes the event listeners on the node.
  4948. * @param {Event} evt
  4949. * @returns {Object}
  4950. */
  4951. function getScriptData(evt) {
  4952. //Using currentTarget instead of target for Firefox 2.0's sake. Not
  4953. //all old browsers will be supported, but this one was easy enough
  4954. //to support and still makes sense.
  4955. var node = evt.currentTarget || evt.srcElement;
  4956. //Remove the listeners once here.
  4957. removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange');
  4958. removeListener(node, context.onScriptError, 'error');
  4959. return {
  4960. node: node,
  4961. id: node && node.getAttribute('data-requiremodule')
  4962. };
  4963. }
  4964. function intakeDefines() {
  4965. var args;
  4966. //Any defined modules in the global queue, intake them now.
  4967. takeGlobalQueue();
  4968. //Make sure any remaining defQueue items get properly processed.
  4969. while (defQueue.length) {
  4970. args = defQueue.shift();
  4971. if (args[0] === null) {
  4972. return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
  4973. } else {
  4974. //args are id, deps, factory. Should be normalized by the
  4975. //define() function.
  4976. callGetModule(args);
  4977. }
  4978. }
  4979. }
  4980. context = {
  4981. config: config,
  4982. contextName: contextName,
  4983. registry: registry,
  4984. defined: defined,
  4985. urlFetched: urlFetched,
  4986. defQueue: defQueue,
  4987. Module: Module,
  4988. makeModuleMap: makeModuleMap,
  4989. nextTick: req.nextTick,
  4990. /**
  4991. * Set a configuration for the context.
  4992. * @param {Object} cfg config object to integrate.
  4993. */
  4994. configure: function (cfg) {
  4995. //Make sure the baseUrl ends in a slash.
  4996. if (cfg.baseUrl) {
  4997. if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') {
  4998. cfg.baseUrl += '/';
  4999. }
  5000. }
  5001. //Save off the paths and packages since they require special processing,
  5002. //they are additive.
  5003. var pkgs = config.pkgs,
  5004. shim = config.shim,
  5005. objs = {
  5006. paths: true,
  5007. config: true,
  5008. map: true
  5009. };
  5010. eachProp(cfg, function (value, prop) {
  5011. if (objs[prop]) {
  5012. if (prop === 'map') {
  5013. mixin(config[prop], value, true, true);
  5014. } else {
  5015. mixin(config[prop], value, true);
  5016. }
  5017. } else {
  5018. config[prop] = value;
  5019. }
  5020. });
  5021. //Merge shim
  5022. if (cfg.shim) {
  5023. eachProp(cfg.shim, function (value, id) {
  5024. //Normalize the structure
  5025. if (isArray(value)) {
  5026. value = {
  5027. deps: value
  5028. };
  5029. }
  5030. if ((value.exports || value.init) && !value.exportsFn) {
  5031. value.exportsFn = context.makeShimExports(value);
  5032. }
  5033. shim[id] = value;
  5034. });
  5035. config.shim = shim;
  5036. }
  5037. //Adjust packages if necessary.
  5038. if (cfg.packages) {
  5039. each(cfg.packages, function (pkgObj) {
  5040. var location;
  5041. pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj;
  5042. location = pkgObj.location;
  5043. //Create a brand new object on pkgs, since currentPackages can
  5044. //be passed in again, and config.pkgs is the internal transformed
  5045. //state for all package configs.
  5046. pkgs[pkgObj.name] = {
  5047. name: pkgObj.name,
  5048. location: location || pkgObj.name,
  5049. //Remove leading dot in main, so main paths are normalized,
  5050. //and remove any trailing .js, since different package
  5051. //envs have different conventions: some use a module name,
  5052. //some use a file name.
  5053. main: (pkgObj.main || 'main')
  5054. .replace(currDirRegExp, '')
  5055. .replace(jsSuffixRegExp, '')
  5056. };
  5057. });
  5058. //Done with modifications, assing packages back to context config
  5059. config.pkgs = pkgs;
  5060. }
  5061. //If there are any "waiting to execute" modules in the registry,
  5062. //update the maps for them, since their info, like URLs to load,
  5063. //may have changed.
  5064. eachProp(registry, function (mod, id) {
  5065. //If module already has init called, since it is too
  5066. //late to modify them, and ignore unnormalized ones
  5067. //since they are transient.
  5068. if (!mod.inited && !mod.map.unnormalized) {
  5069. mod.map = makeModuleMap(id);
  5070. }
  5071. });
  5072. //If a deps array or a config callback is specified, then call
  5073. //require with those args. This is useful when require is defined as a
  5074. //config object before require.js is loaded.
  5075. if (cfg.deps || cfg.callback) {
  5076. context.require(cfg.deps || [], cfg.callback);
  5077. }
  5078. },
  5079. makeShimExports: function (value) {
  5080. function fn() {
  5081. var ret;
  5082. if (value.init) {
  5083. ret = value.init.apply(global, arguments);
  5084. }
  5085. return ret || (value.exports && getGlobal(value.exports));
  5086. }
  5087. return fn;
  5088. },
  5089. makeRequire: function (relMap, options) {
  5090. options = options || {};
  5091. function localRequire(deps, callback, errback) {
  5092. var id, map, requireMod;
  5093. if (options.enableBuildCallback && callback && isFunction(callback)) {
  5094. callback.__requireJsBuild = true;
  5095. }
  5096. if (typeof deps === 'string') {
  5097. if (isFunction(callback)) {
  5098. //Invalid call
  5099. return onError(makeError('requireargs', 'Invalid require call'), errback);
  5100. }
  5101. //If require|exports|module are requested, get the
  5102. //value for them from the special handlers. Caveat:
  5103. //this only works while module is being defined.
  5104. if (relMap && hasProp(handlers, deps)) {
  5105. return handlers[deps](registry[relMap.id]);
  5106. }
  5107. //Synchronous access to one module. If require.get is
  5108. //available (as in the Node adapter), prefer that.
  5109. if (req.get) {
  5110. return req.get(context, deps, relMap);
  5111. }
  5112. //Normalize module name, if it contains . or ..
  5113. map = makeModuleMap(deps, relMap, false, true);
  5114. id = map.id;
  5115. if (!hasProp(defined, id)) {
  5116. return onError(makeError('notloaded', 'Module name "' +
  5117. id +
  5118. '" has not been loaded yet for context: ' +
  5119. contextName +
  5120. (relMap ? '' : '. Use require([])')));
  5121. }
  5122. return defined[id];
  5123. }
  5124. //Grab defines waiting in the global queue.
  5125. intakeDefines();
  5126. //Mark all the dependencies as needing to be loaded.
  5127. context.nextTick(function () {
  5128. //Some defines could have been added since the
  5129. //require call, collect them.
  5130. intakeDefines();
  5131. requireMod = getModule(makeModuleMap(null, relMap));
  5132. //Store if map config should be applied to this require
  5133. //call for dependencies.
  5134. requireMod.skipMap = options.skipMap;
  5135. requireMod.init(deps, callback, errback, {
  5136. enabled: true
  5137. });
  5138. checkLoaded();
  5139. });
  5140. return localRequire;
  5141. }
  5142. mixin(localRequire, {
  5143. isBrowser: isBrowser,
  5144. /**
  5145. * Converts a module name + .extension into an URL path.
  5146. * *Requires* the use of a module name. It does not support using
  5147. * plain URLs like nameToUrl.
  5148. */
  5149. toUrl: function (moduleNamePlusExt) {
  5150. var ext, url,
  5151. index = moduleNamePlusExt.lastIndexOf('.'),
  5152. segment = moduleNamePlusExt.split('/')[0],
  5153. isRelative = segment === '.' || segment === '..';
  5154. //Have a file extension alias, and it is not the
  5155. //dots from a relative path.
  5156. if (index !== -1 && (!isRelative || index > 1)) {
  5157. ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
  5158. moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
  5159. }
  5160. url = context.nameToUrl(normalize(moduleNamePlusExt,
  5161. relMap && relMap.id, true), ext || '.fake');
  5162. return ext ? url : url.substring(0, url.length - 5);
  5163. },
  5164. defined: function (id) {
  5165. return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
  5166. },
  5167. specified: function (id) {
  5168. id = makeModuleMap(id, relMap, false, true).id;
  5169. return hasProp(defined, id) || hasProp(registry, id);
  5170. }
  5171. });
  5172. //Only allow undef on top level require calls
  5173. if (!relMap) {
  5174. localRequire.undef = function (id) {
  5175. //Bind any waiting define() calls to this context,
  5176. //fix for #408
  5177. takeGlobalQueue();
  5178. var map = makeModuleMap(id, relMap, true),
  5179. mod = getOwn(registry, id);
  5180. delete defined[id];
  5181. delete urlFetched[map.url];
  5182. delete undefEvents[id];
  5183. if (mod) {
  5184. //Hold on to listeners in case the
  5185. //module will be attempted to be reloaded
  5186. //using a different config.
  5187. if (mod.events.defined) {
  5188. undefEvents[id] = mod.events;
  5189. }
  5190. cleanRegistry(id);
  5191. }
  5192. };
  5193. }
  5194. return localRequire;
  5195. },
  5196. /**
  5197. * Called to enable a module if it is still in the registry
  5198. * awaiting enablement. A second arg, parent, the parent module,
  5199. * is passed in for context, when this method is overriden by
  5200. * the optimizer. Not shown here to keep code compact.
  5201. */
  5202. enable: function (depMap) {
  5203. var mod = getOwn(registry, depMap.id);
  5204. if (mod) {
  5205. getModule(depMap).enable();
  5206. }
  5207. },
  5208. /**
  5209. * Internal method used by environment adapters to complete a load event.
  5210. * A load event could be a script load or just a load pass from a synchronous
  5211. * load call.
  5212. * @param {String} moduleName the name of the module to potentially complete.
  5213. */
  5214. completeLoad: function (moduleName) {
  5215. var found, args, mod,
  5216. shim = getOwn(config.shim, moduleName) || {},
  5217. shExports = shim.exports;
  5218. takeGlobalQueue();
  5219. while (defQueue.length) {
  5220. args = defQueue.shift();
  5221. if (args[0] === null) {
  5222. args[0] = moduleName;
  5223. //If already found an anonymous module and bound it
  5224. //to this name, then this is some other anon module
  5225. //waiting for its completeLoad to fire.
  5226. if (found) {
  5227. break;
  5228. }
  5229. found = true;
  5230. } else if (args[0] === moduleName) {
  5231. //Found matching define call for this script!
  5232. found = true;
  5233. }
  5234. callGetModule(args);
  5235. }
  5236. //Do this after the cycle of callGetModule in case the result
  5237. //of those calls/init calls changes the registry.
  5238. mod = getOwn(registry, moduleName);
  5239. if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) {
  5240. if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
  5241. if (hasPathFallback(moduleName)) {
  5242. return;
  5243. } else {
  5244. return onError(makeError('nodefine',
  5245. 'No define call for ' + moduleName,
  5246. null,
  5247. [moduleName]));
  5248. }
  5249. } else {
  5250. //A script that does not call define(), so just simulate
  5251. //the call for it.
  5252. callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
  5253. }
  5254. }
  5255. checkLoaded();
  5256. },
  5257. /**
  5258. * Converts a module name to a file path. Supports cases where
  5259. * moduleName may actually be just an URL.
  5260. * Note that it **does not** call normalize on the moduleName,
  5261. * it is assumed to have already been normalized. This is an
  5262. * internal API, not a public one. Use toUrl for the public API.
  5263. */
  5264. nameToUrl: function (moduleName, ext) {
  5265. var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url,
  5266. parentPath;
  5267. //If a colon is in the URL, it indicates a protocol is used and it is just
  5268. //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
  5269. //or ends with .js, then assume the user meant to use an url and not a module id.
  5270. //The slash is important for protocol-less URLs as well as full paths.
  5271. if (req.jsExtRegExp.test(moduleName)) {
  5272. //Just a plain path, not module name lookup, so just return it.
  5273. //Add extension if it is included. This is a bit wonky, only non-.js things pass
  5274. //an extension, this method probably needs to be reworked.
  5275. url = moduleName + (ext || '');
  5276. } else {
  5277. //A module that needs to be converted to a path.
  5278. paths = config.paths;
  5279. pkgs = config.pkgs;
  5280. syms = moduleName.split('/');
  5281. //For each module name segment, see if there is a path
  5282. //registered for it. Start with most specific name
  5283. //and work up from it.
  5284. for (i = syms.length; i > 0; i -= 1) {
  5285. parentModule = syms.slice(0, i).join('/');
  5286. pkg = getOwn(pkgs, parentModule);
  5287. parentPath = getOwn(paths, parentModule);
  5288. if (parentPath) {
  5289. //If an array, it means there are a few choices,
  5290. //Choose the one that is desired
  5291. if (isArray(parentPath)) {
  5292. parentPath = parentPath[0];
  5293. }
  5294. syms.splice(0, i, parentPath);
  5295. break;
  5296. } else if (pkg) {
  5297. //If module name is just the package name, then looking
  5298. //for the main module.
  5299. if (moduleName === pkg.name) {
  5300. pkgPath = pkg.location + '/' + pkg.main;
  5301. } else {
  5302. pkgPath = pkg.location;
  5303. }
  5304. syms.splice(0, i, pkgPath);
  5305. break;
  5306. }
  5307. }
  5308. //Join the path parts together, then figure out if baseUrl is needed.
  5309. url = syms.join('/');
  5310. url += (ext || (/\?/.test(url) ? '' : '.js'));
  5311. url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url;
  5312. }
  5313. return config.urlArgs ? url +
  5314. ((url.indexOf('?') === -1 ? '?' : '&') +
  5315. config.urlArgs) : url;
  5316. },
  5317. //Delegates to req.load. Broken out as a separate function to
  5318. //allow overriding in the optimizer.
  5319. load: function (id, url) {
  5320. req.load(context, id, url);
  5321. },
  5322. /**
  5323. * Executes a module callack function. Broken out as a separate function
  5324. * solely to allow the build system to sequence the files in the built
  5325. * layer in the right sequence.
  5326. *
  5327. * @private
  5328. */
  5329. execCb: function (name, callback, args, exports) {
  5330. return callback.apply(exports, args);
  5331. },
  5332. /**
  5333. * callback for script loads, used to check status of loading.
  5334. *
  5335. * @param {Event} evt the event from the browser for the script
  5336. * that was loaded.
  5337. */
  5338. onScriptLoad: function (evt) {
  5339. //Using currentTarget instead of target for Firefox 2.0's sake. Not
  5340. //all old browsers will be supported, but this one was easy enough
  5341. //to support and still makes sense.
  5342. if (evt.type === 'load' ||
  5343. (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
  5344. //Reset interactive script so a script node is not held onto for
  5345. //to long.
  5346. interactiveScript = null;
  5347. //Pull out the name of the module and the context.
  5348. var data = getScriptData(evt);
  5349. context.completeLoad(data.id);
  5350. }
  5351. },
  5352. /**
  5353. * Callback for script errors.
  5354. */
  5355. onScriptError: function (evt) {
  5356. var data = getScriptData(evt);
  5357. if (!hasPathFallback(data.id)) {
  5358. return onError(makeError('scripterror', 'Script error', evt, [data.id]));
  5359. }
  5360. }
  5361. };
  5362. context.require = context.makeRequire();
  5363. return context;
  5364. }
  5365. /**
  5366. * Main entry point.
  5367. *
  5368. * If the only argument to require is a string, then the module that
  5369. * is represented by that string is fetched for the appropriate context.
  5370. *
  5371. * If the first argument is an array, then it will be treated as an array
  5372. * of dependency string names to fetch. An optional function callback can
  5373. * be specified to execute when all of those dependencies are available.
  5374. *
  5375. * Make a local req variable to help Caja compliance (it assumes things
  5376. * on a require that are not standardized), and to give a short
  5377. * name for minification/local scope use.
  5378. */
  5379. req = requirejs = function (deps, callback, errback, optional) {
  5380. //Find the right context, use default
  5381. var context, config,
  5382. contextName = defContextName;
  5383. // Determine if have config object in the call.
  5384. if (!isArray(deps) && typeof deps !== 'string') {
  5385. // deps is a config object
  5386. config = deps;
  5387. if (isArray(callback)) {
  5388. // Adjust args if there are dependencies
  5389. deps = callback;
  5390. callback = errback;
  5391. errback = optional;
  5392. } else {
  5393. deps = [];
  5394. }
  5395. }
  5396. if (config && config.context) {
  5397. contextName = config.context;
  5398. }
  5399. context = getOwn(contexts, contextName);
  5400. if (!context) {
  5401. context = contexts[contextName] = req.s.newContext(contextName);
  5402. }
  5403. if (config) {
  5404. context.configure(config);
  5405. }
  5406. return context.require(deps, callback, errback);
  5407. };
  5408. /**
  5409. * Support require.config() to make it easier to cooperate with other
  5410. * AMD loaders on globally agreed names.
  5411. */
  5412. req.config = function (config) {
  5413. return req(config);
  5414. };
  5415. /**
  5416. * Execute something after the current tick
  5417. * of the event loop. Override for other envs
  5418. * that have a better solution than setTimeout.
  5419. * @param {Function} fn function to execute later.
  5420. */
  5421. req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
  5422. setTimeout(fn, 4);
  5423. } : function (fn) { fn(); };
  5424. /**
  5425. * Export require as a global, but only if it does not already exist.
  5426. */
  5427. if (!require) {
  5428. require = req;
  5429. }
  5430. req.version = version;
  5431. //Used to filter out dependencies that are already paths.
  5432. req.jsExtRegExp = /^\/|:|\?|\.js$/;
  5433. req.isBrowser = isBrowser;
  5434. s = req.s = {
  5435. contexts: contexts,
  5436. newContext: newContext
  5437. };
  5438. //Create default context.
  5439. req({});
  5440. //Exports some context-sensitive methods on global require.
  5441. each([
  5442. 'toUrl',
  5443. 'undef',
  5444. 'defined',
  5445. 'specified'
  5446. ], function (prop) {
  5447. //Reference from contexts instead of early binding to default context,
  5448. //so that during builds, the latest instance of the default context
  5449. //with its config gets used.
  5450. req[prop] = function () {
  5451. var ctx = contexts[defContextName];
  5452. return ctx.require[prop].apply(ctx, arguments);
  5453. };
  5454. });
  5455. if (isBrowser) {
  5456. head = s.head = document.getElementsByTagName('head')[0];
  5457. //If BASE tag is in play, using appendChild is a problem for IE6.
  5458. //When that browser dies, this can be removed. Details in this jQuery bug:
  5459. //http://dev.jquery.com/ticket/2709
  5460. baseElement = document.getElementsByTagName('base')[0];
  5461. if (baseElement) {
  5462. head = s.head = baseElement.parentNode;
  5463. }
  5464. }
  5465. /**
  5466. * Any errors that require explicitly generates will be passed to this
  5467. * function. Intercept/override it if you want custom error handling.
  5468. * @param {Error} err the error object.
  5469. */
  5470. req.onError = function (err) {
  5471. throw err;
  5472. };
  5473. /**
  5474. * Does the request to load a module for the browser case.
  5475. * Make this a separate function to allow other environments
  5476. * to override it.
  5477. *
  5478. * @param {Object} context the require context to find state.
  5479. * @param {String} moduleName the name of the module.
  5480. * @param {Object} url the URL to the module.
  5481. */
  5482. req.load = function (context, moduleName, url) {
  5483. var config = (context && context.config) || {},
  5484. node;
  5485. if (isBrowser) {
  5486. //In the browser so use a script tag
  5487. node = config.xhtml ?
  5488. document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
  5489. document.createElement('script');
  5490. node.type = config.scriptType || 'text/javascript';
  5491. node.charset = 'utf-8';
  5492. node.async = true;
  5493. node.setAttribute('data-requirecontext', context.contextName);
  5494. node.setAttribute('data-requiremodule', moduleName);
  5495. //Set up load listener. Test attachEvent first because IE9 has
  5496. //a subtle issue in its addEventListener and script onload firings
  5497. //that do not match the behavior of all other browsers with
  5498. //addEventListener support, which fire the onload event for a
  5499. //script right after the script execution. See:
  5500. //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
  5501. //UNFORTUNATELY Opera implements attachEvent but does not follow the script
  5502. //script execution mode.
  5503. if (node.attachEvent &&
  5504. //Check if node.attachEvent is artificially added by custom script or
  5505. //natively supported by browser
  5506. //read https://github.com/jrburke/requirejs/issues/187
  5507. //if we can NOT find [native code] then it must NOT natively supported.
  5508. //in IE8, node.attachEvent does not have toString()
  5509. //Note the test for "[native code" with no closing brace, see:
  5510. //https://github.com/jrburke/requirejs/issues/273
  5511. !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
  5512. !isOpera) {
  5513. //Probably IE. IE (at least 6-8) do not fire
  5514. //script onload right after executing the script, so
  5515. //we cannot tie the anonymous define call to a name.
  5516. //However, IE reports the script as being in 'interactive'
  5517. //readyState at the time of the define call.
  5518. useInteractive = true;
  5519. node.attachEvent('onreadystatechange', context.onScriptLoad);
  5520. //It would be great to add an error handler here to catch
  5521. //404s in IE9+. However, onreadystatechange will fire before
  5522. //the error handler, so that does not help. If addEvenListener
  5523. //is used, then IE will fire error before load, but we cannot
  5524. //use that pathway given the connect.microsoft.com issue
  5525. //mentioned above about not doing the 'script execute,
  5526. //then fire the script load event listener before execute
  5527. //next script' that other browsers do.
  5528. //Best hope: IE10 fixes the issues,
  5529. //and then destroys all installs of IE 6-9.
  5530. //node.attachEvent('onerror', context.onScriptError);
  5531. } else {
  5532. node.addEventListener('load', context.onScriptLoad, false);
  5533. node.addEventListener('error', context.onScriptError, false);
  5534. }
  5535. node.src = url;
  5536. //For some cache cases in IE 6-8, the script executes before the end
  5537. //of the appendChild execution, so to tie an anonymous define
  5538. //call to the module name (which is stored on the node), hold on
  5539. //to a reference to this node, but clear after the DOM insertion.
  5540. currentlyAddingScript = node;
  5541. if (baseElement) {
  5542. head.insertBefore(node, baseElement);
  5543. } else {
  5544. head.appendChild(node);
  5545. }
  5546. currentlyAddingScript = null;
  5547. return node;
  5548. } else if (isWebWorker) {
  5549. //In a web worker, use importScripts. This is not a very
  5550. //efficient use of importScripts, importScripts will block until
  5551. //its script is downloaded and evaluated. However, if web workers
  5552. //are in play, the expectation that a build has been done so that
  5553. //only one script needs to be loaded anyway. This may need to be
  5554. //reevaluated if other use cases become common.
  5555. importScripts(url);
  5556. //Account for anonymous modules
  5557. context.completeLoad(moduleName);
  5558. }
  5559. };
  5560. function getInteractiveScript() {
  5561. if (interactiveScript && interactiveScript.readyState === 'interactive') {
  5562. return interactiveScript;
  5563. }
  5564. eachReverse(scripts(), function (script) {
  5565. if (script.readyState === 'interactive') {
  5566. return (interactiveScript = script);
  5567. }
  5568. });
  5569. return interactiveScript;
  5570. }
  5571. //Look for a data-main script attribute, which could also adjust the baseUrl.
  5572. if (isBrowser) {
  5573. //Figure out baseUrl. Get it from the script tag with require.js in it.
  5574. eachReverse(scripts(), function (script) {
  5575. //Set the 'head' where we can append children by
  5576. //using the script's parent.
  5577. if (!head) {
  5578. head = script.parentNode;
  5579. }
  5580. //Look for a data-main attribute to set main script for the page
  5581. //to load. If it is there, the path to data main becomes the
  5582. //baseUrl, if it is not already set.
  5583. dataMain = script.getAttribute('data-main');
  5584. if (dataMain) {
  5585. //Set final baseUrl if there is not already an explicit one.
  5586. if (!cfg.baseUrl) {
  5587. //Pull off the directory of data-main for use as the
  5588. //baseUrl.
  5589. src = dataMain.split('/');
  5590. mainScript = src.pop();
  5591. subPath = src.length ? src.join('/') + '/' : './';
  5592. cfg.baseUrl = subPath;
  5593. dataMain = mainScript;
  5594. }
  5595. //Strip off any trailing .js since dataMain is now
  5596. //like a module name.
  5597. dataMain = dataMain.replace(jsSuffixRegExp, '');
  5598. //Put the data-main script in the files to load.
  5599. cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain];
  5600. return true;
  5601. }
  5602. });
  5603. }
  5604. /**
  5605. * The function that handles definitions of modules. Differs from
  5606. * require() in that a string for the module should be the first argument,
  5607. * and the function to execute after dependencies are loaded should
  5608. * return a value to define the module corresponding to the first argument's
  5609. * name.
  5610. */
  5611. define = function (name, deps, callback) {
  5612. var node, context;
  5613. //Allow for anonymous modules
  5614. if (typeof name !== 'string') {
  5615. //Adjust args appropriately
  5616. callback = deps;
  5617. deps = name;
  5618. name = null;
  5619. }
  5620. //This module may not have dependencies
  5621. if (!isArray(deps)) {
  5622. callback = deps;
  5623. deps = [];
  5624. }
  5625. //If no name, and callback is a function, then figure out if it a
  5626. //CommonJS thing with dependencies.
  5627. if (!deps.length && isFunction(callback)) {
  5628. //Remove comments from the callback string,
  5629. //look for require calls, and pull them into the dependencies,
  5630. //but only if there are function args.
  5631. if (callback.length) {
  5632. callback
  5633. .toString()
  5634. .replace(commentRegExp, '')
  5635. .replace(cjsRequireRegExp, function (match, dep) {
  5636. deps.push(dep);
  5637. });
  5638. //May be a CommonJS thing even without require calls, but still
  5639. //could use exports, and module. Avoid doing exports and module
  5640. //work though if it just needs require.
  5641. //REQUIRES the function to expect the CommonJS variables in the
  5642. //order listed below.
  5643. deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
  5644. }
  5645. }
  5646. //If in IE 6-8 and hit an anonymous define() call, do the interactive
  5647. //work.
  5648. if (useInteractive) {
  5649. node = currentlyAddingScript || getInteractiveScript();
  5650. if (node) {
  5651. if (!name) {
  5652. name = node.getAttribute('data-requiremodule');
  5653. }
  5654. context = contexts[node.getAttribute('data-requirecontext')];
  5655. }
  5656. }
  5657. //Always save off evaluating the def call until the script onload handler.
  5658. //This allows multiple modules to be in a file without prematurely
  5659. //tracing dependencies, and allows for anonymous module support,
  5660. //where the module name is not known until the script onload event
  5661. //occurs. If no context, use the global queue, and get it processed
  5662. //in the onscript load callback.
  5663. (context ? context.defQueue : globalDefQueue).push([name, deps, callback]);
  5664. };
  5665. define.amd = {
  5666. jQuery: true
  5667. };
  5668. /**
  5669. * Executes the text. Normally just uses eval, but can be modified
  5670. * to use a better, environment-specific call. Only used for transpiling
  5671. * loader plugins, not for plain JS modules.
  5672. * @param {String} text the text to execute/evaluate.
  5673. */
  5674. req.exec = function (text) {
  5675. /*jslint evil: true */
  5676. return eval(text);
  5677. };
  5678. //Set up with config info.
  5679. req(cfg);
  5680. }(this));
  5681. context.require=require; context.define=define; context.requirejs=requirejs; };
  5682. blanket.defaultReporter = function(coverage){
  5683. 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;}",
  5684. successRate = 60,
  5685. head = document.head,
  5686. fileNumber = 0,
  5687. body = document.body,
  5688. headerContent,
  5689. hasBranchTracking = Object.keys(coverage.files).some(function(elem){
  5690. return typeof coverage.files[elem].branchData !== 'undefined';
  5691. }),
  5692. 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>",
  5693. fileTemplate = "<div class='blanket {{statusclass}}'><div class='bl-cl bl-file'><span class='bl-nb'>{{fileNumber}}.</span><a href='javascript:blanket_toggleSource(\"file-{{fileNumber}}\")'>{{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>";
  5694. grandTotalTemplate = "<div class='blanket grand-total {{statusclass}}'><div class='bl-cl'>Totals</div><div class='bl-cl rs'>{{percentage}} %</div>"+( hasBranchTracking ? "<div class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</div>" : "" )+"<div class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</div><div style='clear:both;'></div></div>";
  5695. function blanket_toggleSource(id) {
  5696. var element = document.getElementById(id);
  5697. if(element.style.display === 'block') {
  5698. element.style.display = 'none';
  5699. } else {
  5700. element.style.display = 'block';
  5701. }
  5702. }
  5703. var script = document.createElement("script");
  5704. script.type = "text/javascript";
  5705. script.text = blanket_toggleSource.toString().replace('function ' + blanket_toggleSource.name, 'function blanket_toggleSource');
  5706. body.appendChild(script);
  5707. var percentage = function(number, total) {
  5708. return (Math.round(((number/total) * 100)*100)/100);
  5709. };
  5710. var appendTag = function (type, el, str) {
  5711. var dom = document.createElement(type);
  5712. dom.innerHTML = str;
  5713. el.appendChild(dom);
  5714. };
  5715. function escapeInvalidXmlChars(str) {
  5716. return str.replace(/\&/g, "&amp;")
  5717. .replace(/</g, "&lt;")
  5718. .replace(/\>/g, "&gt;")
  5719. .replace(/\"/g, "&quot;")
  5720. .replace(/\'/g, "&apos;");
  5721. }
  5722. function isBranchFollowed(data,bool){
  5723. var mode = bool ? 0 : 1;
  5724. if (typeof data === 'undefined' ||
  5725. typeof data === null ||
  5726. typeof data[mode] === 'undefined'){
  5727. return false;
  5728. }
  5729. return data[mode].length > 0;
  5730. }
  5731. var branchStack = [];
  5732. function branchReport(colsIndex,src,cols,offset,lineNum){
  5733. var newsrc="";
  5734. var postfix="";
  5735. if (branchStack.length > 0){
  5736. newsrc += "<span class='" + (isBranchFollowed(branchStack[0][1],branchStack[0][1].consequent === branchStack[0][0]) ? 'branchOkay' : 'branchWarning') + "'>";
  5737. if (branchStack[0][0].end.line === lineNum){
  5738. newsrc += escapeInvalidXmlChars(src.slice(0,branchStack[0][0].end.column)) + "</span>";
  5739. src = src.slice(branchStack[0][0].end.column);
  5740. branchStack.shift();
  5741. if (branchStack.length > 0){
  5742. newsrc += "<span class='" + (isBranchFollowed(branchStack[0][1],false) ? 'branchOkay' : 'branchWarning') + "'>";
  5743. if (branchStack[0][0].end.line === lineNum){
  5744. newsrc += escapeInvalidXmlChars(src.slice(0,branchStack[0][0].end.column)) + "</span>";
  5745. src = src.slice(branchStack[0][0].end.column);
  5746. branchStack.shift();
  5747. if (!cols){
  5748. return {src: newsrc + escapeInvalidXmlChars(src) ,cols:cols};
  5749. }
  5750. }
  5751. else if (!cols){
  5752. return {src: newsrc + escapeInvalidXmlChars(src) + "</span>",cols:cols};
  5753. }
  5754. else{
  5755. postfix = "</span>";
  5756. }
  5757. }else if (!cols){
  5758. return {src: newsrc + escapeInvalidXmlChars(src) ,cols:cols};
  5759. }
  5760. }else if(!cols){
  5761. return {src: newsrc + escapeInvalidXmlChars(src) + "</span>",cols:cols};
  5762. }else{
  5763. postfix = "</span>";
  5764. }
  5765. }
  5766. var thisline = cols[colsIndex];
  5767. //consequent
  5768. var cons = thisline.consequent;
  5769. if (cons.start.line > lineNum){
  5770. branchStack.unshift([thisline.alternate,thisline]);
  5771. branchStack.unshift([cons,thisline]);
  5772. src = escapeInvalidXmlChars(src);
  5773. }else{
  5774. var style = "<span class='" + (isBranchFollowed(thisline,true) ? 'branchOkay' : 'branchWarning') + "'>";
  5775. newsrc += escapeInvalidXmlChars(src.slice(0,cons.start.column-offset)) + style;
  5776. if (cols.length > colsIndex+1 &&
  5777. cols[colsIndex+1].consequent.start.line === lineNum &&
  5778. cols[colsIndex+1].consequent.start.column-offset < cols[colsIndex].consequent.end.column-offset)
  5779. {
  5780. var res = branchReport(colsIndex+1,src.slice(cons.start.column-offset,cons.end.column-offset),cols,cons.start.column-offset,lineNum);
  5781. newsrc += res.src;
  5782. cols = res.cols;
  5783. cols[colsIndex+1] = cols[colsIndex+2];
  5784. cols.length--;
  5785. }else{
  5786. newsrc += escapeInvalidXmlChars(src.slice(cons.start.column-offset,cons.end.column-offset));
  5787. }
  5788. newsrc += "</span>";
  5789. var alt = thisline.alternate;
  5790. if (alt.start.line > lineNum){
  5791. newsrc += escapeInvalidXmlChars(src.slice(cons.end.column-offset));
  5792. branchStack.unshift([alt,thisline]);
  5793. }else{
  5794. newsrc += escapeInvalidXmlChars(src.slice(cons.end.column-offset,alt.start.column-offset));
  5795. style = "<span class='" + (isBranchFollowed(thisline,false) ? 'branchOkay' : 'branchWarning') + "'>";
  5796. newsrc += style;
  5797. if (cols.length > colsIndex+1 &&
  5798. cols[colsIndex+1].consequent.start.line === lineNum &&
  5799. cols[colsIndex+1].consequent.start.column-offset < cols[colsIndex].alternate.end.column-offset)
  5800. {
  5801. var res2 = branchReport(colsIndex+1,src.slice(alt.start.column-offset,alt.end.column-offset),cols,alt.start.column-offset,lineNum);
  5802. newsrc += res2.src;
  5803. cols = res2.cols;
  5804. cols[colsIndex+1] = cols[colsIndex+2];
  5805. cols.length--;
  5806. }else{
  5807. newsrc += escapeInvalidXmlChars(src.slice(alt.start.column-offset,alt.end.column-offset));
  5808. }
  5809. newsrc += "</span>";
  5810. newsrc += escapeInvalidXmlChars(src.slice(alt.end.column-offset));
  5811. src = newsrc;
  5812. }
  5813. }
  5814. return {src:src+postfix, cols:cols};
  5815. }
  5816. var isUndefined = function(item){
  5817. return typeof item !== 'undefined';
  5818. };
  5819. var files = coverage.files;
  5820. var totals = {
  5821. totalSmts: 0,
  5822. numberOfFilesCovered: 0
  5823. };
  5824. for(var file in files)
  5825. {
  5826. fileNumber++;
  5827. var statsForFile = files[file],
  5828. totalSmts = 0,
  5829. numberOfFilesCovered = 0,
  5830. code = [],
  5831. i;
  5832. var end = [];
  5833. for(i = 0; i < statsForFile.source.length; i +=1){
  5834. var src = statsForFile.source[i];
  5835. if (branchStack.length > 0 ||
  5836. typeof statsForFile.branchData !== 'undefined')
  5837. {
  5838. if (typeof statsForFile.branchData[i+1] !== 'undefined')
  5839. {
  5840. var cols = statsForFile.branchData[i+1].filter(isUndefined);
  5841. var colsIndex=0;
  5842. src = branchReport(colsIndex,src,cols,0,i+1).src;
  5843. }else if (branchStack.length){
  5844. src = branchReport(0,src,null,0,i+1).src;
  5845. }else{
  5846. src = escapeInvalidXmlChars(src);
  5847. }
  5848. }else{
  5849. src = escapeInvalidXmlChars(src);
  5850. }
  5851. var lineClass="";
  5852. if(statsForFile[i+1]) {
  5853. numberOfFilesCovered += 1;
  5854. totalSmts += 1;
  5855. lineClass = 'hit';
  5856. }else{
  5857. if(statsForFile[i+1] === 0){
  5858. totalSmts++;
  5859. lineClass = 'miss';
  5860. }
  5861. }
  5862. code[i + 1] = "<div class='"+lineClass+"'><span class=''>"+(i + 1)+"</span>"+src+"</div>";
  5863. totals.totalSmts += totalSmts;
  5864. totals.numberOfFilesCovered += numberOfFilesCovered;
  5865. }
  5866. var totalBranches=0;
  5867. var passedBranches=0;
  5868. if (typeof statsForFile.branchData !== 'undefined'){
  5869. for(var j=0;j<statsForFile.branchData.length;j++){
  5870. if (typeof statsForFile.branchData[j] !== 'undefined'){
  5871. for(var k=0;k<statsForFile.branchData[j].length;k++){
  5872. if (typeof statsForFile.branchData[j][k] !== 'undefined'){
  5873. totalBranches++;
  5874. if (typeof statsForFile.branchData[j][k][0] !== 'undefined' &&
  5875. statsForFile.branchData[j][k][0].length > 0 &&
  5876. typeof statsForFile.branchData[j][k][1] !== 'undefined' &&
  5877. statsForFile.branchData[j][k][1].length > 0){
  5878. passedBranches++;
  5879. }
  5880. }
  5881. }
  5882. }
  5883. }
  5884. }
  5885. var result = percentage(numberOfFilesCovered, totalSmts);
  5886. var output = fileTemplate.replace("{{file}}", file)
  5887. .replace("{{percentage}}",result)
  5888. .replace("{{numberCovered}}", numberOfFilesCovered)
  5889. .replace(/\{\{fileNumber\}\}/g, fileNumber)
  5890. .replace("{{totalSmts}}", totalSmts)
  5891. .replace("{{totalBranches}}", totalBranches)
  5892. .replace("{{passedBranches}}", passedBranches)
  5893. .replace("{{source}}", code.join(" "));
  5894. if(result < successRate)
  5895. {
  5896. output = output.replace("{{statusclass}}", "bl-error");
  5897. } else {
  5898. output = output.replace("{{statusclass}}", "bl-success");
  5899. }
  5900. bodyContent += output;
  5901. }
  5902. var totalPercent = percentage(totals.numberOfFilesCovered, totals.totalSmts);
  5903. var statusClass = totalPercent < successRate ? "bl-error" : "bl-success";
  5904. var totalsOutput = grandTotalTemplate.replace("{{percentage}}", totalPercent)
  5905. .replace("{{numberCovered}}", totals.numberOfFilesCovered)
  5906. .replace("{{totalSmts}}", totals.totalSmts)
  5907. .replace("{{statusclass}}", statusClass);
  5908. bodyContent += totalsOutput;
  5909. bodyContent += "</div>"; //closing main
  5910. appendTag('style', head, cssSytle);
  5911. //appendStyle(body, headerContent);
  5912. if (document.getElementById("blanket-main")){
  5913. document.getElementById("blanket-main").innerHTML=
  5914. bodyContent.slice(23,-6);
  5915. }else{
  5916. appendTag('div', body, bodyContent);
  5917. }
  5918. //appendHtml(body, '</div>');
  5919. };
  5920. (function(){
  5921. var newOptions={};
  5922. //http://stackoverflow.com/a/2954896
  5923. var toArray =Array.prototype.slice;
  5924. var scripts = toArray.call(document.scripts);
  5925. toArray.call(scripts[scripts.length - 1].attributes)
  5926. .forEach(function(es){
  5927. if(es.nodeName === "data-cover-only"){
  5928. newOptions.filter = es.nodeValue;
  5929. }
  5930. if(es.nodeName === "data-cover-never"){
  5931. newOptions.antifilter = es.nodeValue;
  5932. }
  5933. if(es.nodeName === "data-cover-reporter"){
  5934. newOptions.reporter = es.nodeValue;
  5935. }
  5936. if (es.nodeName === "data-cover-adapter"){
  5937. newOptions.adapter = es.nodeValue;
  5938. }
  5939. if (es.nodeName === "data-cover-loader"){
  5940. newOptions.loader = es.nodeValue;
  5941. }
  5942. if (es.nodeName === "data-cover-timeout"){
  5943. newOptions.timeout = es.nodeValue;
  5944. }
  5945. if (es.nodeName === "data-cover-reporter-options"){
  5946. try{
  5947. newOptions.reporter_options = JSON.parse(es.nodeValue);
  5948. }catch(e){
  5949. if (blanket.options("debug")){
  5950. throw new Error("Invalid reporter options. Must be a valid stringified JSON object.");
  5951. }
  5952. }
  5953. }
  5954. if (es.nodeName === "data-cover-testReadyCallback"){
  5955. newOptions.testReadyCallback = es.nodeValue;
  5956. }
  5957. if (es.nodeName === "data-cover-customVariable"){
  5958. newOptions.customVariable = es.nodeValue;
  5959. }
  5960. if (es.nodeName === "data-cover-flags"){
  5961. var flags = " "+es.nodeValue+" ";
  5962. if (flags.indexOf(" unordered ") > -1){
  5963. newOptions.order = false;
  5964. }
  5965. if (flags.indexOf(" ignoreError ") > -1){
  5966. newOptions.ignoreScriptError = true;
  5967. }
  5968. if (flags.indexOf(" autoStart ") > -1){
  5969. newOptions.autoStart = true;
  5970. }
  5971. if (flags.indexOf(" ignoreCors ") > -1){
  5972. newOptions.ignoreCors = true;
  5973. }
  5974. if (flags.indexOf(" branchTracking ") > -1){
  5975. newOptions.branchTracking = true;
  5976. }
  5977. if (flags.indexOf(" sourceURL ") > -1){
  5978. newOptions.sourceURL = true;
  5979. }
  5980. if (flags.indexOf(" debug ") > -1){
  5981. newOptions.debug = true;
  5982. }
  5983. if (flags.indexOf(" engineOnly ") > -1){
  5984. newOptions.engineOnly = true;
  5985. }
  5986. if (flags.indexOf(" commonJS ") > -1){
  5987. newOptions.commonJS = true;
  5988. }
  5989. if (flags.indexOf(" instrumentCache ") > -1){
  5990. newOptions.instrumentCache = true;
  5991. }
  5992. }
  5993. });
  5994. blanket.options(newOptions);
  5995. if (typeof requirejs !== 'undefined'){
  5996. blanket.options("existingRequireJS",true);
  5997. }
  5998. /* setup requirejs loader, if needed */
  5999. if (!blanket.options("existingRequireJS") ){
  6000. if (typeof window["define"] !== "undefined"){
  6001. window["__blanket_old_define"]=window["define"];
  6002. window["define"]=void 0;
  6003. }
  6004. if (blanket.options("commonJS")){
  6005. blanket._commonjs = {};
  6006. blanket.setupRequireJS(blanket._commonjs);
  6007. }else{
  6008. blanket.setupRequireJS(window);
  6009. }
  6010. if (typeof window["__blanket_old_define"] !== "undefined"){
  6011. window["define"] = window["__blanket_old_define"];
  6012. }
  6013. }
  6014. })();
  6015. (function(_blanket){
  6016. _blanket.extend({
  6017. utils: {
  6018. normalizeBackslashes: function(str) {
  6019. return str.replace(/\\/g, '/');
  6020. },
  6021. matchPatternAttribute: function(filename,pattern){
  6022. if (typeof pattern === 'string'){
  6023. if (pattern.indexOf("[") === 0){
  6024. //treat as array
  6025. var pattenArr = pattern.slice(1,pattern.length-1).split(",");
  6026. return pattenArr.some(function(elem){
  6027. return _blanket.utils.matchPatternAttribute(filename,_blanket.utils.normalizeBackslashes(elem.slice(1,-1)));
  6028. //return filename.indexOf(_blanket.utils.normalizeBackslashes(elem.slice(1,-1))) > -1;
  6029. });
  6030. }else if ( pattern.indexOf("//") === 0){
  6031. var ex = pattern.slice(2,pattern.lastIndexOf('/'));
  6032. var mods = pattern.slice(pattern.lastIndexOf('/')+1);
  6033. var regex = new RegExp(ex,mods);
  6034. return regex.test(filename);
  6035. }else if (pattern.indexOf("#") === 0){
  6036. return window[pattern.slice(1)].call(window,filename);
  6037. }else{
  6038. return filename.indexOf(_blanket.utils.normalizeBackslashes(pattern)) > -1;
  6039. }
  6040. }else if ( pattern instanceof Array ){
  6041. return pattern.some(function(elem){
  6042. return _blanket.utils.matchPatternAttribute(filename,elem);
  6043. });
  6044. }else if (pattern instanceof RegExp){
  6045. return pattern.test(filename);
  6046. }else if (typeof pattern === "function"){
  6047. return pattern.call(window,filename);
  6048. }
  6049. },
  6050. blanketEval: function(data){
  6051. return ( window.execScript || function( data ) {
  6052. //borrowed from jquery
  6053. window[ "eval" ].call( window, data );
  6054. } )( data );
  6055. },
  6056. collectPageScripts: function(){
  6057. console.log("cps1:"+new Date().getTime());
  6058. var toArray = Array.prototype.slice;
  6059. var scripts = toArray.call(document.scripts);
  6060. var selectedScripts=[],scriptNames=[];
  6061. var filter = _blanket.options("filter");
  6062. if(filter != null){
  6063. //global filter in place, data-cover-only
  6064. var antimatch = _blanket.options("antifilter");
  6065. selectedScripts = toArray.call(document.scripts)
  6066. .filter(function(s){
  6067. return toArray.call(s.attributes).filter(function(sn){
  6068. return sn.nodeName === "src" && _blanket.utils.matchPatternAttribute(sn.nodeValue,filter) &&
  6069. (typeof antimatch === "undefined" || !_blanket.utils.matchPatternAttribute(sn.nodeValue,antimatch));
  6070. }).length === 1;
  6071. });
  6072. }else{
  6073. selectedScripts = toArray.call(document.querySelectorAll("script[data-cover]"));
  6074. }
  6075. scriptNames = selectedScripts.map(function(s){
  6076. return _blanket.utils.qualifyURL(
  6077. toArray.call(s.attributes).filter(
  6078. function(sn){
  6079. return sn.nodeName === "src";
  6080. })[0].nodeValue).replace(".js","");
  6081. });
  6082. if (!filter){
  6083. _blanket.options("filter","['"+scriptNames.join("','")+"']");
  6084. }
  6085. return scriptNames;
  6086. }
  6087. }
  6088. });
  6089. (function(){
  6090. var require = blanket.options("commonJS") ? blanket._commonjs.require : window.require;
  6091. var requirejs = blanket.options("commonJS") ? blanket._commonjs.requirejs : window.requirejs;
  6092. if (!_blanket.options("engineOnly")){
  6093. _blanket.utils.oldloader = requirejs.load;
  6094. console.log("cps2:"+new Date().getTime());
  6095. requirejs.load = function (context, moduleName, url) {
  6096. _blanket.requiringFile(url);
  6097. requirejs.cget(url, function (content) {
  6098. var match = _blanket.options("filter");
  6099. //we check the never matches first
  6100. var antimatch = _blanket.options("antifilter");
  6101. if (typeof antimatch !== "undefined" &&
  6102. _blanket.utils.matchPatternAttribute(url.replace(".js",""),antimatch)
  6103. ){
  6104. _blanket.utils.oldloader(context, moduleName, url);
  6105. if (_blanket.options("debug")) {console.log("BLANKET-File will never be instrumented:"+url);}
  6106. _blanket.requiringFile(url,true);
  6107. }else if (_blanket.utils.matchPatternAttribute(url.replace(".js",""),match)){
  6108. if (_blanket.options("debug")) {console.log("BLANKET-Attempting instrument of:"+url);}
  6109. _blanket.instrument({
  6110. inputFile: content,
  6111. inputFileName: url
  6112. },function(instrumented){
  6113. try{
  6114. _blanket.utils.blanketEval(instrumented);
  6115. context.completeLoad(moduleName);
  6116. _blanket.requiringFile(url,true);
  6117. }
  6118. catch(err){
  6119. if (_blanket.options("ignoreScriptError")){
  6120. //we can continue like normal if
  6121. //we're ignoring script errors,
  6122. //but otherwise we don't want
  6123. //to completeLoad or the error might be
  6124. //missed.
  6125. if (_blanket.options("debug")) { console.log("BLANKET-There was an error loading the file:"+url); }
  6126. context.completeLoad(moduleName);
  6127. _blanket.requiringFile(url,true);
  6128. }else{
  6129. throw new Error("Error parsing instrumented code: "+err);
  6130. }
  6131. }
  6132. });
  6133. }else{
  6134. if (_blanket.options("debug")) { console.log("BLANKET-Loading (without instrumenting) the file:"+url);}
  6135. _blanket.utils.oldloader(context, moduleName, url);
  6136. _blanket.requiringFile(url,true);
  6137. }
  6138. }, function (err) {
  6139. _blanket.requiringFile();
  6140. throw err;
  6141. });
  6142. };
  6143. requirejs.createXhr = function () {
  6144. //Would love to dump the ActiveX crap in here. Need IE 6 to die first.
  6145. var xhr, i, progId;
  6146. if (typeof XMLHttpRequest !== "undefined") {
  6147. return new XMLHttpRequest();
  6148. } else if (typeof ActiveXObject !== "undefined") {
  6149. for (i = 0; i < 3; i += 1) {
  6150. progId = progIds[i];
  6151. try {
  6152. xhr = new ActiveXObject(progId);
  6153. } catch (e) {}
  6154. if (xhr) {
  6155. progIds = [progId]; // so faster next time
  6156. break;
  6157. }
  6158. }
  6159. }
  6160. return xhr;
  6161. };
  6162. requirejs.cget = function (url, callback, errback, onXhr) {
  6163. var foundInSession = false;
  6164. if (_blanket.blanketSession){
  6165. var files = Object.keys(_blanket.blanketSession);
  6166. for (var i=0; i<files.length;i++ ){
  6167. var key = files[i];
  6168. if (url.indexOf(key) > -1){
  6169. callback(_blanket.blanketSession[key]);
  6170. foundInSession=true;
  6171. return;
  6172. }
  6173. }
  6174. }
  6175. if (!foundInSession){
  6176. var xhr = requirejs.createXhr();
  6177. xhr.open('GET', url, true);
  6178. //Allow overrides specified in config
  6179. if (onXhr) {
  6180. onXhr(xhr, url);
  6181. }
  6182. xhr.onreadystatechange = function (evt) {
  6183. var status, err;
  6184. //Do not explicitly handle errors, those should be
  6185. //visible via console output in the browser.
  6186. if (xhr.readyState === 4) {
  6187. status = xhr.status;
  6188. if ((status > 399 && status < 600) /*||
  6189. (status === 0 &&
  6190. navigator.userAgent.toLowerCase().indexOf('firefox') > -1)
  6191. */ ) {
  6192. //An http 4xx or 5xx error. Signal an error.
  6193. err = new Error(url + ' HTTP status: ' + status);
  6194. err.xhr = xhr;
  6195. errback(err);
  6196. } else {
  6197. callback(xhr.responseText);
  6198. }
  6199. }
  6200. };
  6201. try{
  6202. xhr.send(null);
  6203. }catch(e){
  6204. if (e.code && (e.code === 101 || e.code === 1012) && _blanket.options("ignoreCors") === false){
  6205. //running locally and getting error from browser
  6206. _blanket.showManualLoader();
  6207. } else {
  6208. throw e;
  6209. }
  6210. }
  6211. }
  6212. };
  6213. }
  6214. })();
  6215. })(blanket);
  6216. (function() {
  6217. if (! jasmine) {
  6218. throw new Exception("jasmine library does not exist in global namespace!");
  6219. }
  6220. function elapsed(startTime, endTime) {
  6221. return (endTime - startTime)/1000;
  6222. }
  6223. function ISODateString(d) {
  6224. function pad(n) { return n < 10 ? '0'+n : n; }
  6225. return d.getFullYear() + '-' +
  6226. pad(d.getMonth()+1) + '-' +
  6227. pad(d.getDate()) + 'T' +
  6228. pad(d.getHours()) + ':' +
  6229. pad(d.getMinutes()) + ':' +
  6230. pad(d.getSeconds());
  6231. }
  6232. function trim(str) {
  6233. return str.replace(/^\s+/, "" ).replace(/\s+$/, "" );
  6234. }
  6235. function escapeInvalidXmlChars(str) {
  6236. return str.replace(/\&/g, "&amp;")
  6237. .replace(/</g, "&lt;")
  6238. .replace(/\>/g, "&gt;")
  6239. .replace(/\"/g, "&quot;")
  6240. .replace(/\'/g, "&apos;");
  6241. }
  6242. /**
  6243. * based on https://raw.github.com/larrymyers/jasmine-reporters/master/src/jasmine.junit_reporter.js
  6244. */
  6245. var BlanketReporter = function(savePath, consolidate, useDotNotation) {
  6246. blanket.setupCoverage();
  6247. };
  6248. BlanketReporter.finished_at = null; // will be updated after all files have been written
  6249. BlanketReporter.prototype = {
  6250. reportSpecStarting: function(spec) {
  6251. blanket.onTestStart();
  6252. },
  6253. reportSpecResults: function(suite) {
  6254. var results = suite.results();
  6255. blanket.onTestDone(results.totalCount,results.passed());
  6256. },
  6257. reportRunnerResults: function(runner) {
  6258. blanket.onTestsDone();
  6259. },
  6260. log: function(str) {
  6261. var console = jasmine.getGlobal().console;
  6262. if (console && console.log) {
  6263. console.log(str);
  6264. }
  6265. }
  6266. };
  6267. // export public
  6268. jasmine.BlanketReporter = BlanketReporter;
  6269. //override existing jasmine execute
  6270. jasmine.getEnv().execute = function(){ console.log("waiting for blanket..."); };
  6271. //check to make sure requirejs is completed before we start the test runner
  6272. var allLoaded = function() {
  6273. return window.jasmine.getEnv().currentRunner().specs().length > 0 && blanket.requireFilesLoaded();
  6274. };
  6275. blanket.beforeStartTestRunner({
  6276. checkRequirejs:true,
  6277. condition: allLoaded,
  6278. callback:function(){
  6279. jasmine.getEnv().addReporter(new jasmine.BlanketReporter());
  6280. window.jasmine.getEnv().currentRunner().execute();
  6281. jasmine.getEnv().execute = function () {
  6282. jasmine.getEnv().currentRunner().execute;
  6283. };
  6284. }
  6285. });
  6286. })();